mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[8.0][RAC] 117686 replace alert workflow status in alerts view (#118723)
* Add AlertStatus types * Add alert status filter component * Remove Filter in action from the t grid table * Update group buttons to applied Alert status filter instead of Workflow status * Keep the Alert status button in sync when typing and first page load * Fix data test object name and translation keys label * Add possibility to hide the bulk actions * Update how hide the bulk actions * Fix showCheckboxes hardcoded "true". Instead use the leadingControlColumns props * Hide the leading checkboxes in the T Grid with the bulk actions * Update showCheckboxes to false * Fix test as the leading checkboxes are hidden * Update tests * Get back disabledCellActions as it's required by T Grid * Update tests to skip test related to Workflow action buttons * Skip workflow tests * Revert fix showCheckboxes * Remove unused imports * Revert the o11y tests as the checkBoxes fix is reverted * Reactive the tests effected by checkBoxes * Skip alert workflow status * [Code review] use predefined types * Remove unused prop * Use the alert-data index name in the RegEx * Detect * in KQL as "show al"l alert filter Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
e570b8783d
commit
ee3cb46a68
7 changed files with 200 additions and 89 deletions
|
@ -7,6 +7,10 @@
|
||||||
import * as t from 'io-ts';
|
import * as t from 'io-ts';
|
||||||
|
|
||||||
export type Maybe<T> = T | null | undefined;
|
export type Maybe<T> = T | null | undefined;
|
||||||
|
import {
|
||||||
|
ALERT_STATUS_ACTIVE,
|
||||||
|
ALERT_STATUS_RECOVERED,
|
||||||
|
} from '@kbn/rule-data-utils/alerts_as_data_status';
|
||||||
|
|
||||||
export const alertWorkflowStatusRt = t.keyof({
|
export const alertWorkflowStatusRt = t.keyof({
|
||||||
open: null,
|
open: null,
|
||||||
|
@ -25,3 +29,12 @@ export interface ApmIndicesConfig {
|
||||||
apmAgentConfigurationIndex: string;
|
apmAgentConfigurationIndex: string;
|
||||||
apmCustomLinkIndex: string;
|
apmCustomLinkIndex: string;
|
||||||
}
|
}
|
||||||
|
export type AlertStatusFilterButton =
|
||||||
|
| typeof ALERT_STATUS_ACTIVE
|
||||||
|
| typeof ALERT_STATUS_RECOVERED
|
||||||
|
| '';
|
||||||
|
export interface AlertStatusFilter {
|
||||||
|
status: AlertStatusFilterButton;
|
||||||
|
query: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
|
* 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { EuiButtonGroup, EuiButtonGroupOptionProps } from '@elastic/eui';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
ALERT_STATUS_ACTIVE,
|
||||||
|
ALERT_STATUS_RECOVERED,
|
||||||
|
} from '@kbn/rule-data-utils/alerts_as_data_status';
|
||||||
|
import { ALERT_STATUS } from '@kbn/rule-data-utils/technical_field_names';
|
||||||
|
import { AlertStatusFilterButton } from '../../../common/typings';
|
||||||
|
import { AlertStatusFilter } from '../../../common/typings';
|
||||||
|
|
||||||
|
export interface AlertStatusFilterProps {
|
||||||
|
status: AlertStatusFilterButton;
|
||||||
|
onChange: (id: string, value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const allAlerts: AlertStatusFilter = {
|
||||||
|
status: '',
|
||||||
|
query: '',
|
||||||
|
label: i18n.translate('xpack.observability.alerts.alertStatusFilter.showAll', {
|
||||||
|
defaultMessage: 'Show all',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const activeAlerts: AlertStatusFilter = {
|
||||||
|
status: ALERT_STATUS_ACTIVE,
|
||||||
|
query: `${ALERT_STATUS}: "${ALERT_STATUS_ACTIVE}"`,
|
||||||
|
label: i18n.translate('xpack.observability.alerts.alertStatusFilter.active', {
|
||||||
|
defaultMessage: 'Active',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const recoveredAlerts: AlertStatusFilter = {
|
||||||
|
status: ALERT_STATUS_RECOVERED,
|
||||||
|
query: `${ALERT_STATUS}: "${ALERT_STATUS_RECOVERED}"`,
|
||||||
|
label: i18n.translate('xpack.observability.alerts.alertStatusFilter.recovered', {
|
||||||
|
defaultMessage: 'Recovered',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const options: EuiButtonGroupOptionProps[] = [
|
||||||
|
{
|
||||||
|
id: allAlerts.status,
|
||||||
|
label: allAlerts.label,
|
||||||
|
value: allAlerts.query,
|
||||||
|
'data-test-subj': 'alert-status-filter-show-all-button',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: activeAlerts.status,
|
||||||
|
label: activeAlerts.label,
|
||||||
|
value: activeAlerts.query,
|
||||||
|
'data-test-subj': 'alert-status-filter-active-button',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: recoveredAlerts.status,
|
||||||
|
label: recoveredAlerts.label,
|
||||||
|
value: recoveredAlerts.query,
|
||||||
|
'data-test-subj': 'alert-status-filter-recovered-button',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function AlertsStatusFilter({ status, onChange }: AlertStatusFilterProps) {
|
||||||
|
return (
|
||||||
|
<EuiButtonGroup
|
||||||
|
legend="Filter by"
|
||||||
|
color="primary"
|
||||||
|
options={options}
|
||||||
|
idSelected={status}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -13,8 +13,6 @@
|
||||||
import {
|
import {
|
||||||
ALERT_DURATION,
|
ALERT_DURATION,
|
||||||
ALERT_REASON,
|
ALERT_REASON,
|
||||||
ALERT_RULE_CONSUMER,
|
|
||||||
ALERT_RULE_PRODUCER,
|
|
||||||
ALERT_STATUS,
|
ALERT_STATUS,
|
||||||
ALERT_WORKFLOW_STATUS,
|
ALERT_WORKFLOW_STATUS,
|
||||||
TIMESTAMP,
|
TIMESTAMP,
|
||||||
|
@ -34,11 +32,8 @@ import {
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import React, { Suspense, useMemo, useState, useCallback, useEffect } from 'react';
|
import React, { Suspense, useMemo, useState, useCallback, useEffect } from 'react';
|
||||||
import usePrevious from 'react-use/lib/usePrevious';
|
import usePrevious from 'react-use/lib/usePrevious';
|
||||||
import { get, pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
import {
|
import { getAlertsPermissions } from '../../hooks/use_alert_permission';
|
||||||
getAlertsPermissions,
|
|
||||||
useGetUserAlertsPermissions,
|
|
||||||
} from '../../hooks/use_alert_permission';
|
|
||||||
import type {
|
import type {
|
||||||
TimelinesUIStart,
|
TimelinesUIStart,
|
||||||
TGridType,
|
TGridType,
|
||||||
|
@ -46,13 +41,14 @@ import type {
|
||||||
TGridModel,
|
TGridModel,
|
||||||
SortDirection,
|
SortDirection,
|
||||||
} from '../../../../timelines/public';
|
} from '../../../../timelines/public';
|
||||||
import { useStatusBulkActionItems } from '../../../../timelines/public';
|
|
||||||
import type { TopAlert } from './';
|
import type { TopAlert } from './';
|
||||||
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
|
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
|
||||||
import type {
|
import type {
|
||||||
ActionProps,
|
ActionProps,
|
||||||
AlertWorkflowStatus,
|
AlertWorkflowStatus,
|
||||||
ColumnHeaderOptions,
|
ColumnHeaderOptions,
|
||||||
|
ControlColumnProps,
|
||||||
RowRenderer,
|
RowRenderer,
|
||||||
} from '../../../../timelines/common';
|
} from '../../../../timelines/common';
|
||||||
|
|
||||||
|
@ -60,7 +56,6 @@ import { getRenderCellValue } from './render_cell_value';
|
||||||
import { observabilityAppId, observabilityFeatureId } from '../../../common';
|
import { observabilityAppId, observabilityFeatureId } from '../../../common';
|
||||||
import { useGetUserCasesPermissions } from '../../hooks/use_get_user_cases_permissions';
|
import { useGetUserCasesPermissions } from '../../hooks/use_get_user_cases_permissions';
|
||||||
import { usePluginContext } from '../../hooks/use_plugin_context';
|
import { usePluginContext } from '../../hooks/use_plugin_context';
|
||||||
import { getDefaultCellActions } from './default_cell_actions';
|
|
||||||
import { LazyAlertsFlyout } from '../..';
|
import { LazyAlertsFlyout } from '../..';
|
||||||
import { parseAlert } from './parse_alert';
|
import { parseAlert } from './parse_alert';
|
||||||
import { CoreStart } from '../../../../../../src/core/public';
|
import { CoreStart } from '../../../../../../src/core/public';
|
||||||
|
@ -75,7 +70,6 @@ interface AlertsTableTGridProps {
|
||||||
kuery: string;
|
kuery: string;
|
||||||
workflowStatus: AlertWorkflowStatus;
|
workflowStatus: AlertWorkflowStatus;
|
||||||
setRefetch: (ref: () => void) => void;
|
setRefetch: (ref: () => void) => void;
|
||||||
addToQuery: (value: string) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ObservabilityActionsProps extends ActionProps {
|
interface ObservabilityActionsProps extends ActionProps {
|
||||||
|
@ -154,21 +148,21 @@ function ObservabilityActions({
|
||||||
const [openActionsPopoverId, setActionsPopover] = useState(null);
|
const [openActionsPopoverId, setActionsPopover] = useState(null);
|
||||||
const {
|
const {
|
||||||
timelines,
|
timelines,
|
||||||
application: { capabilities },
|
application: {},
|
||||||
} = useKibana<CoreStart & { timelines: TimelinesUIStart }>().services;
|
} = useKibana<CoreStart & { timelines: TimelinesUIStart }>().services;
|
||||||
|
|
||||||
const parseObservabilityAlert = useMemo(
|
const parseObservabilityAlert = useMemo(
|
||||||
() => parseAlert(observabilityRuleTypeRegistry),
|
() => parseAlert(observabilityRuleTypeRegistry),
|
||||||
[observabilityRuleTypeRegistry]
|
[observabilityRuleTypeRegistry]
|
||||||
);
|
);
|
||||||
const alertDataConsumer = useMemo<string>(
|
// const alertDataConsumer = useMemo<string>(
|
||||||
() => get(dataFieldEs, ALERT_RULE_CONSUMER, [''])[0],
|
// () => get(dataFieldEs, ALERT_RULE_CONSUMER, [''])[0],
|
||||||
[dataFieldEs]
|
// [dataFieldEs]
|
||||||
);
|
// );
|
||||||
const alertDataProducer = useMemo<string>(
|
// const alertDataProducer = useMemo<string>(
|
||||||
() => get(dataFieldEs, ALERT_RULE_PRODUCER, [''])[0],
|
// () => get(dataFieldEs, ALERT_RULE_PRODUCER, [''])[0],
|
||||||
[dataFieldEs]
|
// [dataFieldEs]
|
||||||
);
|
// );
|
||||||
|
|
||||||
const alert = parseObservabilityAlert(dataFieldEs);
|
const alert = parseObservabilityAlert(dataFieldEs);
|
||||||
const { prepend } = core.http.basePath;
|
const { prepend } = core.http.basePath;
|
||||||
|
@ -194,27 +188,29 @@ function ObservabilityActions({
|
||||||
};
|
};
|
||||||
}, [data, eventId, ecsData]);
|
}, [data, eventId, ecsData]);
|
||||||
|
|
||||||
const onAlertStatusUpdated = useCallback(() => {
|
// Hide the WorkFlow filter, but keep its code as required in https://github.com/elastic/kibana/issues/117686
|
||||||
setActionsPopover(null);
|
|
||||||
if (refetch) {
|
|
||||||
refetch();
|
|
||||||
}
|
|
||||||
}, [setActionsPopover, refetch]);
|
|
||||||
|
|
||||||
const alertPermissions = useGetUserAlertsPermissions(
|
// const onAlertStatusUpdated = useCallback(() => {
|
||||||
capabilities,
|
// setActionsPopover(null);
|
||||||
alertDataConsumer === 'alerts' ? alertDataProducer : alertDataConsumer
|
// if (refetch) {
|
||||||
);
|
// refetch();
|
||||||
|
// }
|
||||||
|
// }, [setActionsPopover, refetch]);
|
||||||
|
|
||||||
const statusActionItems = useStatusBulkActionItems({
|
// const alertPermissions = useGetUserAlertsPermissions(
|
||||||
eventIds: [eventId],
|
// capabilities,
|
||||||
currentStatus,
|
// alertDataConsumer === 'alerts' ? alertDataProducer : alertDataConsumer
|
||||||
indexName: ecsData._index ?? '',
|
// );
|
||||||
setEventsLoading,
|
|
||||||
setEventsDeleted,
|
// const statusActionItems = useStatusBulkActionItems({
|
||||||
onUpdateSuccess: onAlertStatusUpdated,
|
// eventIds: [eventId],
|
||||||
onUpdateFailure: onAlertStatusUpdated,
|
// currentStatus,
|
||||||
});
|
// indexName: ecsData._index ?? '',
|
||||||
|
// setEventsLoading,
|
||||||
|
// setEventsDeleted,
|
||||||
|
// onUpdateSuccess: onAlertStatusUpdated,
|
||||||
|
// onUpdateFailure: onAlertStatusUpdated,
|
||||||
|
// });
|
||||||
|
|
||||||
const ruleId = alert.fields['kibana.alert.rule.uuid'] ?? null;
|
const ruleId = alert.fields['kibana.alert.rule.uuid'] ?? null;
|
||||||
const linkToRule = ruleId ? prepend(paths.management.ruleDetails(ruleId)) : null;
|
const linkToRule = ruleId ? prepend(paths.management.ruleDetails(ruleId)) : null;
|
||||||
|
@ -239,7 +235,8 @@ function ObservabilityActions({
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(alertPermissions.crud ? statusActionItems : []),
|
// Hide the WorkFlow filter, but keep its code as required in https://github.com/elastic/kibana/issues/117686
|
||||||
|
// ...(alertPermissions.crud ? statusActionItems : []),
|
||||||
...(!!linkToRule
|
...(!!linkToRule
|
||||||
? [
|
? [
|
||||||
<EuiContextMenuItem
|
<EuiContextMenuItem
|
||||||
|
@ -252,15 +249,7 @@ function ObservabilityActions({
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
];
|
];
|
||||||
}, [
|
}, [afterCaseSelection, casePermissions, timelines, event, linkToRule]);
|
||||||
afterCaseSelection,
|
|
||||||
casePermissions,
|
|
||||||
timelines,
|
|
||||||
event,
|
|
||||||
statusActionItems,
|
|
||||||
alertPermissions,
|
|
||||||
linkToRule,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const actionsToolTip =
|
const actionsToolTip =
|
||||||
actionsMenuItems.length <= 0
|
actionsMenuItems.length <= 0
|
||||||
|
@ -320,6 +309,7 @@ function ObservabilityActions({
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Hide the WorkFlow filter, but keep its code as required in https://github.com/elastic/kibana/issues/117686
|
||||||
|
|
||||||
const FIELDS_WITHOUT_CELL_ACTIONS = [
|
const FIELDS_WITHOUT_CELL_ACTIONS = [
|
||||||
'@timestamp',
|
'@timestamp',
|
||||||
|
@ -330,7 +320,7 @@ const FIELDS_WITHOUT_CELL_ACTIONS = [
|
||||||
];
|
];
|
||||||
|
|
||||||
export function AlertsTableTGrid(props: AlertsTableTGridProps) {
|
export function AlertsTableTGrid(props: AlertsTableTGridProps) {
|
||||||
const { indexNames, rangeFrom, rangeTo, kuery, workflowStatus, setRefetch, addToQuery } = props;
|
const { indexNames, rangeFrom, rangeTo, kuery, workflowStatus, setRefetch } = props;
|
||||||
const prevWorkflowStatus = usePrevious(workflowStatus);
|
const prevWorkflowStatus = usePrevious(workflowStatus);
|
||||||
const {
|
const {
|
||||||
timelines,
|
timelines,
|
||||||
|
@ -382,7 +372,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) {
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const leadingControlColumns = useMemo(() => {
|
const leadingControlColumns: ControlColumnProps[] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: 'expand',
|
id: 'expand',
|
||||||
|
@ -428,7 +418,8 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) {
|
||||||
type,
|
type,
|
||||||
columns: tGridState?.columns ?? columns,
|
columns: tGridState?.columns ?? columns,
|
||||||
deletedEventIds,
|
deletedEventIds,
|
||||||
defaultCellActions: getDefaultCellActions({ addToQuery }),
|
// Hide the WorkFlow filter, but keep its code as required in https://github.com/elastic/kibana/issues/117686
|
||||||
|
// defaultCellActions: getDefaultCellActions({ addToQuery }),
|
||||||
disabledCellActions: FIELDS_WITHOUT_CELL_ACTIONS,
|
disabledCellActions: FIELDS_WITHOUT_CELL_ACTIONS,
|
||||||
end: rangeTo,
|
end: rangeTo,
|
||||||
filters: [],
|
filters: [],
|
||||||
|
@ -462,7 +453,6 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) {
|
||||||
};
|
};
|
||||||
}, [
|
}, [
|
||||||
casePermissions,
|
casePermissions,
|
||||||
addToQuery,
|
|
||||||
rangeTo,
|
rangeTo,
|
||||||
hasAlertsCrudPermissions,
|
hasAlertsCrudPermissions,
|
||||||
indexNames,
|
indexNames,
|
||||||
|
|
|
@ -9,10 +9,13 @@ import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||||
|
|
||||||
import { IndexPatternBase } from '@kbn/es-query';
|
import { IndexPatternBase } from '@kbn/es-query';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import React, { useCallback, useRef } from 'react';
|
import React, { useCallback, useRef, useState, useEffect } from 'react';
|
||||||
import useAsync from 'react-use/lib/useAsync';
|
import useAsync from 'react-use/lib/useAsync';
|
||||||
|
import { AlertStatus } from '@kbn/rule-data-utils/alerts_as_data_status';
|
||||||
|
import { ALERT_STATUS } from '@kbn/rule-data-utils/technical_field_names';
|
||||||
|
|
||||||
|
import { AlertStatusFilterButton } from '../../../common/typings';
|
||||||
import { ParsedTechnicalFields } from '../../../../rule_registry/common/parse_technical_fields';
|
import { ParsedTechnicalFields } from '../../../../rule_registry/common/parse_technical_fields';
|
||||||
import type { AlertWorkflowStatus } from '../../../common/typings';
|
|
||||||
import { ExperimentalBadge } from '../../components/shared/experimental_badge';
|
import { ExperimentalBadge } from '../../components/shared/experimental_badge';
|
||||||
import { useBreadcrumbs } from '../../hooks/use_breadcrumbs';
|
import { useBreadcrumbs } from '../../hooks/use_breadcrumbs';
|
||||||
import { useFetcher } from '../../hooks/use_fetcher';
|
import { useFetcher } from '../../hooks/use_fetcher';
|
||||||
|
@ -26,7 +29,7 @@ import { AlertsSearchBar } from './alerts_search_bar';
|
||||||
import { AlertsTableTGrid } from './alerts_table_t_grid';
|
import { AlertsTableTGrid } from './alerts_table_t_grid';
|
||||||
import { Provider, alertsPageStateContainer, useAlertsPageStateContainer } from './state_container';
|
import { Provider, alertsPageStateContainer, useAlertsPageStateContainer } from './state_container';
|
||||||
import './styles.scss';
|
import './styles.scss';
|
||||||
import { WorkflowStatusFilter } from './workflow_status_filter';
|
import { AlertsStatusFilter } from './alerts_status_filter';
|
||||||
import { AlertsDisclaimer } from './alerts_disclaimer';
|
import { AlertsDisclaimer } from './alerts_disclaimer';
|
||||||
|
|
||||||
export interface TopAlert {
|
export interface TopAlert {
|
||||||
|
@ -36,25 +39,29 @@ export interface TopAlert {
|
||||||
link?: string;
|
link?: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
}
|
}
|
||||||
|
const regExpEscape = (str: string) => str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||||
const NO_INDEX_NAMES: string[] = [];
|
const NO_INDEX_NAMES: string[] = [];
|
||||||
const NO_INDEX_PATTERNS: IndexPatternBase[] = [];
|
const NO_INDEX_PATTERNS: IndexPatternBase[] = [];
|
||||||
|
const BASE_ALERT_REGEX = new RegExp(`\\s*${regExpEscape(ALERT_STATUS)}\\s*:\\s*"(.*?|\\*?)"`);
|
||||||
|
const ALERT_STATUS_REGEX = new RegExp(
|
||||||
|
`\\s*and\\s*${regExpEscape(ALERT_STATUS)}\\s*:\\s*(".+?"|\\*?)|${regExpEscape(
|
||||||
|
ALERT_STATUS
|
||||||
|
)}\\s*:\\s*(".+?"|\\*?)`,
|
||||||
|
'gm'
|
||||||
|
);
|
||||||
|
|
||||||
function AlertsPage() {
|
function AlertsPage() {
|
||||||
const { core, plugins, ObservabilityPageTemplate } = usePluginContext();
|
const { core, plugins, ObservabilityPageTemplate } = usePluginContext();
|
||||||
|
const [alertFilterStatus, setAlertFilterStatus] = useState('' as AlertStatusFilterButton);
|
||||||
const { prepend } = core.http.basePath;
|
const { prepend } = core.http.basePath;
|
||||||
const refetch = useRef<() => void>();
|
const refetch = useRef<() => void>();
|
||||||
const timefilterService = useTimefilterService();
|
const timefilterService = useTimefilterService();
|
||||||
const {
|
const { rangeFrom, setRangeFrom, rangeTo, setRangeTo, kuery, setKuery, workflowStatus } =
|
||||||
rangeFrom,
|
useAlertsPageStateContainer();
|
||||||
setRangeFrom,
|
|
||||||
rangeTo,
|
useEffect(() => {
|
||||||
setRangeTo,
|
syncAlertStatusFilterStatus(kuery as string);
|
||||||
kuery,
|
}, [kuery]);
|
||||||
setKuery,
|
|
||||||
workflowStatus,
|
|
||||||
setWorkflowStatus,
|
|
||||||
} = useAlertsPageStateContainer();
|
|
||||||
|
|
||||||
useBreadcrumbs([
|
useBreadcrumbs([
|
||||||
{
|
{
|
||||||
|
@ -103,36 +110,56 @@ function AlertsPage() {
|
||||||
];
|
];
|
||||||
}, [indexNames]);
|
}, [indexNames]);
|
||||||
|
|
||||||
const setWorkflowStatusFilter = useCallback(
|
// Keep the Workflow status code commented (no delete) as requested: https://github.com/elastic/kibana/issues/117686
|
||||||
(value: AlertWorkflowStatus) => {
|
|
||||||
setWorkflowStatus(value);
|
// const setWorkflowStatusFilter = useCallback(
|
||||||
},
|
// (value: AlertWorkflowStatus) => {
|
||||||
[setWorkflowStatus]
|
// setWorkflowStatus(value);
|
||||||
);
|
// },
|
||||||
|
// [setWorkflowStatus]
|
||||||
|
// );
|
||||||
|
|
||||||
const onQueryChange = useCallback(
|
const onQueryChange = useCallback(
|
||||||
({ dateRange, query }) => {
|
({ dateRange, query }) => {
|
||||||
if (rangeFrom === dateRange.from && rangeTo === dateRange.to && kuery === (query ?? '')) {
|
if (rangeFrom === dateRange.from && rangeTo === dateRange.to && kuery === (query ?? '')) {
|
||||||
return refetch.current && refetch.current();
|
return refetch.current && refetch.current();
|
||||||
}
|
}
|
||||||
|
|
||||||
timefilterService.setTime(dateRange);
|
timefilterService.setTime(dateRange);
|
||||||
setRangeFrom(dateRange.from);
|
setRangeFrom(dateRange.from);
|
||||||
setRangeTo(dateRange.to);
|
setRangeTo(dateRange.to);
|
||||||
setKuery(query);
|
setKuery(query);
|
||||||
|
syncAlertStatusFilterStatus(query as string);
|
||||||
},
|
},
|
||||||
[rangeFrom, setRangeFrom, rangeTo, setRangeTo, kuery, setKuery, timefilterService]
|
[rangeFrom, setRangeFrom, rangeTo, setRangeTo, kuery, setKuery, timefilterService]
|
||||||
);
|
);
|
||||||
|
|
||||||
const addToQuery = useCallback(
|
const syncAlertStatusFilterStatus = (query: string) => {
|
||||||
(value: string) => {
|
const [, alertStatus] = BASE_ALERT_REGEX.exec(query) || [];
|
||||||
let output = value;
|
if (!alertStatus) {
|
||||||
if (kuery !== '') {
|
setAlertFilterStatus('');
|
||||||
output = `${kuery} and ${value}`;
|
return;
|
||||||
|
}
|
||||||
|
setAlertFilterStatus(alertStatus.toLowerCase() as AlertStatus);
|
||||||
|
};
|
||||||
|
const setAlertStatusFilter = useCallback(
|
||||||
|
(id: string, query: string) => {
|
||||||
|
setAlertFilterStatus(id as AlertStatusFilterButton);
|
||||||
|
// Updating the KQL query bar alongside with user inputs is tricky.
|
||||||
|
// To avoid issue, this function always remove the AlertFilter and add it
|
||||||
|
// at the end of the query, each time the filter is added/updated/removed (Show All)
|
||||||
|
// NOTE: This (query appending) will be changed entirely: https://github.com/elastic/kibana/issues/116135
|
||||||
|
let output = kuery;
|
||||||
|
if (kuery === '') {
|
||||||
|
output = query;
|
||||||
|
} else {
|
||||||
|
// console.log(ALERT_STATUS_REGEX);
|
||||||
|
const queryWithoutAlertFilter = kuery.replace(ALERT_STATUS_REGEX, '');
|
||||||
|
output = `${queryWithoutAlertFilter} and ${query}`;
|
||||||
}
|
}
|
||||||
onQueryChange({
|
onQueryChange({
|
||||||
dateRange: { from: rangeFrom, to: rangeTo },
|
dateRange: { from: rangeFrom, to: rangeTo },
|
||||||
query: output,
|
// Clean up the kuery from unwanted trailing/ahead ANDs after appending and removing filters.
|
||||||
|
query: output.replace(/^\s*and\s*|\s*and\s*$/gm, ''),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[kuery, onQueryChange, rangeFrom, rangeTo]
|
[kuery, onQueryChange, rangeFrom, rangeTo]
|
||||||
|
@ -194,7 +221,9 @@ function AlertsPage() {
|
||||||
<EuiFlexItem>
|
<EuiFlexItem>
|
||||||
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
|
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<WorkflowStatusFilter status={workflowStatus} onChange={setWorkflowStatusFilter} />
|
{/* Keep the Workflow status code commented (no delete) as requested: https://github.com/elastic/kibana/issues/117686*/}
|
||||||
|
{/* <WorkflowStatusFilter status={workflowStatus} onChange={setWorkflowStatusFilter} /> */}
|
||||||
|
<AlertsStatusFilter status={alertFilterStatus} onChange={setAlertStatusFilter} />
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
</EuiFlexGroup>
|
</EuiFlexGroup>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
@ -207,7 +236,6 @@ function AlertsPage() {
|
||||||
kuery={kuery}
|
kuery={kuery}
|
||||||
workflowStatus={workflowStatus}
|
workflowStatus={workflowStatus}
|
||||||
setRefetch={setRefetch}
|
setRefetch={setRefetch}
|
||||||
addToQuery={addToQuery}
|
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
</EuiFlexGroup>
|
</EuiFlexGroup>
|
||||||
|
|
|
@ -186,7 +186,7 @@ export default ({ getService }: FtrProviderContext) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Cell actions', () => {
|
describe.skip('Cell actions', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await retry.try(async () => {
|
await retry.try(async () => {
|
||||||
const cells = await observability.alerts.common.getTableCells();
|
const cells = await observability.alerts.common.getTableCells();
|
||||||
|
|
|
@ -39,7 +39,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||||
|
|
||||||
await assertAlertsPageState({
|
await assertAlertsPageState({
|
||||||
kuery: 'kibana.alert.evaluation.threshold > 75',
|
kuery: 'kibana.alert.evaluation.threshold > 75',
|
||||||
workflowStatus: 'Closed',
|
// workflowStatus: 'Closed',
|
||||||
timeRange: '~ a month ago - ~ 10 days ago',
|
timeRange: '~ a month ago - ~ 10 days ago',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -55,7 +55,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||||
|
|
||||||
await assertAlertsPageState({
|
await assertAlertsPageState({
|
||||||
kuery: '',
|
kuery: '',
|
||||||
workflowStatus: 'Open',
|
// workflowStatus: 'Open',
|
||||||
timeRange: 'Last 15 minutes',
|
timeRange: 'Last 15 minutes',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -77,15 +77,15 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||||
|
|
||||||
async function assertAlertsPageState(expected: {
|
async function assertAlertsPageState(expected: {
|
||||||
kuery: string;
|
kuery: string;
|
||||||
workflowStatus: string;
|
// workflowStatus: string;
|
||||||
timeRange: string;
|
timeRange: string;
|
||||||
}) {
|
}) {
|
||||||
expect(await (await observability.alerts.common.getQueryBar()).getVisibleText()).to.be(
|
expect(await (await observability.alerts.common.getQueryBar()).getVisibleText()).to.be(
|
||||||
expected.kuery
|
expected.kuery
|
||||||
);
|
);
|
||||||
expect(await observability.alerts.common.getWorkflowStatusFilterValue()).to.be(
|
// expect(await observability.alerts.common.getWorkflowStatusFilterValue()).to.be(
|
||||||
expected.workflowStatus
|
// expected.workflowStatus
|
||||||
);
|
// );
|
||||||
const timeRange = await observability.alerts.common.getTimeRange();
|
const timeRange = await observability.alerts.common.getTimeRange();
|
||||||
expect(timeRange).to.be(expected.timeRange);
|
expect(timeRange).to.be(expected.timeRange);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,8 @@ const OPEN_ALERTS_ROWS_COUNT = 33;
|
||||||
export default ({ getService }: FtrProviderContext) => {
|
export default ({ getService }: FtrProviderContext) => {
|
||||||
const esArchiver = getService('esArchiver');
|
const esArchiver = getService('esArchiver');
|
||||||
|
|
||||||
describe('alert workflow status', function () {
|
// Keep the Workflow status code commented (no delete) as requested: https://github.com/elastic/kibana/issues/117686
|
||||||
|
describe.skip('alert workflow status', function () {
|
||||||
this.tags('includeFirefox');
|
this.tags('includeFirefox');
|
||||||
|
|
||||||
const observability = getService('observability');
|
const observability = getService('observability');
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue