From 56dfd1830e2d3da4f858feeaf27c7c717a9f5dd3 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 11 Jun 2020 16:06:12 -0500 Subject: [PATCH 01/13] Add metric threshold global prefill --- .../components/alert_dropdown.tsx | 12 +- .../components/expression.tsx | 22 +- .../use_metric_threshold_alert_prefill.ts | 23 +++ .../public/alerting/metric_threshold/types.ts | 9 + .../public/alerting/use_alert_prefill.ts | 16 ++ .../infra/public/pages/metrics/index.tsx | 192 +++++++++--------- .../hooks/use_metrics_explorer_options.ts | 13 ++ 7 files changed, 183 insertions(+), 104 deletions(-) create mode 100644 x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metric_threshold_alert_prefill.ts create mode 100644 x-pack/plugins/infra/public/alerting/use_alert_prefill.ts diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx index d26575f65dfec..384a93e796dbe 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx @@ -7,14 +7,18 @@ import React, { useState, useCallback, useMemo } from 'react'; import { EuiPopover, EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { AlertFlyout } from './alert_flyout'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; +import { useAlertPrefillContext } from '../../use_alert_prefill'; +import { AlertFlyout } from './alert_flyout'; export const MetricsAlertDropdown = () => { const [popoverOpen, setPopoverOpen] = useState(false); const [flyoutVisible, setFlyoutVisible] = useState(false); const kibana = useKibana(); + const { metricThresholdPrefill } = useAlertPrefillContext(); + const { groupBy, filterQuery, metrics } = metricThresholdPrefill; + const closePopover = useCallback(() => { setPopoverOpen(false); }, [setPopoverOpen]); @@ -57,7 +61,11 @@ export const MetricsAlertDropdown = () => { > - + ); }; diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx index d5d61733e8717..8ba010ee85d98 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx @@ -38,21 +38,14 @@ import { useSourceViaHttp } from '../../../containers/source/use_source_via_http import { convertKueryToElasticSearchQuery } from '../../../utils/kuery'; import { ExpressionRow } from './expression_row'; -import { AlertContextMeta, TimeUnit, MetricExpression } from '../types'; +import { AlertContextMeta, TimeUnit, MetricExpression, AlertParams } from '../types'; import { ExpressionChart } from './expression_chart'; const FILTER_TYPING_DEBOUNCE_MS = 500; interface Props { errors: IErrorObject[]; - alertParams: { - criteria: MetricExpression[]; - groupBy?: string; - filterQuery?: string; - sourceId?: string; - filterQueryText?: string; - alertOnNoData?: boolean; - }; + alertParams: AlertParams; alertsContext: AlertsContextValue; setAlertParams(key: string, value: any): void; setAlertProperty(key: string, value: any): void; @@ -224,6 +217,13 @@ export const Expressions: React.FC = (props) => { } }, [alertsContext.metadata, derivedIndexPattern, setAlertParams]); + const preFillAlertGroupBy = useCallback(() => { + const md = alertsContext.metadata; + if (md && md.currentOptions?.groupBy && !md.series) { + setAlertParams('groupBy', md.currentOptions.groupBy); + } + }, [alertsContext.metadata, setAlertParams]); + useEffect(() => { if (alertParams.criteria && alertParams.criteria.length) { setTimeSize(alertParams.criteria[0].timeSize); @@ -236,6 +236,10 @@ export const Expressions: React.FC = (props) => { preFillAlertFilter(); } + if (!alertParams.groupBy) { + preFillAlertGroupBy(); + } + if (!alertParams.sourceId) { setAlertParams('sourceId', source?.id || 'default'); } diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metric_threshold_alert_prefill.ts b/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metric_threshold_alert_prefill.ts new file mode 100644 index 0000000000000..6b1eae66206f3 --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metric_threshold_alert_prefill.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useState } from 'react'; +import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer'; + +export const useMetricThresholdAlertPrefill = () => { + const [groupBy, setGroupBy] = useState(); + const [filterQuery, setFilterQuery] = useState(); + const [metrics, setMetrics] = useState([]); + + return { + groupBy, + filterQuery, + metrics, + setGroupBy, + setFilterQuery, + setMetrics, + }; +}; diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/types.ts b/x-pack/plugins/infra/public/alerting/metric_threshold/types.ts index feeec4b0ce8bf..2f8d7ec0ba6f4 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/types.ts +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/types.ts @@ -51,3 +51,12 @@ export interface ExpressionChartData { id: string; series: ExpressionChartSeries; } + +export interface AlertParams { + criteria: MetricExpression[]; + groupBy?: string; + filterQuery?: string; + sourceId?: string; + filterQueryText?: string; + alertOnNoData?: boolean; +} diff --git a/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts b/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts new file mode 100644 index 0000000000000..58e4f134f60ea --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import createContainer from 'constate'; +import { useMetricThresholdAlertPrefill } from './metric_threshold/hooks/use_metric_threshold_alert_prefill'; + +const useAlertPrefill = () => { + const metricThresholdPrefill = useMetricThresholdAlertPrefill(); + + return { metricThresholdPrefill }; +}; + +export const [AlertPrefillProvider, useAlertPrefillContext] = createContainer(useAlertPrefill); diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index 35a6cadc786f6..a0516cec9f34c 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -31,6 +31,7 @@ import { WaffleFiltersProvider } from './inventory_view/hooks/use_waffle_filters import { InventoryAlertDropdown } from '../../components/alerting/inventory/alert_dropdown'; import { MetricsAlertDropdown } from '../../alerting/metric_threshold/components/alert_dropdown'; +import { AlertPrefillProvider } from '../../alerting/use_alert_prefill'; export const InfrastructurePage = ({ match }: RouteComponentProps) => { const uiCapabilities = useKibana().services.application?.capabilities; @@ -38,102 +39,107 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => { return ( - - - - - - - + + + + + + -
- - - - - - - - - - - + - - - ( - - {({ configuration, createDerivedIndexPattern }) => ( - - - {configuration ? ( - - ) : ( - - )} - - )} - - )} +
- - - - - - + + + + + + + + + + + + + + + ( + + {({ configuration, createDerivedIndexPattern }) => ( + + + {configuration ? ( + + ) : ( + + )} + + )} + + )} + /> + + + + + + + ); diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts index 56595c09aadde..07386b9fbc794 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts @@ -6,6 +6,7 @@ import createContainer from 'constate'; import { useState, useEffect, Dispatch, SetStateAction } from 'react'; +import { useAlertPrefillContext } from '../../../../alerting/use_alert_prefill'; import { MetricsExplorerColor } from '../../../../../common/color_palette'; import { MetricsExplorerAggregation, @@ -122,6 +123,18 @@ export const useMetricsExplorerOptions = () => { DEFAULT_CHART_OPTIONS ); const [isAutoReloading, setAutoReloading] = useState(false); + + const { metricThresholdPrefill } = useAlertPrefillContext(); + + useEffect(() => { + const { setMetrics, setGroupBy, setFilterQuery } = metricThresholdPrefill; + const { metrics, groupBy, filterQuery } = options; + + setGroupBy(groupBy); + setFilterQuery(filterQuery); + setMetrics(metrics); + }, [options, metricThresholdPrefill]); + return { defaultViewState: { options: DEFAULT_OPTIONS, From ef863c6ac8201b5c5a6beb345eaa13f4befd3982 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 11 Jun 2020 16:43:34 -0500 Subject: [PATCH 02/13] Add inventory alert prefill --- .../hooks/use_inventory_alert_prefill.ts | 24 +++++++++++++++++++ .../public/alerting/use_alert_prefill.ts | 4 +++- .../alerting/inventory/alert_dropdown.tsx | 12 +++++++++- .../hooks/use_waffle_filters.ts | 4 ++++ .../hooks/use_waffle_options.ts | 8 +++++++ 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/infra/public/alerting/inventory/hooks/use_inventory_alert_prefill.ts diff --git a/x-pack/plugins/infra/public/alerting/inventory/hooks/use_inventory_alert_prefill.ts b/x-pack/plugins/infra/public/alerting/inventory/hooks/use_inventory_alert_prefill.ts new file mode 100644 index 0000000000000..d659057b95ed9 --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/inventory/hooks/use_inventory_alert_prefill.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useState } from 'react'; +import { SnapshotMetricInput } from '../../../../common/http_api/snapshot_api'; +import { InventoryItemType } from '../../../../common/inventory_models/types'; + +export const useInventoryAlertPrefill = () => { + const [nodeType, setNodeType] = useState('host'); + const [filterQuery, setFilterQuery] = useState(); + const [metric, setMetric] = useState({ type: 'cpu' }); + + return { + nodeType, + filterQuery, + metric, + setNodeType, + setFilterQuery, + setMetric, + }; +}; diff --git a/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts b/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts index 58e4f134f60ea..eff2fe462509f 100644 --- a/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts +++ b/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts @@ -6,11 +6,13 @@ import createContainer from 'constate'; import { useMetricThresholdAlertPrefill } from './metric_threshold/hooks/use_metric_threshold_alert_prefill'; +import { useInventoryAlertPrefill } from './inventory/hooks/use_inventory_alert_prefill'; const useAlertPrefill = () => { const metricThresholdPrefill = useMetricThresholdAlertPrefill(); + const inventoryPrefill = useInventoryAlertPrefill(); - return { metricThresholdPrefill }; + return { metricThresholdPrefill, inventoryPrefill }; }; export const [AlertPrefillProvider, useAlertPrefillContext] = createContainer(useAlertPrefill); diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/alert_dropdown.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/alert_dropdown.tsx index 47a0f037816bc..04642a01c15b4 100644 --- a/x-pack/plugins/infra/public/components/alerting/inventory/alert_dropdown.tsx +++ b/x-pack/plugins/infra/public/components/alerting/inventory/alert_dropdown.tsx @@ -7,6 +7,7 @@ import React, { useState, useCallback, useMemo } from 'react'; import { EuiPopover, EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { useAlertPrefillContext } from '../../../alerting/use_alert_prefill'; import { AlertFlyout } from './alert_flyout'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; @@ -15,6 +16,9 @@ export const InventoryAlertDropdown = () => { const [flyoutVisible, setFlyoutVisible] = useState(false); const kibana = useKibana(); + const { inventoryPrefill } = useAlertPrefillContext(); + const { nodeType, metric, filterQuery } = inventoryPrefill; + const closePopover = useCallback(() => { setPopoverOpen(false); }, [setPopoverOpen]); @@ -57,7 +61,13 @@ export const InventoryAlertDropdown = () => { > - + ); }; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts index 63d9d08796f05..16db7c2b1968f 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts @@ -10,6 +10,7 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { constant, identity } from 'fp-ts/lib/function'; import createContainter from 'constate'; +import { useAlertPrefillContext } from '../../../../alerting/use_alert_prefill'; import { useUrlState } from '../../../../utils/use_url_state'; import { useSourceContext } from '../../../../containers/source'; import { convertKueryToElasticSearchQuery } from '../../../../utils/kuery'; @@ -68,6 +69,9 @@ export const useWaffleFilters = () => { filterQueryDraft, ]); + const { inventoryPrefill } = useAlertPrefillContext(); + useEffect(() => inventoryPrefill.setFilterQuery(state.expression), [inventoryPrefill, state]); + return { filterQuery: urlState, filterQueryDraft, diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts index 975e33cf2415f..a3132c8384979 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts @@ -10,6 +10,7 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { constant, identity } from 'fp-ts/lib/function'; import createContainer from 'constate'; +import { useAlertPrefillContext } from '../../../../alerting/use_alert_prefill'; import { InventoryColorPaletteRT } from '../../../../lib/lib'; import { SnapshotMetricInput, @@ -121,6 +122,13 @@ export const useWaffleOptions = () => { [setState] ); + const { inventoryPrefill } = useAlertPrefillContext(); + useEffect(() => { + const { setNodeType, setMetric } = inventoryPrefill; + setNodeType(state.nodeType); + setMetric(state.metric); + }, [state, inventoryPrefill]); + return { ...DEFAULT_WAFFLE_OPTIONS_STATE, ...state, From 016442c8825ab233ce687b5e5b3c079d03b53a4d Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Fri, 12 Jun 2020 11:09:02 -0500 Subject: [PATCH 03/13] Fix jest --- .../hooks/use_metrics_explorer_options.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts index 07386b9fbc794..5d30456902969 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts @@ -127,12 +127,14 @@ export const useMetricsExplorerOptions = () => { const { metricThresholdPrefill } = useAlertPrefillContext(); useEffect(() => { - const { setMetrics, setGroupBy, setFilterQuery } = metricThresholdPrefill; - const { metrics, groupBy, filterQuery } = options; - - setGroupBy(groupBy); - setFilterQuery(filterQuery); - setMetrics(metrics); + if (metricThresholdPrefill) { + const { setMetrics, setGroupBy, setFilterQuery } = metricThresholdPrefill; + const { metrics, groupBy, filterQuery } = options; + + setGroupBy(groupBy); + setFilterQuery(filterQuery); + setMetrics(metrics); + } }, [options, metricThresholdPrefill]); return { From 2d783535d7a48824673703165362da40b2685857 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 18 Jun 2020 12:49:16 -0500 Subject: [PATCH 04/13] Add metric prefill test to useMetricExplorerOptions --- .../use_metric_threshold_alert_prefill.ts | 20 ++++++--- .../public/alerting/use_alert_prefill.ts | 7 +++- .../use_metrics_explorer_options.test.tsx | 41 ++++++++++++++++--- .../hooks/use_metrics_explorer_options.ts | 15 +++---- 4 files changed, 63 insertions(+), 20 deletions(-) diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metric_threshold_alert_prefill.ts b/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metric_threshold_alert_prefill.ts index 6b1eae66206f3..a11a57b90e605 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metric_threshold_alert_prefill.ts +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metric_threshold_alert_prefill.ts @@ -7,17 +7,25 @@ import { useState } from 'react'; import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer'; +interface MetricThresholdPrefillOptions { + groupBy: string | string[] | undefined; + filterQuery: string | undefined; + metrics: MetricsExplorerMetric[]; +} + export const useMetricThresholdAlertPrefill = () => { - const [groupBy, setGroupBy] = useState(); - const [filterQuery, setFilterQuery] = useState(); - const [metrics, setMetrics] = useState([]); + const [{ groupBy, filterQuery, metrics }, setPrefillOptions] = useState< + MetricThresholdPrefillOptions + >({ + groupBy: undefined, + filterQuery: undefined, + metrics: [], + }); return { groupBy, filterQuery, metrics, - setGroupBy, - setFilterQuery, - setMetrics, + setPrefillOptions, }; }; diff --git a/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts b/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts index eff2fe462509f..5fd76e50b7a66 100644 --- a/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts +++ b/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts @@ -15,4 +15,9 @@ const useAlertPrefill = () => { return { metricThresholdPrefill, inventoryPrefill }; }; -export const [AlertPrefillProvider, useAlertPrefillContext] = createContainer(useAlertPrefill); +const [AlertPrefillProvider, useAlertPrefillContext] = createContainer(useAlertPrefill); +export { AlertPrefillProvider }; + +const useTestableAlertPrefillContext = () => + (window as any).__jestAlertPrefillMock ?? useAlertPrefillContext(); +export { useTestableAlertPrefillContext as useAlertPrefillContext }; diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx index 1381ed9da656a..dc9527fa585f0 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx @@ -6,9 +6,9 @@ import React from 'react'; import { renderHook, act } from '@testing-library/react-hooks'; +import { AlertPrefillProvider } from '../../../../alerting/use_alert_prefill'; import { useMetricsExplorerOptions, - MetricsExplorerOptionsContainer, MetricsExplorerOptions, MetricsExplorerTimeOptions, DEFAULT_OPTIONS, @@ -18,11 +18,7 @@ import { const renderUseMetricsExplorerOptionsHook = () => renderHook(() => useMetricsExplorerOptions(), { initialProps: {}, - wrapper: ({ children }) => ( - - {children} - - ), + wrapper: ({ children }) => {children}, }); interface LocalStore { @@ -48,10 +44,24 @@ Object.defineProperty(window, 'localStorage', { value: localStorageMock, }); +let PREFILL: Record = {}; +const alertPrefillMock = { + metricThresholdPrefill: { + setPrefillOptions(opts: Record) { + PREFILL = opts; + }, + }, +}; + +Object.defineProperty(window, '__jestAlertPrefillMock', { + value: alertPrefillMock, +}); + describe('useMetricExplorerOptions', () => { beforeEach(() => { delete STORE.MetricsExplorerOptions; delete STORE.MetricsExplorerTimeRange; + PREFILL = {}; }); it('should just work', () => { @@ -100,4 +110,23 @@ describe('useMetricExplorerOptions', () => { const { result } = renderUseMetricsExplorerOptionsHook(); expect(result.current.options).toEqual(newOptions); }); + + it('should sync the options to the threshold alert preview context', () => { + const { result, rerender } = renderUseMetricsExplorerOptionsHook(); + + const newOptions: MetricsExplorerOptions = { + ...DEFAULT_OPTIONS, + metrics: [{ aggregation: 'count' }], + filterQuery: 'foo', + groupBy: 'host.hostname', + }; + act(() => { + result.current.setOptions(newOptions); + }); + rerender(); + const currentOptions = result.current.options; + expect(currentOptions.metrics).toEqual(PREFILL.metrics); + expect(currentOptions.groupBy).toEqual(PREFILL.groupBy); + expect(currentOptions.filterQuery).toEqual(PREFILL.filterQuery); + }); }); diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts index 5d30456902969..8abdffd39ed3a 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts @@ -5,7 +5,7 @@ */ import createContainer from 'constate'; -import { useState, useEffect, Dispatch, SetStateAction } from 'react'; +import { useState, useEffect, useMemo, Dispatch, SetStateAction } from 'react'; import { useAlertPrefillContext } from '../../../../alerting/use_alert_prefill'; import { MetricsExplorerColor } from '../../../../../common/color_palette'; import { @@ -125,17 +125,18 @@ export const useMetricsExplorerOptions = () => { const [isAutoReloading, setAutoReloading] = useState(false); const { metricThresholdPrefill } = useAlertPrefillContext(); + // For Jest compatibility; including metricThresholdPrefill as a dep in useEffect causes an + // infinite loop in test environment + const prefillContext = useMemo(() => metricThresholdPrefill, [metricThresholdPrefill]); useEffect(() => { - if (metricThresholdPrefill) { - const { setMetrics, setGroupBy, setFilterQuery } = metricThresholdPrefill; + if (prefillContext) { + const { setPrefillOptions } = prefillContext; const { metrics, groupBy, filterQuery } = options; - setGroupBy(groupBy); - setFilterQuery(filterQuery); - setMetrics(metrics); + setPrefillOptions({ metrics, groupBy, filterQuery }); } - }, [options, metricThresholdPrefill]); + }, [options, prefillContext]); return { defaultViewState: { From f0394e83df2df6edfe2b549018973df3a7c8e1e7 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 18 Jun 2020 15:53:33 -0500 Subject: [PATCH 05/13] Switch thres metric options test to jest.mock; add waffle filter test --- .../public/alerting/use_alert_prefill.ts | 7 +-- .../hooks/use_waffle_filters.test.ts | 55 +++++++++++++++++++ .../hooks/use_waffle_filters.ts | 3 +- .../use_metrics_explorer_options.test.tsx | 39 +++++-------- 4 files changed, 73 insertions(+), 31 deletions(-) create mode 100644 x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.test.ts diff --git a/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts b/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts index 5fd76e50b7a66..eff2fe462509f 100644 --- a/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts +++ b/x-pack/plugins/infra/public/alerting/use_alert_prefill.ts @@ -15,9 +15,4 @@ const useAlertPrefill = () => { return { metricThresholdPrefill, inventoryPrefill }; }; -const [AlertPrefillProvider, useAlertPrefillContext] = createContainer(useAlertPrefill); -export { AlertPrefillProvider }; - -const useTestableAlertPrefillContext = () => - (window as any).__jestAlertPrefillMock ?? useAlertPrefillContext(); -export { useTestableAlertPrefillContext as useAlertPrefillContext }; +export const [AlertPrefillProvider, useAlertPrefillContext] = createContainer(useAlertPrefill); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.test.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.test.ts new file mode 100644 index 0000000000000..23dc974cc7dc4 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.test.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { renderHook, act } from '@testing-library/react-hooks'; + +import { useWaffleFilters, WaffleFiltersState } from './use_waffle_filters'; + +jest.mock('react-router-dom', () => ({ + useHistory: () => ({ + location: '', + replace: () => {}, + }), +})); + +jest.mock('../../../../containers/source', () => ({ + useSourceContext: () => ({ + createDerivedIndexPattern: () => 'jestbeat-*', + }), +})); + +let PREFILL: Record = {}; +jest.mock('../../../../alerting/use_alert_prefill', () => ({ + useAlertPrefillContext: () => ({ + inventoryPrefill: { + setFilterQuery(filterQuery: string) { + PREFILL = { filterQuery }; + }, + }, + }), +})); + +const renderUseWaffleFiltersHook = () => renderHook(() => useWaffleFilters()); + +describe('useWaffleFilters', () => { + beforeEach(() => { + PREFILL = {}; + }); + + it('should sync the options to the inventory alert preview context', () => { + const { result, rerender } = renderUseWaffleFiltersHook(); + + const newQuery = { + expression: 'foo', + kind: 'kuery', + } as WaffleFiltersState; + act(() => { + result.current.applyFilterQuery(newQuery); + }); + rerender(); + expect(PREFILL.filterQuery).toEqual(newQuery.expression); + }); +}); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts index 16db7c2b1968f..d4fb1356be77e 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts @@ -70,7 +70,8 @@ export const useWaffleFilters = () => { ]); const { inventoryPrefill } = useAlertPrefillContext(); - useEffect(() => inventoryPrefill.setFilterQuery(state.expression), [inventoryPrefill, state]); + const prefillContext = useMemo(() => inventoryPrefill, [inventoryPrefill]); // For Jest compatibility + useEffect(() => prefillContext.setFilterQuery(state.expression), [prefillContext, state]); return { filterQuery: urlState, diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx index dc9527fa585f0..c35e9f17bdcc3 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; import { renderHook, act } from '@testing-library/react-hooks'; -import { AlertPrefillProvider } from '../../../../alerting/use_alert_prefill'; import { useMetricsExplorerOptions, MetricsExplorerOptions, @@ -15,11 +13,18 @@ import { DEFAULT_TIMERANGE, } from './use_metrics_explorer_options'; -const renderUseMetricsExplorerOptionsHook = () => - renderHook(() => useMetricsExplorerOptions(), { - initialProps: {}, - wrapper: ({ children }) => {children}, - }); +let PREFILL: Record = {}; +jest.mock('../../../../alerting/use_alert_prefill', () => ({ + useAlertPrefillContext: () => ({ + metricThresholdPrefill: { + setPrefillOptions(opts: Record) { + PREFILL = opts; + }, + }, + }), +})); + +const renderUseMetricsExplorerOptionsHook = () => renderHook(() => useMetricsExplorerOptions()); interface LocalStore { [key: string]: string; @@ -44,19 +49,6 @@ Object.defineProperty(window, 'localStorage', { value: localStorageMock, }); -let PREFILL: Record = {}; -const alertPrefillMock = { - metricThresholdPrefill: { - setPrefillOptions(opts: Record) { - PREFILL = opts; - }, - }, -}; - -Object.defineProperty(window, '__jestAlertPrefillMock', { - value: alertPrefillMock, -}); - describe('useMetricExplorerOptions', () => { beforeEach(() => { delete STORE.MetricsExplorerOptions; @@ -124,9 +116,8 @@ describe('useMetricExplorerOptions', () => { result.current.setOptions(newOptions); }); rerender(); - const currentOptions = result.current.options; - expect(currentOptions.metrics).toEqual(PREFILL.metrics); - expect(currentOptions.groupBy).toEqual(PREFILL.groupBy); - expect(currentOptions.filterQuery).toEqual(PREFILL.filterQuery); + expect(PREFILL.metrics).toEqual(newOptions.metrics); + expect(PREFILL.groupBy).toEqual(newOptions.groupBy); + expect(PREFILL.filterQuery).toEqual(newOptions.filterQuery); }); }); From 5f00cc1c536366a9e3f7e28b07e4b03c9d6eaf50 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 18 Jun 2020 16:08:18 -0500 Subject: [PATCH 06/13] Add waffle options test --- .../metrics/inventory_view/hooks/use_waffle_filters.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.test.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.test.ts index 23dc974cc7dc4..93b6b635183dd 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.test.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.test.ts @@ -8,6 +8,7 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { useWaffleFilters, WaffleFiltersState } from './use_waffle_filters'; +// Mock useUrlState hook jest.mock('react-router-dom', () => ({ useHistory: () => ({ location: '', From bdf9b9021e3b4058802f606f54684618aa1592b1 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 18 Jun 2020 16:08:49 -0500 Subject: [PATCH 07/13] Commit missing files --- .../hooks/use_waffle_options.test.ts | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.test.ts diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.test.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.test.ts new file mode 100644 index 0000000000000..11d5b6f8e5a5d --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.test.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { renderHook, act } from '@testing-library/react-hooks'; + +import { useWaffleOptions, WaffleOptionsState } from './use_waffle_options'; + +// Mock useUrlState hook +jest.mock('react-router-dom', () => ({ + useHistory: () => ({ + location: '', + replace: () => {}, + }), +})); + +// Jest can't access variables outside the scope of the mock factory function except to +// reassign them, so we can't make these both part of the same object +let PREFILL_NODETYPE; +let PREFILL_METRIC; +jest.mock('../../../../alerting/use_alert_prefill', () => ({ + useAlertPrefillContext: () => ({ + inventoryPrefill: { + setNodeType(nodeType: string) { + PREFILL_NODETYPE = nodeType; + }, + setMetric(metric: { type: string }) { + PREFILL_METRIC = metric; + }, + }, + }), +})); + +const renderUseWaffleOptionsHook = () => renderHook(() => useWaffleOptions()); + +describe('useWaffleOptions', () => { + beforeEach(() => { + PREFILL_NODETYPE = undefined; + PREFILL_METRIC = undefined; + }); + + it('should sync the options to the inventory alert preview context', () => { + const { result, rerender } = renderUseWaffleOptionsHook(); + + const newOptions = { + nodeType: 'pod', + metriic: { type: 'memory' }, + } as WaffleOptionsState; + act(() => { + result.current.changeNodeType(newOptions.nodeType); + }); + rerender(); + expect(PREFILL_NODETYPE).toEqual(newOptions.nodeType); + act(() => { + result.current.changeMetric(newOptions.metric); + }); + rerender(); + expect(PREFILL_METRIC).toEqual(newOptions.metric); + }); +}); From dd4eab41a632f2e1fd28fcc3c2570c08b1db9f7b Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 18 Jun 2020 17:03:04 -0500 Subject: [PATCH 08/13] Expression component test WIP --- .../components/expression.test.tsx | 102 ++++++++++++++++++ .../components/expression.tsx | 6 +- .../components/validation.tsx | 2 +- .../common/expression_items/threshold.tsx | 4 +- 4 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.test.tsx diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.test.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.test.tsx new file mode 100644 index 0000000000000..c1addc84dd656 --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.test.tsx @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers'; +import { actionTypeRegistryMock } from '../../../../../triggers_actions_ui/public/application/action_type_registry.mock'; +import { alertTypeRegistryMock } from '../../../../../triggers_actions_ui/public/application/alert_type_registry.mock'; +import { coreMock } from '../../../../../../../src/core/public/mocks'; +import { AlertsContextValue } from '../../../../../triggers_actions_ui/public/application/context/alerts_context'; +import { AlertContextMeta, MetricExpression } from '../types'; +import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer'; +import React from 'react'; +import { Expressions, defaultExpression } from './expression'; +import { act } from 'react-dom/test-utils'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { Comparator } from '../../../../server/lib/alerting/metric_threshold/types'; +import { MetricsExplorerResponse } from '../../../../common/http_api'; +import { validateMetricThreshold } from './validation'; + +describe('Expression', () => { + async function setup(currentOptions: { + metrics?: MetricsExplorerMetric[]; + filterQuery?: string; + groupBy?: string; + }) { + const alertParams = { + criteria: [defaultExpression], + }; + + const mocks = coreMock.createSetup(); + const [ + { + application: { capabilities }, + }, + ] = await mocks.getStartServices(); + + const context: AlertsContextValue = { + http: mocks.http, + toastNotifications: mocks.notifications.toasts, + actionTypeRegistry: actionTypeRegistryMock.create() as any, + alertTypeRegistry: alertTypeRegistryMock.create() as any, + docLinks: mocks.docLinks, + capabilities: { + ...capabilities, + actions: { + delete: true, + save: true, + show: true, + }, + }, + metadata: { + currentOptions, + }, + }; + + const validationResult = validateMetricThreshold([alertParams.criteria]); + + const wrapper = mountWithIntl( + Reflect.set(alertParams, key, value)} + setAlertProperty={() => {}} + /> + ); + + const update = async () => + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + await update(); + + return { wrapper, update, alertParams }; + } + + it('should prefill the alert using the context metadata', async () => { + const currentOptions = { + groupBy: 'host.hostname', + filterQuery: 'foo', + metrics: [{ aggregation: 'avg', field: 'system.load.1' }], + }; + const { alertParams } = await setup(currentOptions); + expect(alertParams.groupBy).toBe('host.hostname'); + expect(alertParams.filterQueryText).toBe('foo'); + expect(alertParams.criteria).toEqual([ + { + metric: 'system.load.1', + comparator: Comparator.GT, + threshold: [], + timeSize, + timeUnit, + aggType: 'avg', + }, + ]); + }); +}); diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx index e7e917a8510a3..77f6285c323c3 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { debounce, pick } from 'lodash'; +import { debounce, pick, omit } from 'lodash'; import * as rt from 'io-ts'; import { HttpSetup } from 'src/core/public'; import React, { ChangeEvent, useCallback, useMemo, useEffect, useState } from 'react'; @@ -71,6 +71,7 @@ const defaultExpression = { timeSize: 1, timeUnit: 'm', } as MetricExpression; +export { defaultExpression }; async function getAlertPreview({ fetch, @@ -481,7 +482,7 @@ export const Expressions: React.FC = (props) => { id="selectPreviewLookbackInterval" value={previewLookbackInterval} onChange={onSelectPreviewLookbackInterval} - options={previewOptions} + options={previewDOMOptions} /> @@ -642,6 +643,7 @@ const previewOptions = [ }), }, ]; +const previewDOMOptions = previewOptions.map((o) => omit(o, 'shortText')); const firedTimeLabel = i18n.translate('xpack.infra.metrics.alertFlyout.firedTime', { defaultMessage: 'time', diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/validation.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/validation.tsx index da342f0a45420..2221d3cd4fe12 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/validation.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/validation.tsx @@ -50,7 +50,7 @@ export function validateMetricThreshold({ if (!c.aggType) { errors[id].aggField.push( i18n.translate('xpack.infra.metrics.alertFlyout.error.aggregationRequired', { - defaultMessage: 'Aggreation is required.', + defaultMessage: 'Aggregation is required.', }) ); } diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/threshold.tsx b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/threshold.tsx index 09acf4fe1ef68..fe592aadb37a5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/threshold.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/threshold.tsx @@ -136,14 +136,14 @@ export const ThresholdExpression = ({ ) : null} 0 || !threshold[i]} + isInvalid={errors[`threshold${i}`]?.length > 0 || !threshold[i]} error={errors[`threshold${i}`]} > 0 || !threshold[i]} + isInvalid={errors[`threshold${i}`]?.length > 0 || !threshold[i]} onChange={(e) => { const { value } = e.target; const thresholdVal = value !== '' ? parseFloat(value) : undefined; From 8809d7c700cd1aeec4b95e6d9145f7bb43630d66 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Tue, 23 Jun 2020 11:56:51 -0500 Subject: [PATCH 09/13] Add Expression enzyme test for prefill --- .../components/expression.test.tsx | 36 +++++++++++++------ .../containers/with_kuery_autocompletion.tsx | 2 +- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.test.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.test.tsx index c1addc84dd656..f0602ccf15d44 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.test.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.test.tsx @@ -9,15 +9,20 @@ import { actionTypeRegistryMock } from '../../../../../triggers_actions_ui/publi import { alertTypeRegistryMock } from '../../../../../triggers_actions_ui/public/application/alert_type_registry.mock'; import { coreMock } from '../../../../../../../src/core/public/mocks'; import { AlertsContextValue } from '../../../../../triggers_actions_ui/public/application/context/alerts_context'; -import { AlertContextMeta, MetricExpression } from '../types'; +import { AlertContextMeta } from '../types'; import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer'; import React from 'react'; import { Expressions, defaultExpression } from './expression'; import { act } from 'react-dom/test-utils'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { Comparator } from '../../../../server/lib/alerting/metric_threshold/types'; -import { MetricsExplorerResponse } from '../../../../common/http_api'; -import { validateMetricThreshold } from './validation'; + +jest.mock('../../../containers/source/use_source_via_http', () => ({ + useSourceViaHttp: (any) => ({ + source: { id: 'default' }, + createDerivedIndexPattern: () => ({ fields: [], title: 'metricbeat-*' }), + }), +})); describe('Expression', () => { async function setup(currentOptions: { @@ -26,7 +31,9 @@ describe('Expression', () => { groupBy?: string; }) { const alertParams = { - criteria: [defaultExpression], + criteria: [], + groupBy: undefined, + filterQueryText: '', }; const mocks = coreMock.createSetup(); @@ -55,14 +62,12 @@ describe('Expression', () => { }, }; - const validationResult = validateMetricThreshold([alertParams.criteria]); - const wrapper = mountWithIntl( Reflect.set(alertParams, key, value)} setAlertProperty={() => {}} /> @@ -83,7 +88,10 @@ describe('Expression', () => { const currentOptions = { groupBy: 'host.hostname', filterQuery: 'foo', - metrics: [{ aggregation: 'avg', field: 'system.load.1' }], + metrics: [ + { aggregation: 'avg', field: 'system.load.1' }, + { aggregation: 'cardinality', field: 'system.cpu.user.pct' }, + ] as MetricsExplorerMetric[], }; const { alertParams } = await setup(currentOptions); expect(alertParams.groupBy).toBe('host.hostname'); @@ -93,10 +101,18 @@ describe('Expression', () => { metric: 'system.load.1', comparator: Comparator.GT, threshold: [], - timeSize, - timeUnit, + timeSize: 1, + timeUnit: 'm', aggType: 'avg', }, + { + metric: 'system.cpu.user.pct', + comparator: Comparator.GT, + threshold: [], + timeSize: 1, + timeUnit: 'm', + aggType: 'cardinality', + }, ]); }); }); diff --git a/x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx b/x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx index a04897d9c738d..2c76b3bb925ee 100644 --- a/x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx +++ b/x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx @@ -59,7 +59,7 @@ class WithKueryAutocompletionComponent extends React.Component< ) => { const { indexPattern } = this.props; const language = 'kuery'; - const hasQuerySuggestions = this.props.kibana.services.data.autocomplete.hasQuerySuggestions( + const hasQuerySuggestions = this.props.kibana.services.data?.autocomplete.hasQuerySuggestions( language ); From 550e476e9be2443b3d89e4300d3fab0ba016a03e Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Tue, 23 Jun 2020 13:03:36 -0500 Subject: [PATCH 10/13] Fix typecheck --- .../metric_threshold/components/expression.test.tsx | 4 ++-- .../metric_threshold/components/expression.tsx | 4 +++- .../inventory_view/hooks/use_waffle_options.test.ts | 10 +++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.test.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.test.tsx index f0602ccf15d44..fa535e28c0b77 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.test.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.test.tsx @@ -12,13 +12,13 @@ import { AlertsContextValue } from '../../../../../triggers_actions_ui/public/ap import { AlertContextMeta } from '../types'; import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer'; import React from 'react'; -import { Expressions, defaultExpression } from './expression'; +import { Expressions } from './expression'; import { act } from 'react-dom/test-utils'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { Comparator } from '../../../../server/lib/alerting/metric_threshold/types'; jest.mock('../../../containers/source/use_source_via_http', () => ({ - useSourceViaHttp: (any) => ({ + useSourceViaHttp: () => ({ source: { id: 'default' }, createDerivedIndexPattern: () => ({ fields: [], title: 'metricbeat-*' }), }), diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx index 77f6285c323c3..ea1d4e81b5f36 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx @@ -643,7 +643,9 @@ const previewOptions = [ }), }, ]; -const previewDOMOptions = previewOptions.map((o) => omit(o, 'shortText')); +const previewDOMOptions: Array<{ text: string; value: string }> = previewOptions.map((o) => + omit(o, 'shortText') +); const firedTimeLabel = i18n.translate('xpack.infra.metrics.alertFlyout.firedTime', { defaultMessage: 'time', diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.test.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.test.ts index 11d5b6f8e5a5d..579073e9500d0 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.test.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.test.ts @@ -18,15 +18,15 @@ jest.mock('react-router-dom', () => ({ // Jest can't access variables outside the scope of the mock factory function except to // reassign them, so we can't make these both part of the same object -let PREFILL_NODETYPE; -let PREFILL_METRIC; +let PREFILL_NODETYPE: WaffleOptionsState['nodeType'] | undefined; +let PREFILL_METRIC: WaffleOptionsState['metric'] | undefined; jest.mock('../../../../alerting/use_alert_prefill', () => ({ useAlertPrefillContext: () => ({ inventoryPrefill: { - setNodeType(nodeType: string) { + setNodeType(nodeType: WaffleOptionsState['nodeType']) { PREFILL_NODETYPE = nodeType; }, - setMetric(metric: { type: string }) { + setMetric(metric: WaffleOptionsState['metric']) { PREFILL_METRIC = metric; }, }, @@ -46,7 +46,7 @@ describe('useWaffleOptions', () => { const newOptions = { nodeType: 'pod', - metriic: { type: 'memory' }, + metric: { type: 'memory' }, } as WaffleOptionsState; act(() => { result.current.changeNodeType(newOptions.nodeType); From e5f73180b27efcd74a02220364a5655bc39a3ad8 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Tue, 23 Jun 2020 13:52:18 -0500 Subject: [PATCH 11/13] Fix bad merge --- x-pack/plugins/infra/public/pages/metrics/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index b395190683e49..495c3f1febb60 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -11,7 +11,6 @@ import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { EuiErrorBoundary, EuiFlexItem, EuiFlexGroup, EuiButtonEmpty } from '@elastic/eui'; import { DocumentTitle } from '../../components/document_title'; -import { HelpCenterContent } from '../../components/help_center_content'; import { RoutedTabs } from '../../components/navigation/routed_tabs'; import { ColumnarPage } from '../../components/page'; import { Header } from '../../components/header'; From e730aa95e44eeef46856503a90f22c9e7def6c70 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Tue, 23 Jun 2020 15:58:27 -0500 Subject: [PATCH 12/13] Fix bad merge and metrics explorer infinite loop --- .../use_metric_threshold_alert_prefill.ts | 11 ++-- .../infra/public/pages/metrics/index.tsx | 61 +++---------------- 2 files changed, 15 insertions(+), 57 deletions(-) diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metric_threshold_alert_prefill.ts b/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metric_threshold_alert_prefill.ts index a11a57b90e605..366d6aa7003e6 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metric_threshold_alert_prefill.ts +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/hooks/use_metric_threshold_alert_prefill.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { isEqual } from 'lodash'; import { useState } from 'react'; import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer'; @@ -14,18 +15,20 @@ interface MetricThresholdPrefillOptions { } export const useMetricThresholdAlertPrefill = () => { - const [{ groupBy, filterQuery, metrics }, setPrefillOptions] = useState< - MetricThresholdPrefillOptions - >({ + const [prefillOptionsState, setPrefillOptionsState] = useState({ groupBy: undefined, filterQuery: undefined, metrics: [], }); + const { groupBy, filterQuery, metrics } = prefillOptionsState; + return { groupBy, filterQuery, metrics, - setPrefillOptions, + setPrefillOptions(newState: MetricThresholdPrefillOptions) { + if (!isEqual(newState, prefillOptionsState)) setPrefillOptionsState(newState); + }, }; }; diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index 495c3f1febb60..fd30a10879441 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -11,6 +11,7 @@ import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { EuiErrorBoundary, EuiFlexItem, EuiFlexGroup, EuiButtonEmpty } from '@elastic/eui'; import { DocumentTitle } from '../../components/document_title'; +import { HelpCenterContent } from '../../components/help_center_content'; import { RoutedTabs } from '../../components/navigation/routed_tabs'; import { ColumnarPage } from '../../components/page'; import { Header } from '../../components/header'; @@ -55,6 +56,13 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => { })} /> + +
{ -
- - - - - - - - - - - - Date: Wed, 24 Jun 2020 11:59:56 -0500 Subject: [PATCH 13/13] Fix bad merge --- .../components/expression.tsx | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx index 77a5d28eb0742..f45474f284484 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx @@ -593,55 +593,10 @@ export const Expressions: React.FC = (props) => { ); }; -const previewOptions = [ - { - value: 'h', - text: i18n.translate('xpack.infra.metrics.alertFlyout.lastHourLabel', { - defaultMessage: 'Last hour', - }), - shortText: i18n.translate('xpack.infra.metrics.alertFlyout.hourLabel', { - defaultMessage: 'hour', - }), - }, - { - value: 'd', - text: i18n.translate('xpack.infra.metrics.alertFlyout.lastDayLabel', { - defaultMessage: 'Last day', - }), - shortText: i18n.translate('xpack.infra.metrics.alertFlyout.dayLabel', { - defaultMessage: 'day', - }), - }, - { - value: 'w', - text: i18n.translate('xpack.infra.metrics.alertFlyout.lastWeekLabel', { - defaultMessage: 'Last week', - }), - shortText: i18n.translate('xpack.infra.metrics.alertFlyout.weekLabel', { - defaultMessage: 'week', - }), - }, - { - value: 'M', - text: i18n.translate('xpack.infra.metrics.alertFlyout.lastMonthLabel', { - defaultMessage: 'Last month', - }), - shortText: i18n.translate('xpack.infra.metrics.alertFlyout.monthLabel', { - defaultMessage: 'month', - }), - }, -]; const previewDOMOptions: Array<{ text: string; value: string }> = previewOptions.map((o) => omit(o, 'shortText') ); -const firedTimeLabel = i18n.translate('xpack.infra.metrics.alertFlyout.firedTime', { - defaultMessage: 'time', -}); -const firedTimesLabel = i18n.translate('xpack.infra.metrics.alertFlyout.firedTimes', { - defaultMessage: 'times', -}); - // required for dynamic import // eslint-disable-next-line import/no-default-export export default Expressions;