diff --git a/packages/kbn-alerts-ui-shared/src/alerts_search_bar/index.test.tsx b/packages/kbn-alerts-ui-shared/src/alerts_search_bar/index.test.tsx
new file mode 100644
index 00000000000000..7e11a4ee8759a0
--- /dev/null
+++ b/packages/kbn-alerts-ui-shared/src/alerts_search_bar/index.test.tsx
@@ -0,0 +1,128 @@
+/*
+ * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
+import { httpServiceMock, notificationServiceMock } from '@kbn/core/public/mocks';
+import { Filter } from '@kbn/es-query';
+import { useLoadRuleTypesQuery, useAlertsDataView, useRuleAADFields } from '../common/hooks';
+import { AlertsSearchBar } from '.';
+
+jest.mock('../common/hooks/use_load_rule_types_query');
+jest.mock('../common/hooks/use_rule_aad_fields');
+jest.mock('../common/hooks/use_alerts_data_view');
+
+jest.mocked(useAlertsDataView).mockReturnValue({
+ isLoading: false,
+ dataView: {
+ title: '.alerts-*',
+ fields: [
+ {
+ name: 'event.action',
+ type: 'string',
+ aggregatable: true,
+ searchable: true,
+ },
+ ],
+ },
+});
+
+jest.mocked(useLoadRuleTypesQuery).mockReturnValue({
+ ruleTypesState: {
+ isInitialLoad: false,
+ data: new Map(),
+ isLoading: false,
+ error: null,
+ },
+ authorizedToReadAnyRules: false,
+ hasAnyAuthorizedRuleType: false,
+ authorizedRuleTypes: [],
+ authorizedToCreateAnyRules: false,
+ isSuccess: false,
+});
+
+jest.mocked(useRuleAADFields).mockReturnValue({
+ aadFields: [],
+ loading: false,
+});
+
+const mockDataPlugin = dataPluginMock.createStartContract();
+const unifiedSearchBarMock = jest.fn().mockImplementation((props) => (
+
+));
+const httpMock = httpServiceMock.createStartContract();
+const toastsMock = notificationServiceMock.createStartContract().toasts;
+
+describe('AlertsSearchBar', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('renders correctly', () => {
+ render(
+
+ );
+ expect(screen.getByTestId('querySubmitButton')).toBeInTheDocument();
+ });
+
+ it('renders initial filters correctly', () => {
+ const filters = [
+ {
+ meta: {
+ negate: false,
+ alias: null,
+ disabled: false,
+ type: 'custom',
+ key: 'query',
+ },
+ query: { match_phrase: { 'host.name': 'testValue' } },
+ $state: { store: 'appState' },
+ },
+ ] as Filter[];
+
+ render(
+
+ );
+
+ expect(mockDataPlugin.query.filterManager.addFilters).toHaveBeenCalledWith(filters);
+ });
+});
diff --git a/packages/kbn-alerts-ui-shared/src/alerts_search_bar/index.tsx b/packages/kbn-alerts-ui-shared/src/alerts_search_bar/index.tsx
index 3cdb3b5b08a0c5..0b8bdab528864c 100644
--- a/packages/kbn-alerts-ui-shared/src/alerts_search_bar/index.tsx
+++ b/packages/kbn-alerts-ui-shared/src/alerts_search_bar/index.tsx
@@ -7,7 +7,8 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
-import { useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo, useEffect, useState, useRef } from 'react';
+import { cloneDeep } from 'lodash';
import type { Query, TimeRange } from '@kbn/es-query';
import type { SuggestionsAbstraction } from '@kbn/unified-search-plugin/public/typeahead/suggestions_component';
import { AlertConsumers, ValidFeatureId } from '@kbn/rule-data-utils';
@@ -26,10 +27,8 @@ export const AlertsSearchBar = ({
featureIds = EMPTY_FEATURE_IDS,
ruleTypeId,
query,
- filters,
onQueryChange,
onQuerySubmit,
- onFiltersUpdated,
rangeFrom,
rangeTo,
showFilterBar = false,
@@ -40,14 +39,17 @@ export const AlertsSearchBar = ({
http,
toasts,
unifiedSearchBar,
- dataViewsService,
+ dataService,
+ initialFilters,
+ onFiltersUpdated,
}: AlertsSearchBarProps) => {
const [queryLanguage, setQueryLanguage] = useState('kuery');
+ const isFirstRender = useRef(false);
const { dataView } = useAlertsDataView({
featureIds,
http,
toasts,
- dataViewsService,
+ dataViewsService: dataService.dataViews,
});
const { aadFields, loading: fieldsLoading } = useRuleAADFields({
ruleTypeId,
@@ -105,6 +107,26 @@ export const AlertsSearchBar = ({
});
};
+ useEffect(() => {
+ if (initialFilters?.length && !isFirstRender.current) {
+ dataService.query.filterManager.addFilters(cloneDeep(initialFilters));
+ isFirstRender.current = true;
+ }
+
+ const subscription = dataService.query.state$.subscribe((state) => {
+ if (state.changes.filters) {
+ onFiltersUpdated?.(state.state.filters ?? []);
+ }
+ });
+
+ return () => {
+ isFirstRender.current = false;
+ subscription.unsubscribe();
+ dataService.query.filterManager.removeAll();
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [initialFilters]);
+
return unifiedSearchBar({
appName,
disableQueryLanguageSwitcher,
@@ -112,13 +134,11 @@ export const AlertsSearchBar = ({
indexPatterns: !indexPatterns || fieldsLoading ? NO_INDEX_PATTERNS : indexPatterns,
placeholder,
query: { query: query ?? '', language: queryLanguage },
- filters,
dateRangeFrom: rangeFrom,
dateRangeTo: rangeTo,
displayStyle: 'inPage',
showFilterBar,
onQuerySubmit: onSearchQuerySubmit,
- onFiltersUpdated,
onRefresh,
showDatePicker,
showQueryInput: true,
diff --git a/packages/kbn-alerts-ui-shared/src/alerts_search_bar/types.ts b/packages/kbn-alerts-ui-shared/src/alerts_search_bar/types.ts
index 8875ef62947a84..0c844989e4a332 100644
--- a/packages/kbn-alerts-ui-shared/src/alerts_search_bar/types.ts
+++ b/packages/kbn-alerts-ui-shared/src/alerts_search_bar/types.ts
@@ -11,7 +11,7 @@ import type { Filter } from '@kbn/es-query';
import type { ValidFeatureId } from '@kbn/rule-data-utils';
import type { ToastsStart, HttpStart } from '@kbn/core/public';
import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
-import type { DataViewsContract } from '@kbn/data-views-plugin/common';
+import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
export type QueryLanguageType = 'lucene' | 'kuery';
@@ -22,7 +22,7 @@ export interface AlertsSearchBarProps {
rangeFrom?: string;
rangeTo?: string;
query?: string;
- filters?: Filter[];
+ initialFilters?: Filter[];
showFilterBar?: boolean;
showDatePicker?: boolean;
showSubmitButton?: boolean;
@@ -41,5 +41,5 @@ export interface AlertsSearchBarProps {
http: HttpStart;
toasts: ToastsStart;
unifiedSearchBar: UnifiedSearchPublicPluginStart['ui']['SearchBar'];
- dataViewsService: DataViewsContract;
+ dataService: DataPublicPluginStart;
}
diff --git a/x-pack/plugins/alerting/public/hooks/use_create_maintenance_window.ts b/x-pack/plugins/alerting/public/hooks/use_create_maintenance_window.ts
index 399f49f9a4cc09..d0a3fd324ed051 100644
--- a/x-pack/plugins/alerting/public/hooks/use_create_maintenance_window.ts
+++ b/x-pack/plugins/alerting/public/hooks/use_create_maintenance_window.ts
@@ -15,7 +15,7 @@ import { createMaintenanceWindow, CreateParams } from '../services/maintenance_w
const onErrorWithMessage = (message: string) =>
i18n.translate('xpack.alerting.maintenanceWindowsCreateFailureWithMessage', {
- defaultMessage: 'Failed to create maintenance window: {message}',
+ defaultMessage: ['Failed to create maintenance window', message].filter(Boolean).join(': '),
values: { message },
});
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx
index 6783289963f6c7..49169f473bf708 100644
--- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx
@@ -85,9 +85,7 @@ export const CreateMaintenanceWindowForm = React.memo(initialValue?.scopedQuery?.kql || '');
- const [filters, setFilters] = useState(
- (initialValue?.scopedQuery?.filters as Filter[]) || []
- );
+ const [filters, setFilters] = useState(initialValue?.scopedQuery?.filters || []);
const [scopedQueryErrors, setScopedQueryErrors] = useState([]);
const hasSetInitialCategories = useRef(false);
const categoryIdsHistory = useRef([]);
@@ -463,7 +461,7 @@ export const CreateMaintenanceWindowForm = React.memo {
@@ -63,7 +63,7 @@ describe('MaintenanceWindowScopedQuery', () => {
featureIds={['observability', 'management', 'securitySolution'] as AlertConsumers[]}
isEnabled={false}
query={''}
- filters={[]}
+ initialFilters={[]}
onQueryChange={jest.fn()}
onFiltersChange={jest.fn()}
/>
@@ -77,7 +77,7 @@ describe('MaintenanceWindowScopedQuery', () => {
featureIds={['observability', 'management', 'securitySolution'] as AlertConsumers[]}
isLoading={true}
query={''}
- filters={[]}
+ initialFilters={[]}
onQueryChange={jest.fn()}
onFiltersChange={jest.fn()}
/>
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/maintenance_window_scoped_query.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/maintenance_window_scoped_query.tsx
index d252333fb4a0bf..6aa00dfec02113 100644
--- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/maintenance_window_scoped_query.tsx
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/maintenance_window_scoped_query.tsx
@@ -16,7 +16,7 @@ import { useKibana } from '../../../utils/kibana_react';
export interface MaintenanceWindowScopedQueryProps {
featureIds: AlertConsumers[];
query: string;
- filters: Filter[];
+ initialFilters?: Filter[];
errors?: string[];
isLoading?: boolean;
isEnabled?: boolean;
@@ -29,7 +29,7 @@ export const MaintenanceWindowScopedQuery = React.memo(
const {
featureIds,
query,
- filters,
+ initialFilters,
errors = [],
isLoading,
isEnabled = true,
@@ -79,7 +79,7 @@ export const MaintenanceWindowScopedQuery = React.memo(
featureIds={featureIds}
disableQueryLanguageSwitcher={true}
query={query}
- filters={filters}
+ initialFilters={initialFilters}
onQueryChange={onQueryChangeInternal}
onQuerySubmit={onQueryChangeInternal}
onFiltersUpdated={onFiltersChange}
@@ -90,7 +90,7 @@ export const MaintenanceWindowScopedQuery = React.memo(
http={http}
toasts={toasts}
unifiedSearchBar={SearchBar}
- dataViewsService={data.dataViews}
+ dataService={data}
/>
diff --git a/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.tsx b/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.tsx
index 863855bbbb3b85..c45d2cdfa08fe2 100644
--- a/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.tsx
+++ b/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.tsx
@@ -165,7 +165,7 @@ export function ObservabilityAlertSearchBar({
rangeFrom={rangeFrom}
rangeTo={rangeTo}
showFilterBar={showFilterBar}
- filters={filters}
+ initialFilters={filters}
onFiltersUpdated={onFilterUpdated}
savedQuery={savedQuery}
onSavedQueryUpdated={setSavedQuery}
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index 5a4660f362987a..068073bc6ac2eb 100644
--- a/x-pack/plugins/translations/translations/fr-FR.json
+++ b/x-pack/plugins/translations/translations/fr-FR.json
@@ -9793,7 +9793,6 @@
"xpack.alerting.maintenanceWindows.upcoming": "À venir",
"xpack.alerting.maintenanceWindowsArchiveFailure": "Impossible d'archiver la fenêtre de maintenance.",
"xpack.alerting.maintenanceWindowsArchiveSuccess": "Fenêtre de maintenance archivée \"{title}\"",
- "xpack.alerting.maintenanceWindowsCreateFailureWithMessage": "Impossible de créer la fenêtre de maintenance : {message}",
"xpack.alerting.maintenanceWindowsCreateFailureWithoutMessage": "Impossible de créer la fenêtre de maintenance",
"xpack.alerting.maintenanceWindowsCreateSuccess": "Fenêtre de maintenance créée \"{title}\"",
"xpack.alerting.maintenanceWindowsFinishedAndArchiveFailure": "Impossible d'annuler et d'archiver la fenêtre de maintenance.",
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index c112b137c2e2b8..4d644aae283bd7 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -9787,7 +9787,6 @@
"xpack.alerting.maintenanceWindows.upcoming": "予定",
"xpack.alerting.maintenanceWindowsArchiveFailure": "保守時間枠をアーカイブできませんでした。",
"xpack.alerting.maintenanceWindowsArchiveSuccess": "アーカイブされた保守時間枠''{title}''",
- "xpack.alerting.maintenanceWindowsCreateFailureWithMessage": "保守時間枠を作成できませんでした:{message}",
"xpack.alerting.maintenanceWindowsCreateFailureWithoutMessage": "保守時間枠を作成できませんでした",
"xpack.alerting.maintenanceWindowsCreateSuccess": "作成された保守時間枠''{title}''",
"xpack.alerting.maintenanceWindowsFinishedAndArchiveFailure": "保守時間枠をキャンセルしてアーカイブできませんでした。",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 30d822480bdff0..41f8a38e1eaa0c 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -9801,7 +9801,6 @@
"xpack.alerting.maintenanceWindows.upcoming": "即将发生",
"xpack.alerting.maintenanceWindowsArchiveFailure": "无法归档维护窗口。",
"xpack.alerting.maintenanceWindowsArchiveSuccess": "已归档维护窗口“{title}”",
- "xpack.alerting.maintenanceWindowsCreateFailureWithMessage": "无法创建维护窗口:{message}",
"xpack.alerting.maintenanceWindowsCreateFailureWithoutMessage": "无法创建维护窗口",
"xpack.alerting.maintenanceWindowsCreateSuccess": "已创建维护窗口“{title}”",
"xpack.alerting.maintenanceWindowsFinishedAndArchiveFailure": "无法取消并归档维护窗口。",
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/value_validators.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/value_validators.test.ts
index 97c9ba686435a9..df1dce08f684ab 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/lib/value_validators.test.ts
+++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/value_validators.test.ts
@@ -11,9 +11,10 @@ import {
isValidUrl,
getConnectorWithInvalidatedFields,
getRuleWithInvalidatedFields,
+ validateActionFilterQuery,
} from './value_validators';
import { v4 as uuidv4 } from 'uuid';
-import { Rule, IErrorObject, UserConfiguredActionConnector } from '../../types';
+import { Rule, IErrorObject, UserConfiguredActionConnector, RuleUiAction } from '../../types';
describe('throwIfAbsent', () => {
test('throws if value is absent', () => {
@@ -441,3 +442,70 @@ describe('getRuleWithInvalidatedFields', () => {
expect((rule.actions[1].params as any).incident.field.name).toEqual('myIncident');
});
});
+
+describe('validateActionFilterQuery', () => {
+ test('does not return an error when kql query exists', () => {
+ const actionItem: RuleUiAction = {
+ actionTypeId: 'test',
+ group: 'qwer',
+ id: '123',
+ params: {
+ incident: {
+ field: {
+ name: 'myIncident',
+ },
+ },
+ },
+ alertsFilter: { query: { kql: 'id: *', filters: [] } },
+ };
+
+ expect(validateActionFilterQuery(actionItem)).toBe(null);
+ });
+
+ test('does not return an error when filter query exists', () => {
+ const actionItem = {
+ actionTypeId: 'test',
+ group: 'qwer',
+ id: '123',
+ params: {
+ incident: {
+ field: {
+ name: 'myIncident',
+ },
+ },
+ },
+ alertsFilter: {
+ query: {
+ kql: undefined,
+ filters: [
+ {
+ $state: { store: 'state' },
+ meta: { key: 'test' },
+ query: { exists: { field: '_id' } },
+ },
+ ],
+ },
+ },
+ };
+
+ expect(validateActionFilterQuery(actionItem)).toBe(null);
+ });
+
+ test('returns an error no kql and no filters', () => {
+ const actionItem = {
+ actionTypeId: 'test',
+ group: 'qwer',
+ id: '123',
+ params: {
+ incident: {
+ field: {
+ name: 'myIncident',
+ },
+ },
+ },
+ alertsFilter: { query: { kql: '', filters: [] } },
+ };
+
+ expect(validateActionFilterQuery(actionItem)).toBe('A custom query is required.');
+ });
+});
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/value_validators.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/value_validators.ts
index bb98c2664141d5..6ad7eb14c8270e 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/lib/value_validators.ts
+++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/value_validators.ts
@@ -20,7 +20,7 @@ const filterQueryRequiredError = i18n.translate(
export const validateActionFilterQuery = (actionItem: RuleUiAction): string | null => {
if ('alertsFilter' in actionItem) {
const query = actionItem?.alertsFilter?.query;
- if (query && !query.kql) {
+ if (query && !(query.kql || query.filters.length)) {
return filterQueryRequiredError;
}
}
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_query.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_query.tsx
index 0abcce240b17e0..48ca372eef81dc 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_query.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_query.tsx
@@ -84,7 +84,7 @@ export const ActionAlertsFilterQuery: React.FC = (
ruleTypeId={ruleTypeId}
disableQueryLanguageSwitcher={true}
query={query.kql}
- filters={query.filters ?? []}
+ initialFilters={query.filters ?? []}
onQueryChange={onQueryChange}
onQuerySubmit={onQueryChange}
onFiltersUpdated={onFiltersUpdated}
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.test.tsx
new file mode 100644
index 00000000000000..f0a818121cac84
--- /dev/null
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.test.tsx
@@ -0,0 +1,136 @@
+/*
+ * 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 from 'react';
+import { render, screen } from '@testing-library/react';
+import { useAlertsDataView } from '@kbn/alerts-ui-shared/src/common/hooks/use_alerts_data_view';
+import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
+import { Filter } from '@kbn/es-query';
+import { NotificationsStart } from '@kbn/core-notifications-browser';
+import { useLoadRuleTypesQuery } from '../../hooks/use_load_rule_types_query';
+import { useRuleAADFields } from '../../hooks/use_rule_aad_fields';
+import { AlertsSearchBar } from './alerts_search_bar';
+
+const mockDataPlugin = dataPluginMock.createStartContract();
+jest.mock('../../hooks/use_load_rule_types_query');
+jest.mock('../../hooks/use_rule_aad_fields');
+jest.mock('@kbn/alerts-ui-shared/src/common/hooks/use_alerts_data_view');
+jest.mock('@kbn/kibana-react-plugin/public', () => {
+ const original = jest.requireActual('@kbn/kibana-react-plugin/public');
+ return {
+ useKibana: () => ({
+ services: {
+ ...original.useKibana().services,
+ data: mockDataPlugin,
+ unifiedSearch: {
+ ui: {
+ SearchBar: jest.fn().mockImplementation((props) => (
+
+ )),
+ },
+ },
+ notifications: { toasts: { addWarning: jest.fn() } } as unknown as NotificationsStart,
+ },
+ }),
+ };
+});
+jest.mocked(useAlertsDataView).mockReturnValue({
+ isLoading: false,
+ dataView: {
+ title: '.alerts-*',
+ fields: [
+ {
+ name: 'event.action',
+ type: 'string',
+ aggregatable: true,
+ searchable: true,
+ },
+ ],
+ },
+});
+
+jest.mocked(useLoadRuleTypesQuery).mockReturnValue({
+ ruleTypesState: {
+ initialLoad: false,
+ data: new Map(),
+ isLoading: false,
+ error: undefined,
+ },
+ authorizedToReadAnyRules: false,
+ hasAnyAuthorizedRuleType: false,
+ authorizedRuleTypes: [],
+ authorizedToCreateAnyRules: false,
+ isSuccess: false,
+});
+
+jest.mocked(useRuleAADFields).mockReturnValue({
+ aadFields: [],
+ loading: false,
+});
+
+describe('AlertsSearchBar', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('renders correctly', () => {
+ render(
+
+ );
+ expect(screen.getByTestId('querySubmitButton')).toBeInTheDocument();
+ });
+
+ it('renders initial filters correctly', () => {
+ const filters = [
+ {
+ meta: {
+ negate: false,
+ alias: null,
+ disabled: false,
+ type: 'custom',
+ key: 'query',
+ },
+ query: { match_phrase: { 'host.name': 'testValue' } },
+ $state: { store: 'appState' },
+ },
+ ] as Filter[];
+
+ render(
+
+ );
+
+ expect(mockDataPlugin.query.filterManager.addFilters).toHaveBeenCalledWith(filters);
+ });
+});
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx
index 3896e5d0e938a7..0cdda4f35840ad 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx
@@ -5,13 +5,14 @@
* 2.0.
*/
-import React, { useCallback, useMemo, useState } from 'react';
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { compareFilters, Query, TimeRange } from '@kbn/es-query';
import { SuggestionsAbstraction } from '@kbn/unified-search-plugin/public/typeahead/suggestions_component';
import { AlertConsumers, ValidFeatureId } from '@kbn/rule-data-utils';
import { EuiContextMenuPanelDescriptor, EuiContextMenuPanelItemDescriptor } from '@elastic/eui';
import { useAlertsDataView } from '@kbn/alerts-ui-shared/src/common/hooks/use_alerts_data_view';
+import { cloneDeep } from 'lodash';
import { isQuickFiltersGroup, QuickFiltersMenuItem } from './quick_filters';
import { NO_INDEX_PATTERNS } from './constants';
import { SEARCH_BAR_PLACEHOLDER } from './translations';
@@ -31,7 +32,7 @@ export function AlertsSearchBar({
featureIds = EMPTY_FEATURE_IDS,
ruleTypeId,
query,
- filters,
+ initialFilters,
quickFilters = [],
onQueryChange,
onQuerySubmit,
@@ -53,9 +54,11 @@ export function AlertsSearchBar({
unifiedSearch: {
ui: { SearchBar },
},
+ data: dataService,
} = useKibana().services;
const [queryLanguage, setQueryLanguage] = useState('kuery');
+ const isFirstRender = useRef(false);
const { dataView } = useAlertsDataView({
featureIds,
http,
@@ -146,8 +149,8 @@ export function AlertsSearchBar({
...menuItem,
icon: qf.icon ?? 'filterInCircle',
onClick: () => {
- if (!filters?.some((f) => compareFilters(f, filter))) {
- onFiltersUpdated?.([...(filters ?? []), filter]);
+ if (!initialFilters?.some((f) => compareFilters(f, filter))) {
+ onFiltersUpdated?.([...(initialFilters ?? []), filter]);
}
},
'data-test-subj': `quick-filters-item-${qf.name}`,
@@ -166,7 +169,27 @@ export function AlertsSearchBar({
panels: [],
};
}
- }, [filters, onFiltersUpdated, quickFilters, showFilterBar]);
+ }, [initialFilters, onFiltersUpdated, quickFilters, showFilterBar]);
+
+ useEffect(() => {
+ if (initialFilters?.length && !isFirstRender.current) {
+ dataService.query.filterManager.addFilters(cloneDeep(initialFilters));
+ isFirstRender.current = true;
+ }
+
+ const subscription = dataService.query.state$.subscribe((state) => {
+ if (state.changes.filters) {
+ onFiltersUpdated?.(state.state.filters ?? []);
+ }
+ });
+
+ return () => {
+ isFirstRender.current = false;
+ subscription.unsubscribe();
+ dataService.query.filterManager.removeAll();
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [initialFilters]);
return (
, 'query' | 'onQueryChange' | 'onQuerySubmit'> {
+ extends Omit, 'query' | 'onQueryChange' | 'onQuerySubmit' | 'filters'> {
appName: string;
disableQueryLanguageSwitcher?: boolean;
featureIds: ValidFeatureId[];
rangeFrom?: string;
rangeTo?: string;
query?: string;
- filters?: Filter[];
+ initialFilters?: Filter[];
quickFilters?: QuickFiltersMenuItem[];
showFilterBar?: boolean;
showDatePicker?: boolean;
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/url_synced_alerts_search_bar.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/url_synced_alerts_search_bar.tsx
index 71594e3206ffd5..1eb9a3891b2d0d 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/url_synced_alerts_search_bar.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/url_synced_alerts_search_bar.tsx
@@ -138,7 +138,7 @@ export const UrlSyncedAlertsSearchBar = ({
rangeTo={rangeTo}
query={kuery}
onQuerySubmit={onQueryChange}
- filters={filters}
+ initialFilters={filters}
onFiltersUpdated={onFiltersChange}
savedQuery={savedQuery}
onSavedQueryUpdated={setSavedQuery}