From 4e96f3533218bba4b2b7117ec64f36c8df6303f7 Mon Sep 17 00:00:00 2001 From: Maryam Saeidi Date: Mon, 28 Nov 2022 15:20:49 +0100 Subject: [PATCH 1/8] Refactor ObservabilityAlertSearchBar and expose it via Observability plugin --- .../alert_search_bar.test.tsx | 93 ++++++++++++++----- .../alert_search_bar/alert_search_bar.tsx | 73 ++++++++------- .../components/alerts_status_filter.tsx | 5 +- .../use_alert_search_bar_state_container.tsx | 10 +- .../shared/alert_search_bar/types.ts | 14 +-- .../public/components/shared/index.tsx | 11 +++ x-pack/plugins/observability/public/index.ts | 1 + .../containers/alerts_page/alerts_page.tsx | 2 +- .../public/pages/rule_details/index.tsx | 4 +- .../sections/alerts_search_bar/types.ts | 4 +- 10 files changed, 142 insertions(+), 75 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx index bdf565a29cbdb..d0d42f99c0282 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx @@ -8,7 +8,7 @@ import { triggersActionsUiMock } from '@kbn/triggers-actions-ui-plugin/public/mocks'; import React from 'react'; import { act, waitFor } from '@testing-library/react'; -import { AlertSearchBarProps } from './types'; +import { ObservabilityAlertSearchBarProps } from './types'; import { ObservabilityAlertSearchBar } from './alert_search_bar'; import { observabilityAlertFeatureIds } from '../../../config'; import { useKibana } from '../../../utils/kibana_react'; @@ -18,7 +18,6 @@ import { render } from '../../../utils/test_helper'; const useKibanaMock = useKibana as jest.Mock; const getAlertsSearchBarMock = jest.fn(); const ALERT_SEARCH_BAR_DATA_TEST_SUBJ = 'alerts-search-bar'; -const ACTIVE_BUTTON_DATA_TEST_SUBJ = 'alert-status-filter-active-button'; jest.mock('../../../utils/kibana_react'); @@ -37,21 +36,21 @@ const mockKibana = () => { }; describe('ObservabilityAlertSearchBar', () => { - const renderComponent = (props: Partial = {}) => { - const alertSearchBarProps: AlertSearchBarProps = { + const renderComponent = (props: Partial = {}) => { + const observabilityAlertSearchBarProps: ObservabilityAlertSearchBarProps = { appName: 'testAppName', - rangeFrom: 'now-15m', - setRangeFrom: jest.fn(), - rangeTo: 'now', - setRangeTo: jest.fn(), kuery: '', - setKuery: jest.fn(), - status: 'active', - setStatus: jest.fn(), - setEsQuery: jest.fn(), + onRangeFromChange: jest.fn(), + onRangeToChange: jest.fn(), + onKueryChange: jest.fn(), + onStatusChange: jest.fn(), + onEsQueryChange: jest.fn(), + rangeTo: 'now', + rangeFrom: 'now-15m', + status: 'all', ...props, }; - return render(); + return render(); }; beforeAll(() => { @@ -88,21 +87,20 @@ describe('ObservabilityAlertSearchBar', () => { }); it('should filter active alerts', async () => { - const mockedSetEsQuery = jest.fn(); + const mockedOnEsQueryChange = jest.fn(); const mockedFrom = '2022-11-15T09:38:13.604Z'; const mockedTo = '2022-11-15T09:53:13.604Z'; - const { getByTestId } = renderComponent({ - setEsQuery: mockedSetEsQuery, - rangeFrom: mockedFrom, - rangeTo: mockedTo, - }); - await act(async () => { - const activeButton = getByTestId(ACTIVE_BUTTON_DATA_TEST_SUBJ); - activeButton.click(); + act(() => { + renderComponent({ + onEsQueryChange: mockedOnEsQueryChange, + rangeFrom: mockedFrom, + rangeTo: mockedTo, + status: 'active', + }); }); - expect(mockedSetEsQuery).toHaveBeenCalledWith({ + expect(mockedOnEsQueryChange).toHaveBeenCalledWith({ bool: { filter: [ { @@ -127,4 +125,53 @@ describe('ObservabilityAlertSearchBar', () => { }, }); }); + + it('should include defaultSearchQueries in es query', async () => { + const mockedOnEsQueryChange = jest.fn(); + const mockedFrom = '2022-11-15T09:38:13.604Z'; + const mockedTo = '2022-11-15T09:53:13.604Z'; + const defaultSearchQueries = [ + { + query: 'kibana.alert.rule.uuid: 413a9631-1a29-4344-a8b4-9a1dc23421ee', + language: 'kuery', + }, + ]; + + act(() => { + renderComponent({ + onEsQueryChange: mockedOnEsQueryChange, + rangeFrom: mockedFrom, + rangeTo: mockedTo, + defaultSearchQueries, + status: 'all', + }); + }); + + expect(mockedOnEsQueryChange).toHaveBeenCalledWith({ + bool: { + filter: [ + { + bool: { + minimum_should_match: 1, + should: [ + { match: { 'kibana.alert.rule.uuid': '413a9631-1a29-4344-a8b4-9a1dc23421ee' } }, + ], + }, + }, + { + range: { + '@timestamp': expect.objectContaining({ + format: 'strict_date_optional_time', + gte: mockedFrom, + lte: mockedTo, + }), + }, + }, + ], + must: [], + must_not: [], + should: [], + }, + }); + }); }); diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx index 2bcedac677fa9..925b16f6af4b9 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx @@ -15,7 +15,7 @@ import { observabilityAlertFeatureIds } from '../../../config'; import { ObservabilityAppServices } from '../../../application/types'; import { AlertsStatusFilter } from './components'; import { ALERT_STATUS_QUERY, DEFAULT_QUERIES, DEFAULT_QUERY_STRING } from './constants'; -import { AlertSearchBarProps } from './types'; +import { ObservabilityAlertSearchBarProps } from './types'; import { buildEsQuery } from '../../../utils/build_es_query'; import { AlertStatus } from '../../../../common/typings'; @@ -27,17 +27,17 @@ const getAlertStatusQuery = (status: string): Query[] => { export function ObservabilityAlertSearchBar({ appName, + defaultSearchQueries = DEFAULT_QUERIES, + onEsQueryChange, + onKueryChange, + onRangeFromChange, + onRangeToChange, + onStatusChange, + kuery, rangeFrom, - setRangeFrom, rangeTo, - setRangeTo, - kuery, - setKuery, status, - setStatus, - setEsQuery, - queries = DEFAULT_QUERIES, -}: AlertSearchBarProps) { +}: ObservabilityAlertSearchBarProps) { const { data: { query: { @@ -48,62 +48,66 @@ export function ObservabilityAlertSearchBar({ triggersActionsUi: { getAlertsSearchBar: AlertsSearchBar }, } = useKibana().services; - const onStatusChange = useCallback( + const onAlertStatusChange = useCallback( (alertStatus: AlertStatus) => { - setEsQuery( + onEsQueryChange( buildEsQuery( { to: rangeTo, from: rangeFrom, }, kuery, - [...getAlertStatusQuery(alertStatus), ...queries] + [...getAlertStatusQuery(alertStatus), ...defaultSearchQueries] ) ); }, - [kuery, queries, rangeFrom, rangeTo, setEsQuery] + [kuery, defaultSearchQueries, rangeFrom, rangeTo, onEsQueryChange] ); useEffect(() => { - onStatusChange(status); - }, [onStatusChange, status]); + onAlertStatusChange(status); + }, [onAlertStatusChange, status]); - const onSearchBarParamsChange = useCallback( + const onSearchBarParamsChange = useCallback< + (query: { + dateRange: { from: string; to: string; mode?: 'absolute' | 'relative' }; + query: string; + }) => void + >( ({ dateRange, query }) => { + console.log('query:', { dateRange, query }); try { // First try to create es query to make sure query is valid, then save it in state const esQuery = buildEsQuery( { - to: rangeTo, - from: rangeFrom, + to: dateRange.to, + from: dateRange.from, }, query, - [...getAlertStatusQuery(status), ...queries] + [...getAlertStatusQuery(status), ...defaultSearchQueries] ); - setKuery(query); + onKueryChange(query); timeFilterService.setTime(dateRange); - setRangeFrom(dateRange.from); - setRangeTo(dateRange.to); - setEsQuery(esQuery); + onRangeFromChange(dateRange.from); + onRangeToChange(dateRange.to); + onEsQueryChange(esQuery); } catch (error) { toasts.addError(error, { title: i18n.translate('xpack.observability.alerts.searchBar.invalidQueryTitle', { defaultMessage: 'Invalid query string', }), }); - setKuery(DEFAULT_QUERY_STRING); + onKueryChange(DEFAULT_QUERY_STRING); } }, [ + defaultSearchQueries, timeFilterService, - setRangeFrom, - setRangeTo, - setKuery, - setEsQuery, - rangeTo, - rangeFrom, + onRangeFromChange, + onRangeToChange, + onKueryChange, + onEsQueryChange, status, - queries, toasts, ] ); @@ -126,9 +130,7 @@ export function ObservabilityAlertSearchBar({ { - setStatus(id as AlertStatus); - }} + onChange={(id) => onStatusChange(id as AlertStatus)} /> @@ -136,3 +138,6 @@ export function ObservabilityAlertSearchBar({ ); } + +// eslint-disable-next-line import/no-default-export +export default ObservabilityAlertSearchBar; diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/components/alerts_status_filter.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/components/alerts_status_filter.tsx index fa1f362120713..bc2ed5a29844a 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/components/alerts_status_filter.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/components/alerts_status_filter.tsx @@ -6,6 +6,7 @@ */ import { EuiButtonGroup, EuiButtonGroupOptionProps } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import React from 'react'; import { ALL_ALERTS, ACTIVE_ALERTS, RECOVERED_ALERTS } from '../constants'; import { AlertStatusFilterProps } from '../types'; @@ -34,7 +35,9 @@ const options: EuiButtonGroupOptionProps[] = [ export function AlertsStatusFilter({ status, onChange }: AlertStatusFilterProps) { return ( void; - setRangeTo: (rangeTo: string) => void; - setKuery: (kuery: string) => void; - setStatus: (status: AlertStatus) => void; + onRangeFromChange: (rangeFrom: string) => void; + onRangeToChange: (rangeTo: string) => void; + onKueryChange: (kuery: string) => void; + onStatusChange: (status: AlertStatus) => void; } export interface CommonAlertSearchBarProps { appName: string; - setEsQuery: (query: { bool: BoolQuery }) => void; - queries?: Query[]; + onEsQueryChange: (query: { bool: BoolQuery }) => void; + defaultSearchQueries?: Query[]; } export interface AlertSearchBarWithUrlSyncProps extends CommonAlertSearchBarProps { urlStorageKey: string; } -export interface AlertSearchBarProps +export interface ObservabilityAlertSearchBarProps extends AlertSearchBarContainerState, AlertSearchBarStateTransitions, CommonAlertSearchBarProps {} diff --git a/x-pack/plugins/observability/public/components/shared/index.tsx b/x-pack/plugins/observability/public/components/shared/index.tsx index fab875ebaf078..5c3dbc083e285 100644 --- a/x-pack/plugins/observability/public/components/shared/index.tsx +++ b/x-pack/plugins/observability/public/components/shared/index.tsx @@ -8,6 +8,7 @@ import React, { lazy, Suspense } from 'react'; import { EuiLoadingSpinner } from '@elastic/eui'; import { LoadWhenInViewProps } from './load_when_in_view/load_when_in_view'; +import { ObservabilityAlertSearchBarProps } from './alert_search_bar/types'; import type { CoreVitalProps, HeaderMenuPortalProps } from './types'; import type { FieldValueSuggestionsProps, @@ -113,3 +114,13 @@ export function LoadWhenInView(props: LoadWhenInViewProps) { ); } + +const ObservabilityAlertSearchBarLazy = lazy(() => import('./alert_search_bar/alert_search_bar')); + +export function ObservabilityAlertSearchBar(props: ObservabilityAlertSearchBarProps) { + return ( + }> + + + ); +} diff --git a/x-pack/plugins/observability/public/index.ts b/x-pack/plugins/observability/public/index.ts index 37ee74157ede3..e00fd5184a56b 100644 --- a/x-pack/plugins/observability/public/index.ts +++ b/x-pack/plugins/observability/public/index.ts @@ -57,6 +57,7 @@ export { ExploratoryView, DatePicker, LoadWhenInView, + ObservabilityAlertSearchBar, } from './components/shared'; export type { LazyObservabilityPageTemplateProps } from './components/shared'; diff --git a/x-pack/plugins/observability/public/pages/alerts/containers/alerts_page/alerts_page.tsx b/x-pack/plugins/observability/public/pages/alerts/containers/alerts_page/alerts_page.tsx index f1f4e14baf337..e2a6915fd79b6 100644 --- a/x-pack/plugins/observability/public/pages/alerts/containers/alerts_page/alerts_page.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/containers/alerts_page/alerts_page.tsx @@ -136,7 +136,7 @@ export function AlertsPage() { diff --git a/x-pack/plugins/observability/public/pages/rule_details/index.tsx b/x-pack/plugins/observability/public/pages/rule_details/index.tsx index 12732939ad66c..0aea50d568a16 100644 --- a/x-pack/plugins/observability/public/pages/rule_details/index.tsx +++ b/x-pack/plugins/observability/public/pages/rule_details/index.tsx @@ -223,9 +223,9 @@ export function RuleDetailsPage() { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/types.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/types.ts index 86e3e60ef059e..e75dd56168687 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/types.ts @@ -15,8 +15,8 @@ export interface AlertsSearchBarProps { rangeFrom?: string; rangeTo?: string; query?: string; - onQueryChange: ({}: { + onQueryChange: (query: { dateRange: { from: string; to: string; mode?: 'absolute' | 'relative' }; - query?: string; + query: string; }) => void; } From b693b1112780ebf8206bb54d21bda0a149ed75b6 Mon Sep 17 00:00:00 2001 From: Maryam Saeidi Date: Tue, 29 Nov 2022 14:23:01 +0100 Subject: [PATCH 2/8] Implement ObservabilityAlertSearchBarKibanaProvider --- .../alert_search_bar.test.tsx | 31 ++++++------- .../alert_search_bar/alert_search_bar.tsx | 22 +++------- .../alert_search_bar_with_url_sync.tsx | 10 ++++- .../shared/alert_search_bar/services.tsx | 39 ++++++++++++++++ .../shared/alert_search_bar/types.ts | 44 ++++++++++++++----- x-pack/plugins/observability/public/index.ts | 2 + 6 files changed, 103 insertions(+), 45 deletions(-) create mode 100644 x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx index d0d42f99c0282..03c5011302a6d 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx @@ -5,33 +5,28 @@ * 2.0. */ -import { triggersActionsUiMock } from '@kbn/triggers-actions-ui-plugin/public/mocks'; import React from 'react'; import { act, waitFor } from '@testing-library/react'; +import { timefilterServiceMock } from '@kbn/data-plugin/public/query/timefilter/timefilter_service.mock'; +import { useServices } from './services'; import { ObservabilityAlertSearchBarProps } from './types'; import { ObservabilityAlertSearchBar } from './alert_search_bar'; import { observabilityAlertFeatureIds } from '../../../config'; -import { useKibana } from '../../../utils/kibana_react'; -import { kibanaStartMock } from '../../../utils/kibana_react.mock'; import { render } from '../../../utils/test_helper'; -const useKibanaMock = useKibana as jest.Mock; +const useServicesMock = useServices as jest.Mock; const getAlertsSearchBarMock = jest.fn(); const ALERT_SEARCH_BAR_DATA_TEST_SUBJ = 'alerts-search-bar'; -jest.mock('../../../utils/kibana_react'); - -const mockKibana = () => { - useKibanaMock.mockReturnValue({ - services: { - ...kibanaStartMock.startContract().services, - triggersActionsUi: { - ...triggersActionsUiMock.createStart(), - getAlertsSearchBar: getAlertsSearchBarMock.mockReturnValue( -
- ), - }, - }, +jest.mock('./services'); + +const mockServices = () => { + useServicesMock.mockReturnValue({ + timeFilterService: timefilterServiceMock, + AlertsSearchBar: getAlertsSearchBarMock.mockReturnValue( +
+ ), + errorToast: jest.fn(), }); }; @@ -54,7 +49,7 @@ describe('ObservabilityAlertSearchBar', () => { }; beforeAll(() => { - mockKibana(); + mockServices(); }); beforeEach(() => { diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx index 925b16f6af4b9..2fed1e27aff97 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx @@ -6,14 +6,13 @@ */ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - import React, { useCallback, useEffect } from 'react'; + import { i18n } from '@kbn/i18n'; import { Query } from '@kbn/es-query'; -import { useKibana } from '../../../utils/kibana_react'; -import { observabilityAlertFeatureIds } from '../../../config'; -import { ObservabilityAppServices } from '../../../application/types'; +import { useServices } from './services'; import { AlertsStatusFilter } from './components'; +import { observabilityAlertFeatureIds } from '../../../config'; import { ALERT_STATUS_QUERY, DEFAULT_QUERIES, DEFAULT_QUERY_STRING } from './constants'; import { ObservabilityAlertSearchBarProps } from './types'; import { buildEsQuery } from '../../../utils/build_es_query'; @@ -38,15 +37,7 @@ export function ObservabilityAlertSearchBar({ rangeTo, status, }: ObservabilityAlertSearchBarProps) { - const { - data: { - query: { - timefilter: { timefilter: timeFilterService }, - }, - }, - notifications: { toasts }, - triggersActionsUi: { getAlertsSearchBar: AlertsSearchBar }, - } = useKibana().services; + const { AlertsSearchBar, errorToast, timeFilterService } = useServices(); const onAlertStatusChange = useCallback( (alertStatus: AlertStatus) => { @@ -75,7 +66,6 @@ export function ObservabilityAlertSearchBar({ }) => void >( ({ dateRange, query }) => { - console.log('query:', { dateRange, query }); try { // First try to create es query to make sure query is valid, then save it in state const esQuery = buildEsQuery( @@ -92,7 +82,7 @@ export function ObservabilityAlertSearchBar({ onRangeToChange(dateRange.to); onEsQueryChange(esQuery); } catch (error) { - toasts.addError(error, { + errorToast(error, { title: i18n.translate('xpack.observability.alerts.searchBar.invalidQueryTitle', { defaultMessage: 'Invalid query string', }), @@ -108,7 +98,7 @@ export function ObservabilityAlertSearchBar({ onKueryChange, onEsQueryChange, status, - toasts, + errorToast, ] ); diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar_with_url_sync.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar_with_url_sync.tsx index 203d207ce9a10..4cb2afc6f6e4d 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar_with_url_sync.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar_with_url_sync.tsx @@ -12,13 +12,21 @@ import { useAlertSearchBarStateContainer, } from './containers'; import { ObservabilityAlertSearchBar } from './alert_search_bar'; +import { ObservabilityAlertSearchBarKibanaProvider } from './services'; import { AlertSearchBarWithUrlSyncProps } from './types'; +import { useKibana } from '../../../utils/kibana_react'; +import { ObservabilityAppServices } from '../../../application/types'; function AlertSearchbarWithUrlSync(props: AlertSearchBarWithUrlSyncProps) { const { urlStorageKey, ...searchBarProps } = props; const stateProps = useAlertSearchBarStateContainer(urlStorageKey); + const services = useKibana().services; - return ; + return ( + + + + ); } export function ObservabilityAlertSearchbarWithUrlSync(props: AlertSearchBarWithUrlSyncProps) { diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx new file mode 100644 index 0000000000000..4abccf777f1ad --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx @@ -0,0 +1,39 @@ +/* + * 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 React, { FC, useContext } from 'react'; +import { ObservabilityAlertSearchBarKibanaDependencies, Services } from './types'; + +const ObservabilityAlertSearchBarContext = React.createContext(null); + +export const ObservabilityAlertSearchBarKibanaProvider: FC< + ObservabilityAlertSearchBarKibanaDependencies +> = ({ children, ...services }) => { + return ( + + {children} + + ); +}; + +export function useServices() { + const context = useContext(ObservabilityAlertSearchBarContext); + + if (!context) { + throw new Error( + 'ObservabilityAlertSearchBarContext is missing. Ensure your component or React root is wrapped with ObservabilityAlertSearchBarProvider.' + ); + } + + return context; +} diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/types.ts b/x-pack/plugins/observability/public/components/shared/alert_search_bar/types.ts index 591580d229d24..ccfc0895f14b1 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/types.ts +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/types.ts @@ -5,6 +5,10 @@ * 2.0. */ +import { ReactElement } from 'react'; +import { ErrorToastOptions, Toast, ToastsStart } from '@kbn/core-notifications-browser'; +import { TimefilterContract } from '@kbn/data-plugin/public'; +import { AlertsSearchBarProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_search_bar'; import { BoolQuery, Query } from '@kbn/es-query'; import { AlertStatus } from '../../../../common/typings'; @@ -13,6 +17,35 @@ export interface AlertStatusFilterProps { onChange: (id: string, value: string) => void; } +export interface AlertSearchBarWithUrlSyncProps extends CommonAlertSearchBarProps { + urlStorageKey: string; +} + +export interface KibanaDependencies { + data: { + query: { + timefilter: { timefilter: TimefilterContract }; + }; + }; + notifications: { toasts: ToastsStart }; + triggersActionsUi: { + getAlertsSearchBar: (props: AlertsSearchBarProps) => ReactElement; + }; +} + +export type ObservabilityAlertSearchBarKibanaDependencies = KibanaDependencies; + +export interface Services { + timeFilterService: TimefilterContract; + AlertsSearchBar: (props: AlertsSearchBarProps) => ReactElement; + errorToast: (error: Error, options: ErrorToastOptions) => Toast; +} + +export interface ObservabilityAlertSearchBarProps + extends AlertSearchBarContainerState, + AlertSearchBarStateTransitions, + CommonAlertSearchBarProps {} + interface AlertSearchBarContainerState { rangeFrom: string; rangeTo: string; @@ -27,17 +60,8 @@ interface AlertSearchBarStateTransitions { onStatusChange: (status: AlertStatus) => void; } -export interface CommonAlertSearchBarProps { +interface CommonAlertSearchBarProps { appName: string; onEsQueryChange: (query: { bool: BoolQuery }) => void; defaultSearchQueries?: Query[]; } - -export interface AlertSearchBarWithUrlSyncProps extends CommonAlertSearchBarProps { - urlStorageKey: string; -} - -export interface ObservabilityAlertSearchBarProps - extends AlertSearchBarContainerState, - AlertSearchBarStateTransitions, - CommonAlertSearchBarProps {} diff --git a/x-pack/plugins/observability/public/index.ts b/x-pack/plugins/observability/public/index.ts index e00fd5184a56b..4cfdd8910e716 100644 --- a/x-pack/plugins/observability/public/index.ts +++ b/x-pack/plugins/observability/public/index.ts @@ -47,6 +47,8 @@ export * from './components/shared/action_menu'; export type { UXMetrics } from './components/shared/core_web_vitals'; export { DatePickerContextProvider } from './context/date_picker_context'; +export { ObservabilityAlertSearchBarKibanaProvider } from './components/shared/alert_search_bar/services'; + export { getCoreVitalsComponent, HeaderMenuPortal, From f937182497498c2f2d7456097cb9883168c58d3b Mon Sep 17 00:00:00 2001 From: Maryam Saeidi Date: Tue, 29 Nov 2022 14:32:15 +0100 Subject: [PATCH 3/8] Rename ObservabilityAlertSearchBarKibanaProvider to ObservabilityAlertSearchBarProvider --- .../components/shared/alert_search_bar/services.tsx | 9 +++++---- .../public/components/shared/alert_search_bar/types.ts | 2 +- x-pack/plugins/observability/public/index.ts | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx index 4abccf777f1ad..8f142d0b23558 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx @@ -6,13 +6,14 @@ */ import React, { FC, useContext } from 'react'; -import { ObservabilityAlertSearchBarKibanaDependencies, Services } from './types'; +import { ObservabilityAlertSearchBarDependencies, Services } from './types'; const ObservabilityAlertSearchBarContext = React.createContext(null); -export const ObservabilityAlertSearchBarKibanaProvider: FC< - ObservabilityAlertSearchBarKibanaDependencies -> = ({ children, ...services }) => { +export const ObservabilityAlertSearchBarProvider: FC = ({ + children, + ...services +}) => { return ( Date: Tue, 29 Nov 2022 15:05:41 +0100 Subject: [PATCH 4/8] Fix import --- .../alert_search_bar/alert_search_bar_with_url_sync.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar_with_url_sync.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar_with_url_sync.tsx index 4cb2afc6f6e4d..04289e3f23e72 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar_with_url_sync.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar_with_url_sync.tsx @@ -12,7 +12,7 @@ import { useAlertSearchBarStateContainer, } from './containers'; import { ObservabilityAlertSearchBar } from './alert_search_bar'; -import { ObservabilityAlertSearchBarKibanaProvider } from './services'; +import { ObservabilityAlertSearchBarProvider } from './services'; import { AlertSearchBarWithUrlSyncProps } from './types'; import { useKibana } from '../../../utils/kibana_react'; import { ObservabilityAppServices } from '../../../application/types'; @@ -23,9 +23,9 @@ function AlertSearchbarWithUrlSync(props: AlertSearchBarWithUrlSyncProps) { const services = useKibana().services; return ( - + - + ); } From 7275cc6719139b1df27510b710e0b0c1c99286fd Mon Sep 17 00:00:00 2001 From: Maryam Saeidi Date: Wed, 30 Nov 2022 13:41:36 +0100 Subject: [PATCH 5/8] Fix toast undefined error and related functional test --- .../alert_search_bar.test.tsx | 2 +- .../alert_search_bar/alert_search_bar.tsx | 7 ++--- .../alert_search_bar_with_url_sync.tsx | 9 +++++-- .../shared/alert_search_bar/services.tsx | 26 ++++++++++++------- .../shared/alert_search_bar/types.ts | 10 +++---- .../observability/public/hooks/use_toast.ts | 11 ++++++++ 6 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 x-pack/plugins/observability/public/hooks/use_toast.ts diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx index 03c5011302a6d..8e0c792244cc9 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx @@ -26,7 +26,7 @@ const mockServices = () => { AlertsSearchBar: getAlertsSearchBarMock.mockReturnValue(
), - errorToast: jest.fn(), + useToasts: jest.fn(), }); }; diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx index 2fed1e27aff97..c4e463f41fab7 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx @@ -37,7 +37,8 @@ export function ObservabilityAlertSearchBar({ rangeTo, status, }: ObservabilityAlertSearchBarProps) { - const { AlertsSearchBar, errorToast, timeFilterService } = useServices(); + const { AlertsSearchBar, timeFilterService, useToasts } = useServices(); + const toasts = useToasts(); const onAlertStatusChange = useCallback( (alertStatus: AlertStatus) => { @@ -82,7 +83,7 @@ export function ObservabilityAlertSearchBar({ onRangeToChange(dateRange.to); onEsQueryChange(esQuery); } catch (error) { - errorToast(error, { + toasts.addError(error, { title: i18n.translate('xpack.observability.alerts.searchBar.invalidQueryTitle', { defaultMessage: 'Invalid query string', }), @@ -98,7 +99,7 @@ export function ObservabilityAlertSearchBar({ onKueryChange, onEsQueryChange, status, - errorToast, + toasts, ] ); diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar_with_url_sync.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar_with_url_sync.tsx index 04289e3f23e72..405382f49b47f 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar_with_url_sync.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar_with_url_sync.tsx @@ -16,14 +16,19 @@ import { ObservabilityAlertSearchBarProvider } from './services'; import { AlertSearchBarWithUrlSyncProps } from './types'; import { useKibana } from '../../../utils/kibana_react'; import { ObservabilityAppServices } from '../../../application/types'; +import { useToasts } from '../../../hooks/use_toast'; function AlertSearchbarWithUrlSync(props: AlertSearchBarWithUrlSyncProps) { const { urlStorageKey, ...searchBarProps } = props; const stateProps = useAlertSearchBarStateContainer(urlStorageKey); - const services = useKibana().services; + const { data, triggersActionsUi } = useKibana().services; return ( - + ); diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx index 8f142d0b23558..89edf5cb9dfa1 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx @@ -5,23 +5,31 @@ * 2.0. */ -import React, { FC, useContext } from 'react'; +import React, { FC, useContext, useMemo } from 'react'; import { ObservabilityAlertSearchBarDependencies, Services } from './types'; const ObservabilityAlertSearchBarContext = React.createContext(null); export const ObservabilityAlertSearchBarProvider: FC = ({ children, - ...services + data: { + query: { + timefilter: { timefilter: timeFilterService }, + }, + }, + useToasts, + triggersActionsUi: { getAlertsSearchBar: AlertsSearchBar }, }) => { + const services = useMemo( + () => ({ + timeFilterService, + useToasts, + AlertsSearchBar, + }), + [timeFilterService, useToasts, AlertsSearchBar] + ); return ( - + {children} ); diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/types.ts b/x-pack/plugins/observability/public/components/shared/alert_search_bar/types.ts index ad9e208bd517f..f7ef793d6c47a 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/types.ts +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/types.ts @@ -6,7 +6,7 @@ */ import { ReactElement } from 'react'; -import { ErrorToastOptions, Toast, ToastsStart } from '@kbn/core-notifications-browser'; +import { ToastsStart } from '@kbn/core-notifications-browser'; import { TimefilterContract } from '@kbn/data-plugin/public'; import { AlertsSearchBarProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_search_bar'; import { BoolQuery, Query } from '@kbn/es-query'; @@ -21,24 +21,24 @@ export interface AlertSearchBarWithUrlSyncProps extends CommonAlertSearchBarProp urlStorageKey: string; } -export interface KibanaDependencies { +export interface Dependencies { data: { query: { timefilter: { timefilter: TimefilterContract }; }; }; - notifications: { toasts: ToastsStart }; triggersActionsUi: { getAlertsSearchBar: (props: AlertsSearchBarProps) => ReactElement; }; + useToasts: () => ToastsStart; } -export type ObservabilityAlertSearchBarDependencies = KibanaDependencies; +export type ObservabilityAlertSearchBarDependencies = Dependencies; export interface Services { timeFilterService: TimefilterContract; AlertsSearchBar: (props: AlertsSearchBarProps) => ReactElement; - errorToast: (error: Error, options: ErrorToastOptions) => Toast; + useToasts: () => ToastsStart; } export interface ObservabilityAlertSearchBarProps diff --git a/x-pack/plugins/observability/public/hooks/use_toast.ts b/x-pack/plugins/observability/public/hooks/use_toast.ts new file mode 100644 index 0000000000000..380d57bb28b63 --- /dev/null +++ b/x-pack/plugins/observability/public/hooks/use_toast.ts @@ -0,0 +1,11 @@ +/* + * 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 { useKibana } from '@kbn/kibana-react-plugin/public'; +import { ObservabilityAppServices } from '../application/types'; + +export const useToasts = () => useKibana().services.notifications.toasts; From a86b076dc5fb814d72e9690c6ec435716daf130c Mon Sep 17 00:00:00 2001 From: Maryam Saeidi Date: Thu, 1 Dec 2022 17:13:20 +0100 Subject: [PATCH 6/8] Remove unnecessary act --- .../alert_search_bar.test.tsx | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx index 8e0c792244cc9..d12bee2f87e47 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { act, waitFor } from '@testing-library/react'; +import { waitFor } from '@testing-library/react'; import { timefilterServiceMock } from '@kbn/data-plugin/public/query/timefilter/timefilter_service.mock'; import { useServices } from './services'; import { ObservabilityAlertSearchBarProps } from './types'; @@ -65,9 +65,7 @@ describe('ObservabilityAlertSearchBar', () => { }); it('should call alert search bar with correct props', () => { - act(() => { - renderComponent(); - }); + renderComponent(); expect(getAlertsSearchBarMock).toHaveBeenCalledWith( expect.objectContaining({ @@ -86,13 +84,11 @@ describe('ObservabilityAlertSearchBar', () => { const mockedFrom = '2022-11-15T09:38:13.604Z'; const mockedTo = '2022-11-15T09:53:13.604Z'; - act(() => { - renderComponent({ - onEsQueryChange: mockedOnEsQueryChange, - rangeFrom: mockedFrom, - rangeTo: mockedTo, - status: 'active', - }); + renderComponent({ + onEsQueryChange: mockedOnEsQueryChange, + rangeFrom: mockedFrom, + rangeTo: mockedTo, + status: 'active', }); expect(mockedOnEsQueryChange).toHaveBeenCalledWith({ @@ -132,14 +128,12 @@ describe('ObservabilityAlertSearchBar', () => { }, ]; - act(() => { - renderComponent({ - onEsQueryChange: mockedOnEsQueryChange, - rangeFrom: mockedFrom, - rangeTo: mockedTo, - defaultSearchQueries, - status: 'all', - }); + renderComponent({ + onEsQueryChange: mockedOnEsQueryChange, + rangeFrom: mockedFrom, + rangeTo: mockedTo, + defaultSearchQueries, + status: 'all', }); expect(mockedOnEsQueryChange).toHaveBeenCalledWith({ From 66d173dcb7f774a4aa63f11a96b209ed50abcd30 Mon Sep 17 00:00:00 2001 From: Maryam Saeidi Date: Thu, 1 Dec 2022 17:16:55 +0100 Subject: [PATCH 7/8] Remove useMemo --- .../shared/alert_search_bar/services.tsx | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx index 89edf5cb9dfa1..186178d6747d2 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/services.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, useContext, useMemo } from 'react'; +import React, { FC, useContext } from 'react'; import { ObservabilityAlertSearchBarDependencies, Services } from './types'; const ObservabilityAlertSearchBarContext = React.createContext(null); @@ -20,14 +20,11 @@ export const ObservabilityAlertSearchBarProvider: FC { - const services = useMemo( - () => ({ - timeFilterService, - useToasts, - AlertsSearchBar, - }), - [timeFilterService, useToasts, AlertsSearchBar] - ); + const services = { + timeFilterService, + useToasts, + AlertsSearchBar, + }; return ( {children} From 03598ccdcbd6a688860710a1dc10cc648ee5c0cf Mon Sep 17 00:00:00 2001 From: Maryam Saeidi Date: Fri, 2 Dec 2022 16:31:21 +0100 Subject: [PATCH 8/8] Refactoring based on comments --- .../shared/alert_search_bar/alert_search_bar.tsx | 5 +---- .../alert_search_bar/components/alerts_status_filter.tsx | 3 ++- .../public/components/shared/alert_search_bar/types.ts | 9 ++++----- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx index c4e463f41fab7..3d8de61482694 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/alert_search_bar.tsx @@ -119,10 +119,7 @@ export function ObservabilityAlertSearchBar({ - onStatusChange(id as AlertStatus)} - /> + diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/components/alerts_status_filter.tsx b/x-pack/plugins/observability/public/components/shared/alert_search_bar/components/alerts_status_filter.tsx index bc2ed5a29844a..5dbbfd06d744a 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/components/alerts_status_filter.tsx +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/components/alerts_status_filter.tsx @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { ALL_ALERTS, ACTIVE_ALERTS, RECOVERED_ALERTS } from '../constants'; import { AlertStatusFilterProps } from '../types'; +import { AlertStatus } from '../../../../../common/typings'; const options: EuiButtonGroupOptionProps[] = [ { @@ -41,7 +42,7 @@ export function AlertsStatusFilter({ status, onChange }: AlertStatusFilterProps) color="primary" options={options} idSelected={status} - onChange={onChange} + onChange={(id) => onChange(id as AlertStatus)} /> ); } diff --git a/x-pack/plugins/observability/public/components/shared/alert_search_bar/types.ts b/x-pack/plugins/observability/public/components/shared/alert_search_bar/types.ts index f7ef793d6c47a..be3ccce505505 100644 --- a/x-pack/plugins/observability/public/components/shared/alert_search_bar/types.ts +++ b/x-pack/plugins/observability/public/components/shared/alert_search_bar/types.ts @@ -14,7 +14,7 @@ import { AlertStatus } from '../../../../common/typings'; export interface AlertStatusFilterProps { status: AlertStatus; - onChange: (id: string, value: string) => void; + onChange: (id: AlertStatus) => void; } export interface AlertSearchBarWithUrlSyncProps extends CommonAlertSearchBarProps { @@ -41,10 +41,9 @@ export interface Services { useToasts: () => ToastsStart; } -export interface ObservabilityAlertSearchBarProps - extends AlertSearchBarContainerState, - AlertSearchBarStateTransitions, - CommonAlertSearchBarProps {} +export type ObservabilityAlertSearchBarProps = AlertSearchBarContainerState & + AlertSearchBarStateTransitions & + CommonAlertSearchBarProps; interface AlertSearchBarContainerState { rangeFrom: string;