mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Actionable Observability] Expose ObservabilityAlertSearchBar from Observability plugin (#146401)
Resolves #146286 ## 📝 Summary In this PR, I exposed ObservabilityAlertSearchBar from the Observability plugin to be used in other plugins such as APM. I've added `ObservabilityAlertSearchBarProvider` in order for other plugins to provide Kibana dependencies to the shared component. ## 🧪 How to test For testing the implementation, I imported this component in the APM plugin and used it in the alerts tab, you can do the same locally by following these steps: 1. Import `ObservabilityAlertSearchBar` in [APM](https://github.com/elastic/kibana/blob/main/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx) and define related hook: ``` import { ObservabilityAlertSearchBar, ObservabilityAlertSearchBarProvider, } from '@kbn/observability-plugin/public'; export const useToasts = () => useKibana<ApmPluginStartDeps>().services.notifications!.toasts; ``` 2. Replace [AlertsTableStatusFilter](https://github.com/elastic/kibana/blob/main/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx#L74) with the `ObservabilityAlertSearchBar` component: ``` <ObservabilityAlertSearchBarProvider {...services} useToasts={useToasts} > <ObservabilityAlertSearchBar appName={'apmApp'} kuery={''} onRangeFromChange={(input) => console.log(input)} onRangeToChange={(input) => console.log(input)} onKueryChange={(input) => console.log(input)} onStatusChange={(input) => console.log(input)} onEsQueryChange={(input) => console.log(input)} rangeTo={'now'} rangeFrom={'now-15m'} status={'all'} /> </ObservabilityAlertSearchBarProvider> ``` You should see the new search bar in APM alerts tab: 
This commit is contained in:
parent
98412f795e
commit
9b828e3c4c
13 changed files with 264 additions and 125 deletions
|
@ -5,57 +5,51 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
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 { 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';
|
||||
const ACTIVE_BUTTON_DATA_TEST_SUBJ = 'alert-status-filter-active-button';
|
||||
|
||||
jest.mock('../../../utils/kibana_react');
|
||||
jest.mock('./services');
|
||||
|
||||
const mockKibana = () => {
|
||||
useKibanaMock.mockReturnValue({
|
||||
services: {
|
||||
...kibanaStartMock.startContract().services,
|
||||
triggersActionsUi: {
|
||||
...triggersActionsUiMock.createStart(),
|
||||
getAlertsSearchBar: getAlertsSearchBarMock.mockReturnValue(
|
||||
<div data-test-subj={ALERT_SEARCH_BAR_DATA_TEST_SUBJ} />
|
||||
),
|
||||
},
|
||||
},
|
||||
const mockServices = () => {
|
||||
useServicesMock.mockReturnValue({
|
||||
timeFilterService: timefilterServiceMock,
|
||||
AlertsSearchBar: getAlertsSearchBarMock.mockReturnValue(
|
||||
<div data-test-subj={ALERT_SEARCH_BAR_DATA_TEST_SUBJ} />
|
||||
),
|
||||
useToasts: jest.fn(),
|
||||
});
|
||||
};
|
||||
|
||||
describe('ObservabilityAlertSearchBar', () => {
|
||||
const renderComponent = (props: Partial<AlertSearchBarProps> = {}) => {
|
||||
const alertSearchBarProps: AlertSearchBarProps = {
|
||||
const renderComponent = (props: Partial<ObservabilityAlertSearchBarProps> = {}) => {
|
||||
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(<ObservabilityAlertSearchBar {...alertSearchBarProps} />);
|
||||
return render(<ObservabilityAlertSearchBar {...observabilityAlertSearchBarProps} />);
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
mockKibana();
|
||||
mockServices();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -71,9 +65,7 @@ describe('ObservabilityAlertSearchBar', () => {
|
|||
});
|
||||
|
||||
it('should call alert search bar with correct props', () => {
|
||||
act(() => {
|
||||
renderComponent();
|
||||
});
|
||||
renderComponent();
|
||||
|
||||
expect(getAlertsSearchBarMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
|
@ -88,21 +80,18 @@ 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,
|
||||
|
||||
renderComponent({
|
||||
onEsQueryChange: mockedOnEsQueryChange,
|
||||
rangeFrom: mockedFrom,
|
||||
rangeTo: mockedTo,
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
const activeButton = getByTestId(ACTIVE_BUTTON_DATA_TEST_SUBJ);
|
||||
activeButton.click();
|
||||
});
|
||||
|
||||
expect(mockedSetEsQuery).toHaveBeenCalledWith({
|
||||
expect(mockedOnEsQueryChange).toHaveBeenCalledWith({
|
||||
bool: {
|
||||
filter: [
|
||||
{
|
||||
|
@ -127,4 +116,51 @@ 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',
|
||||
},
|
||||
];
|
||||
|
||||
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: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,16 +6,15 @@
|
|||
*/
|
||||
|
||||
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 { AlertSearchBarProps } from './types';
|
||||
import { ObservabilityAlertSearchBarProps } from './types';
|
||||
import { buildEsQuery } from '../../../utils/build_es_query';
|
||||
import { AlertStatus } from '../../../../common/typings';
|
||||
|
||||
|
@ -27,83 +26,79 @@ const getAlertStatusQuery = (status: string): Query[] => {
|
|||
|
||||
export function ObservabilityAlertSearchBar({
|
||||
appName,
|
||||
rangeFrom,
|
||||
setRangeFrom,
|
||||
rangeTo,
|
||||
setRangeTo,
|
||||
defaultSearchQueries = DEFAULT_QUERIES,
|
||||
onEsQueryChange,
|
||||
onKueryChange,
|
||||
onRangeFromChange,
|
||||
onRangeToChange,
|
||||
onStatusChange,
|
||||
kuery,
|
||||
setKuery,
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
status,
|
||||
setStatus,
|
||||
setEsQuery,
|
||||
queries = DEFAULT_QUERIES,
|
||||
}: AlertSearchBarProps) {
|
||||
const {
|
||||
data: {
|
||||
query: {
|
||||
timefilter: { timefilter: timeFilterService },
|
||||
},
|
||||
},
|
||||
notifications: { toasts },
|
||||
triggersActionsUi: { getAlertsSearchBar: AlertsSearchBar },
|
||||
} = useKibana<ObservabilityAppServices>().services;
|
||||
}: ObservabilityAlertSearchBarProps) {
|
||||
const { AlertsSearchBar, timeFilterService, useToasts } = useServices();
|
||||
const toasts = useToasts();
|
||||
|
||||
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 }) => {
|
||||
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,
|
||||
]
|
||||
);
|
||||
|
@ -124,15 +119,13 @@ export function ObservabilityAlertSearchBar({
|
|||
<EuiFlexItem>
|
||||
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<AlertsStatusFilter
|
||||
status={status}
|
||||
onChange={(id) => {
|
||||
setStatus(id as AlertStatus);
|
||||
}}
|
||||
/>
|
||||
<AlertsStatusFilter status={status} onChange={onStatusChange} />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default ObservabilityAlertSearchBar;
|
||||
|
|
|
@ -12,13 +12,26 @@ import {
|
|||
useAlertSearchBarStateContainer,
|
||||
} from './containers';
|
||||
import { ObservabilityAlertSearchBar } from './alert_search_bar';
|
||||
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 { data, triggersActionsUi } = useKibana<ObservabilityAppServices>().services;
|
||||
|
||||
return <ObservabilityAlertSearchBar {...stateProps} {...searchBarProps} />;
|
||||
return (
|
||||
<ObservabilityAlertSearchBarProvider
|
||||
data={data}
|
||||
triggersActionsUi={triggersActionsUi}
|
||||
useToasts={useToasts}
|
||||
>
|
||||
<ObservabilityAlertSearchBar {...stateProps} {...searchBarProps} />
|
||||
</ObservabilityAlertSearchBarProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export function ObservabilityAlertSearchbarWithUrlSync(props: AlertSearchBarWithUrlSyncProps) {
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
*/
|
||||
|
||||
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';
|
||||
import { AlertStatus } from '../../../../../common/typings';
|
||||
|
||||
const options: EuiButtonGroupOptionProps[] = [
|
||||
{
|
||||
|
@ -34,11 +36,13 @@ const options: EuiButtonGroupOptionProps[] = [
|
|||
export function AlertsStatusFilter({ status, onChange }: AlertStatusFilterProps) {
|
||||
return (
|
||||
<EuiButtonGroup
|
||||
legend="Filter by"
|
||||
legend={i18n.translate('xpack.observability.alerts.alertStatusFilter.legend', {
|
||||
defaultMessage: 'Filter by',
|
||||
})}
|
||||
color="primary"
|
||||
options={options}
|
||||
idSelected={status}
|
||||
onChange={onChange}
|
||||
onChange={(id) => onChange(id as AlertStatus)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -52,14 +52,14 @@ export function useAlertSearchBarStateContainer(urlStorageKey: string) {
|
|||
);
|
||||
|
||||
return {
|
||||
rangeFrom,
|
||||
setRangeFrom,
|
||||
rangeTo,
|
||||
setRangeTo,
|
||||
kuery,
|
||||
setKuery,
|
||||
onKueryChange: setKuery,
|
||||
onRangeFromChange: setRangeFrom,
|
||||
onRangeToChange: setRangeTo,
|
||||
onStatusChange: setStatus,
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
status,
|
||||
setStatus,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 { ObservabilityAlertSearchBarDependencies, Services } from './types';
|
||||
|
||||
const ObservabilityAlertSearchBarContext = React.createContext<Services | null>(null);
|
||||
|
||||
export const ObservabilityAlertSearchBarProvider: FC<ObservabilityAlertSearchBarDependencies> = ({
|
||||
children,
|
||||
data: {
|
||||
query: {
|
||||
timefilter: { timefilter: timeFilterService },
|
||||
},
|
||||
},
|
||||
useToasts,
|
||||
triggersActionsUi: { getAlertsSearchBar: AlertsSearchBar },
|
||||
}) => {
|
||||
const services = {
|
||||
timeFilterService,
|
||||
useToasts,
|
||||
AlertsSearchBar,
|
||||
};
|
||||
return (
|
||||
<ObservabilityAlertSearchBarContext.Provider value={services}>
|
||||
{children}
|
||||
</ObservabilityAlertSearchBarContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
|
@ -5,14 +5,46 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ReactElement } from 'react';
|
||||
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';
|
||||
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 {
|
||||
urlStorageKey: string;
|
||||
}
|
||||
|
||||
export interface Dependencies {
|
||||
data: {
|
||||
query: {
|
||||
timefilter: { timefilter: TimefilterContract };
|
||||
};
|
||||
};
|
||||
triggersActionsUi: {
|
||||
getAlertsSearchBar: (props: AlertsSearchBarProps) => ReactElement<AlertsSearchBarProps>;
|
||||
};
|
||||
useToasts: () => ToastsStart;
|
||||
}
|
||||
|
||||
export type ObservabilityAlertSearchBarDependencies = Dependencies;
|
||||
|
||||
export interface Services {
|
||||
timeFilterService: TimefilterContract;
|
||||
AlertsSearchBar: (props: AlertsSearchBarProps) => ReactElement<AlertsSearchBarProps>;
|
||||
useToasts: () => ToastsStart;
|
||||
}
|
||||
|
||||
export type ObservabilityAlertSearchBarProps = AlertSearchBarContainerState &
|
||||
AlertSearchBarStateTransitions &
|
||||
CommonAlertSearchBarProps;
|
||||
|
||||
interface AlertSearchBarContainerState {
|
||||
rangeFrom: string;
|
||||
rangeTo: string;
|
||||
|
@ -21,23 +53,14 @@ interface AlertSearchBarContainerState {
|
|||
}
|
||||
|
||||
interface AlertSearchBarStateTransitions {
|
||||
setRangeFrom: (rangeFrom: string) => 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 {
|
||||
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
|
||||
extends AlertSearchBarContainerState,
|
||||
AlertSearchBarStateTransitions,
|
||||
CommonAlertSearchBarProps {}
|
||||
|
|
|
@ -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) {
|
|||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
const ObservabilityAlertSearchBarLazy = lazy(() => import('./alert_search_bar/alert_search_bar'));
|
||||
|
||||
export function ObservabilityAlertSearchBar(props: ObservabilityAlertSearchBarProps) {
|
||||
return (
|
||||
<Suspense fallback={<EuiLoadingSpinner />}>
|
||||
<ObservabilityAlertSearchBarLazy {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
|
11
x-pack/plugins/observability/public/hooks/use_toast.ts
Normal file
11
x-pack/plugins/observability/public/hooks/use_toast.ts
Normal file
|
@ -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<ObservabilityAppServices>().services.notifications.toasts;
|
|
@ -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 { ObservabilityAlertSearchBarProvider } from './components/shared/alert_search_bar/services';
|
||||
|
||||
export {
|
||||
getCoreVitalsComponent,
|
||||
HeaderMenuPortal,
|
||||
|
@ -57,6 +59,7 @@ export {
|
|||
ExploratoryView,
|
||||
DatePicker,
|
||||
LoadWhenInView,
|
||||
ObservabilityAlertSearchBar,
|
||||
} from './components/shared';
|
||||
|
||||
export type { LazyObservabilityPageTemplateProps } from './components/shared';
|
||||
|
|
|
@ -136,7 +136,7 @@ export function AlertsPage() {
|
|||
<EuiFlexItem>
|
||||
<ObservabilityAlertSearchbarWithUrlSync
|
||||
appName={ALERTS_SEARCH_BAR_ID}
|
||||
setEsQuery={setEsQuery}
|
||||
onEsQueryChange={setEsQuery}
|
||||
urlStorageKey={URL_STORAGE_KEY}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
|
|
|
@ -223,9 +223,9 @@ export function RuleDetailsPage() {
|
|||
<EuiSpacer size="m" />
|
||||
<ObservabilityAlertSearchbarWithUrlSync
|
||||
appName={RULE_DETAILS_ALERTS_SEARCH_BAR_ID}
|
||||
setEsQuery={setEsQuery}
|
||||
onEsQueryChange={setEsQuery}
|
||||
urlStorageKey={URL_STORAGE_KEY}
|
||||
queries={ruleQuery.current}
|
||||
defaultSearchQueries={ruleQuery.current}
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFlexGroup style={{ minHeight: 450 }} direction={'column'}>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue