From 7f8d4403edcd0d84f1d074095c7a3f72c4efb4f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 3 Aug 2021 20:54:08 +0200 Subject: [PATCH 01/16] Remove outdated top_alerts route and related types --- .../pages/alerts/alerts_flyout/index.tsx | 9 +- .../public/pages/alerts/alerts_table.tsx | 167 ------------------ .../pages/alerts/alerts_table_t_grid.tsx | 20 +-- .../public/pages/alerts/decorate_response.ts | 39 ---- .../public/pages/alerts/index.tsx | 3 - .../public/pages/alerts/parse_alert.ts | 36 ++++ .../public/pages/alerts/render_cell_value.tsx | 8 +- .../server/lib/rules/get_top_alerts.ts | 52 ------ .../observability/server/routes/rules.ts | 45 +---- .../observability/server/utils/queries.ts | 10 -- 10 files changed, 55 insertions(+), 334 deletions(-) delete mode 100644 x-pack/plugins/observability/public/pages/alerts/alerts_table.tsx delete mode 100644 x-pack/plugins/observability/public/pages/alerts/decorate_response.ts create mode 100644 x-pack/plugins/observability/public/pages/alerts/parse_alert.ts delete mode 100644 x-pack/plugins/observability/server/lib/rules/get_top_alerts.ts diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_flyout/index.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_flyout/index.tsx index 53b5300e556c5..f22188c8290d2 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_flyout/index.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_flyout/index.tsx @@ -31,16 +31,16 @@ import { } from '@kbn/rule-data-utils/target/technical_field_names'; import moment from 'moment-timezone'; import React, { useMemo } from 'react'; -import type { TopAlert, TopAlertResponse } from '../'; +import type { TopAlert } from '../'; import { useKibana, useUiSetting } from '../../../../../../../src/plugins/kibana_react/public'; import { asDuration } from '../../../../common/utils/formatters'; import type { ObservabilityRuleTypeRegistry } from '../../../rules/create_observability_rule_type_registry'; -import { decorateResponse } from '../decorate_response'; +import { parseAlert } from '../parse_alert'; import { SeverityBadge } from '../severity_badge'; type AlertsFlyoutProps = { alert?: TopAlert; - alerts?: TopAlertResponse[]; + alerts?: Array>; isInApp?: boolean; observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry; selectedAlertId?: string; @@ -59,7 +59,8 @@ export function AlertsFlyout({ const { http } = services; const prepend = http?.basePath.prepend; const decoratedAlerts = useMemo(() => { - return decorateResponse(alerts ?? [], observabilityRuleTypeRegistry); + const parseObservabilityAlert = parseAlert(observabilityRuleTypeRegistry); + return (alerts ?? []).map(parseObservabilityAlert); }, [alerts, observabilityRuleTypeRegistry]); let alertData = alert; diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_table.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_table.tsx deleted file mode 100644 index 28d211766cfe5..0000000000000 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_table.tsx +++ /dev/null @@ -1,167 +0,0 @@ -/* - * 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 { - CustomItemAction, - EuiBasicTable, - EuiBasicTableColumn, - EuiButton, - EuiIconTip, - EuiLink, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { - ALERT_DURATION, - ALERT_SEVERITY_LEVEL, - ALERT_UUID, -} from '@kbn/rule-data-utils/target/technical_field_names'; -import React, { Suspense, useMemo, useState } from 'react'; -import { LazyAlertsFlyout } from '../..'; -import { asDuration } from '../../../common/utils/formatters'; -import { TimestampTooltip } from '../../components/shared/timestamp_tooltip'; -import { usePluginContext } from '../../hooks/use_plugin_context'; -import type { TopAlert, TopAlertResponse } from './'; -import { decorateResponse } from './decorate_response'; -import { SeverityBadge } from './severity_badge'; - -const pagination = { pageIndex: 0, pageSize: 0, totalItemCount: 0 }; - -interface AlertsTableProps { - items: TopAlertResponse[]; -} - -export function AlertsTable(props: AlertsTableProps) { - const [selectedAlertId, setSelectedAlertId] = useState(undefined); - const handleFlyoutClose = () => setSelectedAlertId(undefined); - const { core, observabilityRuleTypeRegistry } = usePluginContext(); - const { prepend } = core.http.basePath; - const items = useMemo(() => decorateResponse(props.items, observabilityRuleTypeRegistry), [ - props.items, - observabilityRuleTypeRegistry, - ]); - - const actions: Array> = useMemo( - () => [ - { - render: (alert) => - alert.link ? ( - - {i18n.translate('xpack.observability.alertsTable.viewInAppButtonLabel', { - defaultMessage: 'View in app', - })} - - ) : ( - <> - ), - isPrimary: true, - }, - ], - [prepend] - ); - - const columns: Array> = useMemo( - () => [ - { - field: 'active', - name: i18n.translate('xpack.observability.alertsTable.statusColumnDescription', { - defaultMessage: 'Status', - }), - align: 'center', - render: (_, alert) => { - const { active } = alert; - - return active ? ( - - ) : ( - - ); - }, - }, - { - field: 'start', - name: i18n.translate('xpack.observability.alertsTable.triggeredColumnDescription', { - defaultMessage: 'Triggered', - }), - render: (_, alert) => { - return ( - - ); - }, - }, - { - field: 'duration', - name: i18n.translate('xpack.observability.alertsTable.durationColumnDescription', { - defaultMessage: 'Duration', - }), - render: (_, alert) => { - const { active } = alert; - return active ? null : asDuration(alert.fields[ALERT_DURATION], { extended: true }); - }, - }, - { - field: 'severity', - name: i18n.translate('xpack.observability.alertsTable.severityColumnDescription', { - defaultMessage: 'Severity', - }), - render: (_, alert) => { - return ; - }, - }, - { - field: 'reason', - name: i18n.translate('xpack.observability.alertsTable.reasonColumnDescription', { - defaultMessage: 'Reason', - }), - dataType: 'string', - render: (_, alert) => { - return ( - setSelectedAlertId(alert.fields[ALERT_UUID])}> - {alert.reason} - - ); - }, - }, - { - actions, - name: i18n.translate('xpack.observability.alertsTable.actionsColumnDescription', { - defaultMessage: 'Actions', - }), - }, - ], - [actions, setSelectedAlertId] - ); - - return ( - <> - - - - - columns={columns} - items={items} - tableLayout="auto" - pagination={pagination} - /> - - ); -} diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx index 77c2b5cbca0cf..ad5ddd490cd24 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx @@ -9,7 +9,7 @@ import { EuiButtonIcon, EuiDataGridColumn } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import styled from 'styled-components'; -import React, { Suspense, useState } from 'react'; +import React, { Suspense, useMemo, useState } from 'react'; import { ALERT_DURATION, ALERT_SEVERITY_LEVEL, @@ -25,8 +25,8 @@ import type { ActionProps, ColumnHeaderOptions, RowRenderer } from '../../../../ import { getRenderCellValue } from './render_cell_value'; import { usePluginContext } from '../../hooks/use_plugin_context'; -import { decorateResponse } from './decorate_response'; import { LazyAlertsFlyout } from '../..'; +import { parseAlert } from './parse_alert'; interface AlertsTableTGridProps { indexName: string; @@ -117,6 +117,10 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) { const handleFlyoutClose = () => setFlyoutAlert(undefined); const { timelines } = useKibana<{ timelines: TimelinesUIStart }>().services; + const parseObservabilityAlert = useMemo(() => parseAlert(observabilityRuleTypeRegistry), [ + observabilityRuleTypeRegistry, + ]); + const leadingControlColumns = [ { id: 'expand', @@ -132,11 +136,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) { }, rowCellRender: ({ data }: ActionProps) => { const dataFieldEs = data.reduce((acc, d) => ({ ...acc, [d.field]: d.value }), {}); - const decoratedAlerts = decorateResponse( - [dataFieldEs] ?? [], - observabilityRuleTypeRegistry - ); - const alert = decoratedAlerts[0]; + const alert = parseObservabilityAlert(dataFieldEs); return ( null, rowCellRender: ({ data }: ActionProps) => { const dataFieldEs = data.reduce((acc, d) => ({ ...acc, [d.field]: d.value }), {}); - const decoratedAlerts = decorateResponse( - [dataFieldEs] ?? [], - observabilityRuleTypeRegistry - ); - const alert = decoratedAlerts[0]; + const alert = parseObservabilityAlert(dataFieldEs); return ( { - const parsedFields = parseTechnicalFields(alert); - const formatter = observabilityRuleTypeRegistry.getFormatter(parsedFields[RULE_ID]!); - const formatted = { - link: undefined, - reason: parsedFields[RULE_NAME]!, - ...(formatter?.({ fields: parsedFields, formatters: { asDuration, asPercent } }) ?? {}), - }; - - return { - ...formatted, - fields: parsedFields, - active: parsedFields[ALERT_STATUS] !== 'closed', - start: new Date(parsedFields[ALERT_START]!).getTime(), - }; - }); -} diff --git a/x-pack/plugins/observability/public/pages/alerts/index.tsx b/x-pack/plugins/observability/public/pages/alerts/index.tsx index fed9ee0be3a4a..ec640f4826585 100644 --- a/x-pack/plugins/observability/public/pages/alerts/index.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/index.tsx @@ -15,15 +15,12 @@ import { ExperimentalBadge } from '../../components/shared/experimental_badge'; import { useBreadcrumbs } from '../../hooks/use_breadcrumbs'; import { usePluginContext } from '../../hooks/use_plugin_context'; import { RouteParams } from '../../routes'; -import type { ObservabilityAPIReturnType } from '../../services/call_observability_api/types'; import { AlertsSearchBar } from './alerts_search_bar'; import { AlertsTableTGrid } from './alerts_table_t_grid'; import { StatusFilter } from './status_filter'; import { useFetcher } from '../../hooks/use_fetcher'; import { callObservabilityApi } from '../../services/call_observability_api'; -export type TopAlertResponse = ObservabilityAPIReturnType<'GET /api/observability/rules/alerts/top'>[number]; - export interface TopAlert { fields: ParsedTechnicalFields; start: number; diff --git a/x-pack/plugins/observability/public/pages/alerts/parse_alert.ts b/x-pack/plugins/observability/public/pages/alerts/parse_alert.ts new file mode 100644 index 0000000000000..a44ea74bd5cbf --- /dev/null +++ b/x-pack/plugins/observability/public/pages/alerts/parse_alert.ts @@ -0,0 +1,36 @@ +/* + * 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 { + RULE_ID, + RULE_NAME, + ALERT_STATUS, + ALERT_START, +} from '@kbn/rule-data-utils/target/technical_field_names'; +import type { TopAlert } from '.'; +import { parseTechnicalFields } from '../../../../rule_registry/common/parse_technical_fields'; +import { asDuration, asPercent } from '../../../common/utils/formatters'; +import { ObservabilityRuleTypeRegistry } from '../../rules/create_observability_rule_type_registry'; + +export const parseAlert = (observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry) => ( + alert: Record +): TopAlert => { + const parsedFields = parseTechnicalFields(alert); + const formatter = observabilityRuleTypeRegistry.getFormatter(parsedFields[RULE_ID]!); + const formatted = { + link: undefined, + reason: parsedFields[RULE_NAME]!, + ...(formatter?.({ fields: parsedFields, formatters: { asDuration, asPercent } }) ?? {}), + }; + + return { + ...formatted, + fields: parsedFields, + active: parsedFields[ALERT_STATUS] !== 'closed', + start: new Date(parsedFields[ALERT_START]!).getTime(), + }; +}; diff --git a/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx b/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx index bb6d0ae6c0e40..d9e30ad34e257 100644 --- a/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/render_cell_value.tsx @@ -20,7 +20,7 @@ import { TimestampTooltip } from '../../components/shared/timestamp_tooltip'; import { asDuration } from '../../../common/utils/formatters'; import { SeverityBadge } from './severity_badge'; import { TopAlert } from '.'; -import { decorateResponse } from './decorate_response'; +import { parseAlert } from './parse_alert'; import { usePluginContext } from '../../hooks/use_plugin_context'; const getMappedNonEcsValue = ({ @@ -95,11 +95,7 @@ export const getRenderCellValue = ({ return ; case RULE_NAME: const dataFieldEs = data.reduce((acc, d) => ({ ...acc, [d.field]: d.value }), {}); - const decoratedAlerts = decorateResponse( - [dataFieldEs] ?? [], - observabilityRuleTypeRegistry - ); - const alert = decoratedAlerts[0]; + const alert = parseAlert(observabilityRuleTypeRegistry)(dataFieldEs); return ( // NOTE: EuiLink automatically renders links using a