From 4473863d797f74efb113a74c5007ce6dc8bfa149 Mon Sep 17 00:00:00 2001 From: Rodney Norris Date: Tue, 23 Aug 2022 15:01:52 -0500 Subject: [PATCH 1/3] [Enterprise Search] auto-select index when creating engine (#139152) * [Enterprise Search] auto-select index when creating engine Updated the link to create an App Engine from an elasticsearch index detail page so that it automatically selects that engine on the engine creation page. * [Enterprise Search] disable create engine for hidden indices You cannot create an App Search engine for a hidden index so we are disabling the "Create a new App Search engine" menu item for hidden indices. There is an exception for workplace search document indices, but we are intentionally ignoring this case since the create new engine page will not show any hidden indices by default. You have to first create an alias for the index. So while technically possible, we are choosing to not support it from this page. * [Enterprise Search] added index action for create engine Added an action to handle initializing the create engine page with an es index. * removed addQueryParameter utility This was added to help with encoding parameters, but I opted to use the existing function `generateEncodedPath` instead so this is no longer needed. * improving type usage in fetch_indices * update hidden to required on index type Updated the ElasticsearchIndex type to make hidden required instead of optional since we only really care if its true, otherwise we can treat undefined as not hidden and remove the undefined state. --- .../enterprise_search/common/types/indices.ts | 1 + .../__mocks__/engine_creation_logic.mock.ts | 7 +++ .../engine_creation/engine_creation.tsx | 9 ++- .../engine_creation/engine_creation_logic.ts | 9 +++ .../__mocks__/search_indices.mock.ts | 3 + .../__mocks__/view_index.mock.ts | 3 + .../create_engine_menu_item.tsx | 63 +++++++++++++++++++ .../header_actions/header_actions.tsx | 2 +- .../header_actions/search_engines_popover.tsx | 43 +++++++------ .../applications/shared/constants/index.ts | 1 + .../shared/constants/query_params.ts | 8 +++ .../server/__mocks__/fetch_indices.mock.ts | 2 + .../server/lib/indices/fetch_index.test.ts | 2 + .../server/lib/indices/fetch_indices.test.ts | 9 +++ .../server/lib/indices/fetch_indices.ts | 20 +++--- 15 files changed, 153 insertions(+), 29 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/create_engine_menu_item.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/constants/query_params.ts diff --git a/x-pack/plugins/enterprise_search/common/types/indices.ts b/x-pack/plugins/enterprise_search/common/types/indices.ts index 38f4b9873eba2..08f4125ef8efa 100644 --- a/x-pack/plugins/enterprise_search/common/types/indices.ts +++ b/x-pack/plugins/enterprise_search/common/types/indices.ts @@ -18,6 +18,7 @@ import { Crawler } from './crawler'; export interface ElasticsearchIndex { count: number; // Elasticsearch _count health?: HealthStatus; + hidden: boolean; name: IndexName; status?: IndicesStatsIndexMetadataState; total: { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/__mocks__/engine_creation_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/__mocks__/engine_creation_logic.mock.ts index 6cfba782698b5..42e9c546d85ae 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/__mocks__/engine_creation_logic.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/__mocks__/engine_creation_logic.mock.ts @@ -38,6 +38,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 0, health: 'yellow', + hidden: false, status: 'open', name: 'search-my-index-1', uuid: 'ydlR_QQJTeyZP66tzQSmMQ', @@ -56,6 +57,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 100, health: 'green', + hidden: false, status: 'open', name: 'my-index-2', uuid: '4dlR_QQJTe2ZP6qtzQSmMQ', @@ -74,6 +76,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 100, health: 'green', + hidden: false, status: 'open', name: 'search-my-index-2', uuid: '4dlR_QQJTe2ZP6qtzQSmMQ', @@ -92,6 +95,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 100, health: 'green', + hidden: false, status: 'open', name: 'alias-my-index-2', uuid: '4dlR_QQJTe2ZP6qtzQSmMQ', @@ -110,6 +114,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 100, health: 'green', + hidden: false, status: 'open', name: 'index-without-read-privilege', uuid: '4dlR_QQJTe2ZP6qtzQSmMQ', @@ -128,6 +133,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 100, health: 'green', + hidden: false, status: 'open', name: 'index-without-manage-privilege', uuid: '4dlR_QQJTe2ZP6qtzQSmMQ', @@ -146,6 +152,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 100, health: 'green', + hidden: false, status: 'open', name: 'alias-without-manage-privilege', uuid: '4dlR_QQJTe2ZP6qtzQSmMQ', diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation.tsx index 95ed3875888f4..b9fd23ac904f0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation.tsx @@ -12,6 +12,7 @@ import { useLocation } from 'react-router-dom'; import { Location } from 'history'; import { useActions, useValues } from 'kea'; +import { ESINDEX_QUERY_PARAMETER } from '../../../shared/constants'; import { parseQueryParams } from '../../../shared/query_params'; import { ENGINES_TITLE } from '../engines'; import { AppSearchPageTemplate } from '../layout'; @@ -25,15 +26,19 @@ import { SelectEngineType } from './select_engine_type'; export const EngineCreation: React.FC = () => { const { search } = useLocation() as Location; - const { method } = parseQueryParams(search); + const { method, ...params } = parseQueryParams(search); const { engineType, currentEngineCreationStep } = useValues(EngineCreationLogic); - const { setIngestionMethod } = useActions(EngineCreationLogic); + const { setIngestionMethod, initializeWithESIndex } = useActions(EngineCreationLogic); useEffect(() => { if (typeof method === 'string') { setIngestionMethod(method); } + const esIndexParam = params[ESINDEX_QUERY_PARAMETER]; + if (typeof esIndexParam === 'string') { + initializeWithESIndex(esIndexParam); + } }, []); return ( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation_logic.ts index dbf7efa907c74..347846686b5cd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation_logic.ts @@ -42,6 +42,7 @@ interface EngineCreationActions { setSelectedIndex(selectedIndexName: string): { selectedIndexName: string }; setEngineType(engineType: EngineType): { engineType: EngineType }; setIsAliasAllowed(isAliasAllowed: boolean): { isAliasAllowed: boolean }; + initializeWithESIndex(indexName: string): { indexName: string }; } interface EngineCreationValues { @@ -82,6 +83,7 @@ export const EngineCreationLogic = kea ({ engineType }), setCreationStep: (currentEngineCreationStep) => currentEngineCreationStep, setIsAliasAllowed: (isAliasAllowed) => ({ isAliasAllowed }), + initializeWithESIndex: (indexName) => ({ indexName }), }, reducers: { ingestionMethod: [ @@ -118,6 +120,10 @@ export const EngineCreationLogic = kea + indexName.length === 0 || indexName.startsWith('search-') + ? '' + : `search-${indexName}-alias`, }, ], isAliasAllowed: [ @@ -145,18 +151,21 @@ export const EngineCreationLogic = kea selectedIndexName, onSubmitError: () => '', + initializeWithESIndex: (_, { indexName }) => indexName, }, ], engineType: [ 'appSearch', { setEngineType: (_, { engineType }) => engineType, + initializeWithESIndex: () => 'elasticsearch', }, ], currentEngineCreationStep: [ EngineCreationSteps.SelectStep, { setCreationStep: (_, currentEngineCreationStep) => currentEngineCreationStep, + initializeWithESIndex: () => EngineCreationSteps.ConfigureStep, }, ], }, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/search_indices.mock.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/search_indices.mock.ts index ba72c8ada0dd1..e39ff051f962b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/search_indices.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/search_indices.mock.ts @@ -11,6 +11,7 @@ import { ElasticsearchIndexWithIngestion } from '../../../../common/types/indice export const indices: ElasticsearchIndexWithIngestion[] = [ { count: 1, + hidden: false, name: 'api', total: { docs: { @@ -41,6 +42,7 @@ export const indices: ElasticsearchIndexWithIngestion[] = [ sync_now: false, }, count: 1, + hidden: false, name: 'connector', total: { docs: { @@ -56,6 +58,7 @@ export const indices: ElasticsearchIndexWithIngestion[] = [ id: '3', index_name: 'crawler', }, + hidden: false, name: 'crawler', total: { docs: { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/view_index.mock.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/view_index.mock.ts index 9ade186d55380..bc226baa77f7f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/view_index.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/view_index.mock.ts @@ -20,6 +20,7 @@ export const apiIndex: ApiViewIndex = { ingestionMethod: IngestionMethod.API, ingestionStatus: IngestionStatus.CONNECTED, lastUpdated: null, + hidden: false, name: 'api', total: { docs: { @@ -50,6 +51,7 @@ export const connectorIndex: ConnectorViewIndex = { sync_now: false, }, count: 1, + hidden: false, ingestionMethod: IngestionMethod.CONNECTOR, ingestionStatus: IngestionStatus.INCOMPLETE, lastUpdated: 'never', @@ -68,6 +70,7 @@ export const crawlerIndex: CrawlerViewIndex = { id: '3', index_name: 'crawler', }, + hidden: false, ingestionMethod: IngestionMethod.CRAWLER, ingestionStatus: IngestionStatus.INCOMPLETE, lastUpdated: null, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/create_engine_menu_item.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/create_engine_menu_item.tsx new file mode 100644 index 0000000000000..a5667327a8208 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/create_engine_menu_item.tsx @@ -0,0 +1,63 @@ +/* + * 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 { EuiBetaBadge, EuiContextMenuItem, EuiText, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { APP_SEARCH_PLUGIN } from '../../../../../../../common/constants'; +import { ENGINE_CREATION_PATH } from '../../../../../app_search/routes'; +import { ESINDEX_QUERY_PARAMETER } from '../../../../../shared/constants'; +import { generateEncodedPath } from '../../../../../shared/encode_path_params'; +import { KibanaLogic } from '../../../../../shared/kibana'; + +export interface CreateEngineMenuItemProps { + indexName?: string; + isHiddenIndex?: boolean; +} + +export const CreateEngineMenuItem: React.FC = ({ + indexName, + isHiddenIndex, +}) => { + const engineCreationPath = !indexName + ? `${APP_SEARCH_PLUGIN.URL}${ENGINE_CREATION_PATH}` + : generateEncodedPath(`${APP_SEARCH_PLUGIN.URL}${ENGINE_CREATION_PATH}?:indexKey=:indexName`, { + indexKey: ESINDEX_QUERY_PARAMETER, + indexName, + }); + + return ( + + + { + KibanaLogic.values.navigateToUrl(engineCreationPath, { + shouldNotCreateHref: true, + }); + }} + disabled={isHiddenIndex} + > + +

+ {i18n.translate('xpack.enterpriseSearch.content.index.searchEngines.createEngine', { + defaultMessage: 'Create an App Search engine', + })} +

+
+
+
+ + + +
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/header_actions.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/header_actions.tsx index 3809483e053e7..9f04dd7ba16ce 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/header_actions.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/header_actions.tsx @@ -18,5 +18,5 @@ import { SyncButton } from './sync_button'; export const getHeaderActions = (indexData?: ElasticsearchIndexWithIngestion) => [ ...(isCrawlerIndex(indexData) ? [] : []), ...(isConnectorIndex(indexData) ? [] : []), - , + , ]; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/search_engines_popover.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/search_engines_popover.tsx index d535d37a4a8ee..2ac1682f8676c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/search_engines_popover.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/search_engines_popover.tsx @@ -15,17 +15,26 @@ import { EuiContextMenuPanel, EuiContextMenuItem, EuiText, + EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { APP_SEARCH_PLUGIN } from '../../../../../../../common/constants'; -import { ENGINE_CREATION_PATH } from '../../../../../app_search/routes'; import { KibanaLogic } from '../../../../../shared/kibana'; +import { CreateEngineMenuItem } from './create_engine_menu_item'; import { SearchEnginesPopoverLogic } from './search_engines_popover_logic'; -export const SearchEnginesPopover: React.FC = () => { +export interface SearchEnginesPopoverProps { + indexName?: string; + isHiddenIndex?: boolean; +} + +export const SearchEnginesPopover: React.FC = ({ + indexName, + isHiddenIndex, +}) => { const { isSearchEnginesPopoverOpen } = useValues(SearchEnginesPopoverLogic); const { toggleSearchEnginesPopover } = useActions(SearchEnginesPopoverLogic); @@ -60,22 +69,20 @@ export const SearchEnginesPopover: React.FC = () => {

, - { - KibanaLogic.values.navigateToUrl(APP_SEARCH_PLUGIN.URL + ENGINE_CREATION_PATH, { - shouldNotCreateHref: true, - }); - }} - > - -

- {i18n.translate('xpack.enterpriseSearch.content.index.searchEngines.createEngine', { - defaultMessage: 'Create a new App Search engine', - })} -

-
-
, + isHiddenIndex ? ( + + ) : ( + + ), ]} /> diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/constants/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/constants/index.ts index 6075f6e9822d3..fa9eb67cf9fe4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/constants/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/constants/index.ts @@ -7,6 +7,7 @@ export * from './actions'; export * from './labels'; +export * from './query_params'; export * from './tables'; export * from './units'; export { DEFAULT_META } from './default_meta'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/constants/query_params.ts b/x-pack/plugins/enterprise_search/public/applications/shared/constants/query_params.ts new file mode 100644 index 0000000000000..1a95b9734043e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/constants/query_params.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export const ESINDEX_QUERY_PARAMETER = 'esindex'; diff --git a/x-pack/plugins/enterprise_search/server/__mocks__/fetch_indices.mock.ts b/x-pack/plugins/enterprise_search/server/__mocks__/fetch_indices.mock.ts index 5305cc8ecdb55..a860069af9e93 100644 --- a/x-pack/plugins/enterprise_search/server/__mocks__/fetch_indices.mock.ts +++ b/x-pack/plugins/enterprise_search/server/__mocks__/fetch_indices.mock.ts @@ -15,6 +15,7 @@ export const mockSingleIndexStatsResponse = { indices: { 'search-regular-index': { health: 'green', + hidden: false, status: 'open', total: { docs: { @@ -115,6 +116,7 @@ export const getIndexReturnValue = (indexName: string) => { alias: indexName.startsWith('alias') || indexName.startsWith('search-alias'), count: 100, name: indexName, + hidden: indexName.includes('hidden'), privileges: { manage: true, read: true }, total: { ...mockMultiStatsResponse.indices[indexName].total, diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_index.test.ts b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_index.test.ts index 9bf9f2b2d2f1d..49384f564a988 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_index.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_index.test.ts @@ -43,6 +43,7 @@ describe('fetchIndex lib function', () => { indices: { index_name: { health: 'green', + hidden: false, size: new ByteSizeValue(108000).toString(), status: 'open', total: { @@ -63,6 +64,7 @@ describe('fetchIndex lib function', () => { aliases: [], count: 100, health: 'green', + hidden: false, name: 'index_name', status: 'open', total: { diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.test.ts b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.test.ts index 1fc8f4cc07186..4a01295fbeaa8 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.test.ts @@ -86,6 +86,7 @@ describe('fetchIndices lib function', () => { alias: false, count: 100, health: 'green', + hidden: false, name: 'search-regular-index', privileges: { manage: true, read: true }, status: 'open', @@ -135,6 +136,7 @@ describe('fetchIndices lib function', () => { alias: false, count: 100, health: 'green', + hidden: false, name: 'search-regular-index', privileges: { manage: true, read: true }, status: 'open', @@ -195,6 +197,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: 'green', + hidden: false, name: 'index-without-prefix', status: 'open', alias: false, @@ -213,6 +216,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: 'green', + hidden: false, name: 'search-aliased', status: 'open', alias: true, @@ -231,6 +235,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: 'green', + hidden: false, name: 'search-double-aliased', status: 'open', alias: true, @@ -249,6 +254,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: 'green', + hidden: false, name: 'second-index', status: 'open', alias: false, @@ -298,6 +304,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: 'green', + hidden: false, name: 'index-without-prefix', status: 'open', alias: false, @@ -316,6 +323,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: 'green', + hidden: false, name: 'second-index', status: 'open', alias: false, @@ -350,6 +358,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: undefined, + hidden: false, name: 'search-regular-index', status: undefined, alias: false, diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.ts b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.ts index 28a5373d50ac5..5a1bfec87b9b7 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.ts @@ -13,13 +13,16 @@ import { import { ByteSizeValue } from '@kbn/config-schema'; import { IScopedClusterClient } from '@kbn/core/server'; -import { ElasticsearchIndexWithPrivileges } from '../../../common/types'; +import { + ElasticsearchIndex, + ElasticsearchIndexWithPrivileges, +} from '../../../common/types/indices'; export const mapIndexStats = ( indexData: IndicesIndexState, indexStats: IndicesStatsIndicesStats, indexName: string -) => { +): Omit & { aliases: string[] } => { const aliases = Object.keys(indexData.aliases!); const sizeInBytes = new ByteSizeValue(indexStats?.total?.store?.size_in_bytes ?? 0).toString(); @@ -38,6 +41,7 @@ export const mapIndexStats = ( return { aliases, health: indexStats?.health, + hidden: Boolean(indexData.settings?.index?.hidden), name: indexName, status: indexStats?.status, total, @@ -132,17 +136,17 @@ export const fetchIndices = async ( return mapIndexStats(indexData, indexStats, indexName); }) .flatMap(({ name, aliases, ...indexData }) => { - const indicesAndAliases = [] as ElasticsearchIndexWithPrivileges[]; + const indicesAndAliases: ElasticsearchIndexWithPrivileges[] = []; if (includeAliases) { aliases.forEach((alias) => { if (alias.startsWith(alwaysShowSearchPattern)) { indicesAndAliases.push({ + ...indexData, alias: true, count: indexCounts[alias] ?? 0, name: alias, privileges: { manage: false, read: false, ...indexPrivileges[name] }, - ...indexData, }); } }); @@ -160,23 +164,23 @@ export const fetchIndices = async ( }) .flatMap(({ name, aliases, ...indexData }) => { // expand aliases and add to results - const indicesAndAliases = [] as ElasticsearchIndexWithPrivileges[]; + const indicesAndAliases: ElasticsearchIndexWithPrivileges[] = []; indicesAndAliases.push({ + ...indexData, alias: false, count: indexCounts[name] ?? 0, name, privileges: { manage: false, read: false, ...indexPrivileges[name] }, - ...indexData, }); if (includeAliases) { aliases.forEach((alias) => { indicesAndAliases.push({ + ...indexData, alias: true, count: indexCounts[alias] ?? 0, name: alias, privileges: { manage: false, read: false, ...indexPrivileges[name] }, - ...indexData, }); }); } @@ -191,7 +195,7 @@ export const fetchIndices = async ( const itemsToInclude = alwaysShowIndices.filter(({ name }) => indexNamesToInclude.includes(name)); const indicesData = alwaysShowSearchPattern - ? ([...regularIndexData, ...itemsToInclude] as ElasticsearchIndexWithPrivileges[]) + ? [...regularIndexData, ...itemsToInclude] : regularIndexData; return indicesData.filter( From 908a01b5a695ea50002c3a372031c90e3f37d66f Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 23 Aug 2022 13:12:19 -0700 Subject: [PATCH 2/3] Update docs for KQL autocomplete when DLS is enabled (#139248) --- docs/management/advanced-options.asciidoc | 2 +- src/plugins/data/server/ui_settings.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 7a1eaae676906..e98561ce50108 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -89,7 +89,7 @@ Set this property to `false` to prevent the filter editor and KQL autocomplete from suggesting values for fields. [[autocomplete-valuesuggestionmethod]]`autocomplete:valueSuggestionMethod`:: -When set to `terms_enum`, autocomplete uses the terms enum API for value suggestions. Kibana returns results faster, but suggestions are approximate, sorted alphabetically, and can be outside the selected time range. +When set to `terms_enum`, autocomplete uses the terms enum API for value suggestions. Kibana returns results faster, but suggestions are approximate, sorted alphabetically, and can be outside the selected time range. (Note that this API is incompatible with {ref}/document-level-security.html[Document-Level-Security].) When set to `terms_agg`, Kibana uses a terms aggregation for value suggestions, which is slower, but suggestions include all values that optionally match your time range and are sorted by popularity. diff --git a/src/plugins/data/server/ui_settings.ts b/src/plugins/data/server/ui_settings.ts index 31c360e761078..fce2680f5fc03 100644 --- a/src/plugins/data/server/ui_settings.ts +++ b/src/plugins/data/server/ui_settings.ts @@ -493,8 +493,9 @@ export function getUiSettings( description: i18n.translate('data.advancedSettings.autocompleteValueSuggestionMethodText', { defaultMessage: 'The method used for querying suggestions for values in KQL autocomplete. Select terms_enum to use the ' + - 'Elasticsearch terms enum API for improved autocomplete suggestion performance. Select terms_agg to use an ' + - 'Elasticsearch terms aggregation. {learnMoreLink}', + 'Elasticsearch terms enum API for improved autocomplete suggestion performance. (Note that terms_enum is ' + + 'incompatible with Document Level Security.) Select terms_agg to use an Elasticsearch terms aggregation. ' + + '{learnMoreLink}', values: { learnMoreLink: `` + From fe646b297dfe79d04dbe6275c319c648b25f9c1a Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 23 Aug 2022 14:21:37 -0700 Subject: [PATCH 3/3] [Security Solution][Tech debt] T-Grid cleanup (#138581) * [Security Solution][Tech debt] T-Grid cleanup: removed unused logic * Renamed folder to correspond the logic inside * Fixed types for isEventViewer * Fixed tests, corrected names * Fixed due to comments --- .../common/components/events_viewer/index.tsx | 2 - .../additional_filters_action/index.test.tsx | 80 ++++ .../additional_filters_action/index.tsx | 94 ++++ .../additional_filters_action/translations.ts | 36 ++ .../alerts_utility_bar/index.test.tsx | 419 ------------------ .../alerts_table/alerts_utility_bar/index.tsx | 284 ------------ .../alerts_utility_bar/translations.ts | 85 ---- .../components/alerts_table/index.test.tsx | 4 +- .../components/alerts_table/index.tsx | 210 +-------- .../components/take_action_dropdown/index.tsx | 2 +- .../components/graph_overlay/index.tsx | 7 +- .../public/components/t_grid/helpers.test.tsx | 22 +- .../public/components/t_grid/helpers.tsx | 25 +- .../t_grid/integrated/index.test.tsx | 3 - .../components/t_grid/integrated/index.tsx | 51 +-- .../components/t_grid/standalone/index.tsx | 48 +- .../translations/translations/fr-FR.json | 7 - .../translations/translations/ja-JP.json | 7 - .../translations/translations/zh-CN.json | 7 - 19 files changed, 259 insertions(+), 1134 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.test.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/translations.ts delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/translations.ts diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx index 0556b3678d4db..14921512819ee 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx @@ -61,7 +61,6 @@ export interface Props { onRuleChange?: () => void; renderCellValue: (props: CellValueElementProps) => React.ReactNode; rowRenderers: RowRenderer[]; - utilityBar?: (refetch: inputsModel.Refetch, totalCount: number) => React.ReactNode; additionalFilters?: React.ReactNode; hasAlertsCrud?: boolean; unit?: (n: number) => string; @@ -86,7 +85,6 @@ const StatefulEventsViewerComponent: React.FC = ({ rowRenderers, start, scopeId, - utilityBar, additionalFilters, hasAlertsCrud = false, unit, diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.test.tsx new file mode 100644 index 0000000000000..ec4fdb5cb6e8d --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.test.tsx @@ -0,0 +1,80 @@ +/* + * 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, fireEvent } from '@testing-library/react'; + +import { AdditionalFiltersAction } from '.'; +import { TestProviders } from '../../../../common/mock/test_providers'; + +jest.useFakeTimers(); +jest.mock('../../../../common/lib/kibana'); + +describe('AdditionalFiltersAction', () => { + describe('UtilityBarAdditionalFiltersContent', () => { + test('does not show the showBuildingBlockAlerts checked if the showBuildingBlockAlerts is false', async () => { + const onShowBuildingBlockAlertsChanged = jest.fn(); + render( + + + + ); + // click the filters button to popup the checkbox to make it visible + const additionalFiltersButton = screen.findByTestId('additionalFilters-popover'); + fireEvent.click(await additionalFiltersButton); + + // The check box should be false + expect(await screen.findByTestId('showBuildingBlockAlertsCheckbox')).not.toBeChecked(); + }); + + test('does not show the showOnlyThreatIndicatorAlerts checked if the showOnlyThreatIndicatorAlerts is true', async () => { + render( + + + + ); + // click the filters button to popup the checkbox to make it visible + const additionalFiltersButton = screen.findByTestId('additionalFilters-popover'); + fireEvent.click(await additionalFiltersButton); + + expect(await screen.findByTestId('showOnlyThreatIndicatorAlertsCheckbox')).toBeChecked(); + }); + + test('does show the showBuildingBlockAlerts checked if the showBuildingBlockAlerts is true', async () => { + const onShowBuildingBlockAlertsChanged = jest.fn(); + render( + + + + ); + // click the filters button to popup the checkbox to make it visible + const additionalFiltersButton = screen.findByTestId('additionalFilters-popover'); + fireEvent.click(await additionalFiltersButton); + + // The check box should be true + expect(await screen.findByTestId('showBuildingBlockAlertsCheckbox')).toBeChecked(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.tsx new file mode 100644 index 0000000000000..ef780f783e924 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.tsx @@ -0,0 +1,94 @@ +/* + * 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, { useCallback } from 'react'; + +import { EuiFlexGroup, EuiFlexItem, EuiCheckbox } from '@elastic/eui'; +import styled from 'styled-components'; + +import { UtilityBarAction } from '../../../../common/components/utility_bar'; +import * as i18n from './translations'; + +const UtilityBarFlexGroup = styled(EuiFlexGroup)` + min-width: 175px; +`; + +const AdditionalFiltersItem = styled(EuiFlexItem)` + padding: ${({ theme }) => theme.eui.euiSizeS}; +`; + +const BuildingBlockContainer = styled(AdditionalFiltersItem)` + background: ${({ theme }) => theme.eui.euiColorHighlight}; +`; + +export const AdditionalFiltersAction = ({ + areEventsLoading, + onShowBuildingBlockAlertsChanged, + showBuildingBlockAlerts, + onShowOnlyThreatIndicatorAlertsChanged, + showOnlyThreatIndicatorAlerts, +}: { + areEventsLoading: boolean; + onShowBuildingBlockAlertsChanged: (showBuildingBlockAlerts: boolean) => void; + showBuildingBlockAlerts: boolean; + onShowOnlyThreatIndicatorAlertsChanged: (showOnlyThreatIndicatorAlerts: boolean) => void; + showOnlyThreatIndicatorAlerts: boolean; +}) => { + const UtilityBarAdditionalFiltersContent = useCallback( + (closePopover: () => void) => ( + + + ) => { + closePopover(); + onShowBuildingBlockAlertsChanged(e.target.checked); + }} + checked={showBuildingBlockAlerts} + color="text" + data-test-subj="showBuildingBlockAlertsCheckbox" + label={i18n.ADDITIONAL_FILTERS_ACTIONS_SHOW_BUILDING_BLOCK} + /> + + + ) => { + closePopover(); + onShowOnlyThreatIndicatorAlertsChanged(e.target.checked); + }} + checked={showOnlyThreatIndicatorAlerts} + color="text" + data-test-subj="showOnlyThreatIndicatorAlertsCheckbox" + label={i18n.ADDITIONAL_FILTERS_ACTIONS_SHOW_ONLY_THREAT_INDICATOR_ALERTS} + /> + + + ), + [ + onShowBuildingBlockAlertsChanged, + onShowOnlyThreatIndicatorAlertsChanged, + showBuildingBlockAlerts, + showOnlyThreatIndicatorAlerts, + ] + ); + + return ( + + {i18n.ADDITIONAL_FILTERS_ACTIONS} + + ); +}; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/translations.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/translations.ts new file mode 100644 index 0000000000000..eb421c67ff39a --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/translations.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const ADDITIONAL_FILTERS_ACTIONS = i18n.translate( + 'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersTitle', + { + defaultMessage: 'Additional filters', + } +); + +export const ADDITIONAL_FILTERS_ACTIONS_SHOW_BUILDING_BLOCK = i18n.translate( + 'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showBuildingBlockTitle', + { + defaultMessage: 'Include building block alerts', + } +); + +export const ADDITIONAL_FILTERS_ACTIONS_SHOW_ONLY_THREAT_INDICATOR_ALERTS = i18n.translate( + 'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showOnlyThreatIndicatorAlerts', + { + defaultMessage: 'Show only threat indicator alerts', + } +); + +export const TAKE_ACTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.alerts.utilityBar.takeActionTitle', + { + defaultMessage: 'Take action', + } +); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.test.tsx deleted file mode 100644 index f4372631cf0f4..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.test.tsx +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { shallow, mount } from 'enzyme'; - -import type { AlertsUtilityBarProps } from '.'; -import { AlertsUtilityBar } from '.'; -import { TestProviders } from '../../../../common/mock/test_providers'; - -jest.useFakeTimers(); -jest.mock('../../../../common/lib/kibana'); - -describe('AlertsUtilityBar', () => { - test('renders correctly', () => { - const wrapper = shallow( - - ); - - expect(wrapper.find('[dataTestSubj="alertActionPopover"]')).toBeTruthy(); - }); - - describe('UtilityBarAdditionalFiltersContent', () => { - test('does not show the showBuildingBlockAlerts checked if the showBuildingBlockAlerts is false', () => { - const onShowBuildingBlockAlertsChanged = jest.fn(); - const wrapper = mount( - - - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should be false - expect( - wrapper - .find('[data-test-subj="showBuildingBlockAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(false); - }); - - test('does not show the showOnlyThreatIndicatorAlerts checked if the showThreatMatchOnly is false', () => { - const wrapper = mount( - - - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should be false - expect( - wrapper - .find('[data-test-subj="showOnlyThreatIndicatorAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(false); - }); - - test('does show the showBuildingBlockAlerts checked if the showBuildingBlockAlerts is true', () => { - const onShowBuildingBlockAlertsChanged = jest.fn(); - const wrapper = mount( - - - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should be true - expect( - wrapper - .find('[data-test-subj="showBuildingBlockAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(true); - }); - - test('does show the showOnlyThreatIndicatorAlerts checked if the showOnlyThreatIndicatorAlerts is true', () => { - const wrapper = mount( - - - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should be true - expect( - wrapper - .find('[data-test-subj="showOnlyThreatIndicatorAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(true); - }); - - test('calls the onShowBuildingBlockAlertsChanged when the check box is clicked', () => { - const onShowBuildingBlockAlertsChanged = jest.fn(); - const wrapper = mount( - - - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // check the box - wrapper - .find('[data-test-subj="showBuildingBlockAlertsCheckbox"] input') - .first() - .simulate('change', { target: { checked: true } }); - - // Make sure our callback is called - expect(onShowBuildingBlockAlertsChanged).toHaveBeenCalled(); - }); - - test('calls the onShowOnlyThreatIndicatorAlertsChanged when the check box is clicked', () => { - const onShowOnlyThreatIndicatorAlertsChanged = jest.fn(); - const wrapper = mount( - - - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // check the box - wrapper - .find('[data-test-subj="showOnlyThreatIndicatorAlertsCheckbox"] input') - .first() - .simulate('change', { target: { checked: true } }); - - // Make sure our callback is called - expect(onShowOnlyThreatIndicatorAlertsChanged).toHaveBeenCalled(); - }); - - test('can update showBuildingBlockAlerts from false to true', () => { - const Proxy = (props: AlertsUtilityBarProps) => ( - - - - ); - - const wrapper = mount( - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should false now since we initially set the showBuildingBlockAlerts to false - expect( - wrapper - .find('[data-test-subj="showBuildingBlockAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(false); - - wrapper.setProps({ showBuildingBlockAlerts: true }); - wrapper.update(); - - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should be true now since we changed the showBuildingBlockAlerts from false to true - expect( - wrapper - .find('[data-test-subj="showBuildingBlockAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(true); - }); - - test('can update showOnlyThreatIndicatorAlerts from false to true', () => { - const Proxy = (props: AlertsUtilityBarProps) => ( - - - - ); - - const wrapper = mount( - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should false now since we initially set the showBuildingBlockAlerts to false - expect( - wrapper - .find('[data-test-subj="showOnlyThreatIndicatorAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(false); - - wrapper.setProps({ showOnlyThreatIndicatorAlerts: true }); - wrapper.update(); - - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should be true now since we changed the showBuildingBlockAlerts from false to true - expect( - wrapper - .find('[data-test-subj="showOnlyThreatIndicatorAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(true); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.tsx deleted file mode 100644 index 91425ab90e60b..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.tsx +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { isEmpty } from 'lodash/fp'; -import React, { useCallback } from 'react'; -import numeral from '@elastic/numeral'; - -import { EuiFlexGroup, EuiFlexItem, EuiCheckbox } from '@elastic/eui'; -import styled from 'styled-components'; - -import type { Status } from '../../../../../common/detection_engine/schemas/common/schemas'; -import { Link } from '../../../../common/components/link_icon'; -import { DEFAULT_NUMBER_FORMAT } from '../../../../../common/constants'; -import { - UtilityBar, - UtilityBarAction, - UtilityBarGroup, - UtilityBarSection, - UtilityBarSpacer, - UtilityBarText, -} from '../../../../common/components/utility_bar'; -import * as i18n from './translations'; -import { useUiSetting$ } from '../../../../common/lib/kibana'; -import type { TimelineNonEcsData } from '../../../../../common/search_strategy/timeline'; -import type { UpdateAlertsStatus } from '../types'; -import { FILTER_CLOSED, FILTER_ACKNOWLEDGED, FILTER_OPEN } from '../alerts_filter_group'; - -export interface AlertsUtilityBarProps { - areEventsLoading: boolean; - clearSelection: () => void; - currentFilter: Status; - hasIndexMaintenance: boolean; - hasIndexWrite: boolean; - onShowBuildingBlockAlertsChanged: (showBuildingBlockAlerts: boolean) => void; - onShowOnlyThreatIndicatorAlertsChanged: (showOnlyThreatIndicatorAlerts: boolean) => void; - selectAll: () => void; - selectedEventIds: Readonly>; - showBuildingBlockAlerts: boolean; - showClearSelection: boolean; - showOnlyThreatIndicatorAlerts: boolean; - totalCount: number; - updateAlertsStatus: UpdateAlertsStatus; -} - -const UtilityBarFlexGroup = styled(EuiFlexGroup)` - min-width: 175px; -`; - -const AdditionalFiltersItem = styled(EuiFlexItem)` - padding: ${({ theme }) => theme.eui.euiSizeS}; -`; - -const BuildingBlockContainer = styled(AdditionalFiltersItem)` - background: ${({ theme }) => theme.eui.euiColorHighlight}; -`; - -const AlertsUtilityBarComponent: React.FC = ({ - areEventsLoading, - clearSelection, - currentFilter, - hasIndexMaintenance, - hasIndexWrite, - onShowBuildingBlockAlertsChanged, - onShowOnlyThreatIndicatorAlertsChanged, - selectAll, - selectedEventIds, - showBuildingBlockAlerts, - showClearSelection, - showOnlyThreatIndicatorAlerts, - totalCount, - updateAlertsStatus, -}) => { - const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); - - const handleUpdateStatus = useCallback( - async (selectedStatus: Status) => { - await updateAlertsStatus({ - alertIds: Object.keys(selectedEventIds), - status: currentFilter, - selectedStatus, - }); - }, - [currentFilter, selectedEventIds, updateAlertsStatus] - ); - - const formattedTotalCount = numeral(totalCount).format(defaultNumberFormat); - const formattedSelectedEventsCount = numeral(Object.keys(selectedEventIds).length).format( - defaultNumberFormat - ); - - const UtilityBarPopoverContent = (closePopover: () => void) => ( - - {currentFilter !== FILTER_OPEN && ( - - { - closePopover(); - handleUpdateStatus('open'); - }} - color="text" - data-test-subj="openSelectedAlertsButton" - > - {i18n.BATCH_ACTION_OPEN_SELECTED} - - - )} - - {currentFilter !== FILTER_CLOSED && ( - - { - closePopover(); - handleUpdateStatus('closed'); - }} - color="text" - data-test-subj="closeSelectedAlertsButton" - > - {i18n.BATCH_ACTION_CLOSE_SELECTED} - - - )} - - {currentFilter !== FILTER_ACKNOWLEDGED && ( - - { - closePopover(); - handleUpdateStatus('acknowledged'); - }} - color="text" - data-test-subj="markSelectedAlertsAcknowledgedButton" - > - {i18n.BATCH_ACTION_ACKNOWLEDGED_SELECTED} - - - )} - - ); - - const handleSelectAllAlertsClick = useCallback(() => { - if (!showClearSelection) { - selectAll(); - } else { - clearSelection(); - } - }, [clearSelection, selectAll, showClearSelection]); - - return ( - <> - - - - - {i18n.SHOWING_ALERTS(formattedTotalCount, totalCount)} - - - - - {hasIndexWrite && hasIndexMaintenance && ( - <> - - {i18n.SELECTED_ALERTS( - showClearSelection ? formattedTotalCount : formattedSelectedEventsCount, - showClearSelection ? totalCount : Object.keys(selectedEventIds).length - )} - - - - {i18n.TAKE_ACTION} - - - - {showClearSelection - ? i18n.CLEAR_SELECTION - : i18n.SELECT_ALL_ALERTS(formattedTotalCount, totalCount)} - - - )} - - - - - - - ); -}; - -export const AlertsUtilityBar = React.memo( - AlertsUtilityBarComponent, - (prevProps, nextProps) => - prevProps.areEventsLoading === nextProps.areEventsLoading && - prevProps.selectedEventIds === nextProps.selectedEventIds && - prevProps.totalCount === nextProps.totalCount && - prevProps.showClearSelection === nextProps.showClearSelection && - prevProps.showBuildingBlockAlerts === nextProps.showBuildingBlockAlerts && - prevProps.showOnlyThreatIndicatorAlerts === nextProps.showOnlyThreatIndicatorAlerts -); - -export const AditionalFiltersAction = ({ - areEventsLoading, - onShowBuildingBlockAlertsChanged, - showBuildingBlockAlerts, - onShowOnlyThreatIndicatorAlertsChanged, - showOnlyThreatIndicatorAlerts, -}: { - areEventsLoading: boolean; - onShowBuildingBlockAlertsChanged: (showBuildingBlockAlerts: boolean) => void; - showBuildingBlockAlerts: boolean; - onShowOnlyThreatIndicatorAlertsChanged: (showOnlyThreatIndicatorAlerts: boolean) => void; - showOnlyThreatIndicatorAlerts: boolean; -}) => { - const UtilityBarAdditionalFiltersContent = (closePopover: () => void) => ( - - - ) => { - closePopover(); - onShowBuildingBlockAlertsChanged(e.target.checked); - }} - checked={showBuildingBlockAlerts} - color="text" - data-test-subj="showBuildingBlockAlertsCheckbox" - label={i18n.ADDITIONAL_FILTERS_ACTIONS_SHOW_BUILDING_BLOCK} - /> - - - ) => { - closePopover(); - onShowOnlyThreatIndicatorAlertsChanged(e.target.checked); - }} - checked={showOnlyThreatIndicatorAlerts} - color="text" - data-test-subj="showOnlyThreatIndicatorAlertsCheckbox" - label={i18n.ADDITIONAL_FILTERS_ACTIONS_SHOW_ONLY_THREAT_INDICATOR_ALERTS} - /> - - - ); - - return ( - - {i18n.ADDITIONAL_FILTERS_ACTIONS} - - ); -}; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/translations.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/translations.ts deleted file mode 100644 index 5da63a5ab9598..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/translations.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const SHOWING_ALERTS = (totalAlertsFormatted: string, totalAlerts: number) => - i18n.translate('xpack.securitySolution.detectionEngine.alerts.utilityBar.showingAlertsTitle', { - values: { totalAlertsFormatted, totalAlerts }, - defaultMessage: - 'Showing {totalAlertsFormatted} {totalAlerts, plural, =1 {alert} other {alerts}}', - }); - -export const SELECTED_ALERTS = (selectedAlertsFormatted: string, selectedAlerts: number) => - i18n.translate('xpack.securitySolution.detectionEngine.alerts.utilityBar.selectedAlertsTitle', { - values: { selectedAlertsFormatted, selectedAlerts }, - defaultMessage: - 'Selected {selectedAlertsFormatted} {selectedAlerts, plural, =1 {alert} other {alerts}}', - }); - -export const SELECT_ALL_ALERTS = (totalAlertsFormatted: string, totalAlerts: number) => - i18n.translate('xpack.securitySolution.detectionEngine.alerts.utilityBar.selectAllAlertsTitle', { - values: { totalAlertsFormatted, totalAlerts }, - defaultMessage: - 'Select all {totalAlertsFormatted} {totalAlerts, plural, =1 {alert} other {alerts}}', - }); - -export const ADDITIONAL_FILTERS_ACTIONS = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersTitle', - { - defaultMessage: 'Additional filters', - } -); - -export const ADDITIONAL_FILTERS_ACTIONS_SHOW_BUILDING_BLOCK = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showBuildingBlockTitle', - { - defaultMessage: 'Include building block alerts', - } -); - -export const ADDITIONAL_FILTERS_ACTIONS_SHOW_ONLY_THREAT_INDICATOR_ALERTS = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showOnlyThreatIndicatorAlerts', - { - defaultMessage: 'Show only threat indicator alerts', - } -); - -export const CLEAR_SELECTION = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.clearSelectionTitle', - { - defaultMessage: 'Clear selection', - } -); - -export const TAKE_ACTION = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.takeActionTitle', - { - defaultMessage: 'Take action', - } -); - -export const BATCH_ACTION_OPEN_SELECTED = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.openSelectedTitle', - { - defaultMessage: 'Open selected', - } -); - -export const BATCH_ACTION_CLOSE_SELECTED = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.closeSelectedTitle', - { - defaultMessage: 'Close selected', - } -); - -export const BATCH_ACTION_ACKNOWLEDGED_SELECTED = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.acknowledgedSelectedTitle', - { - defaultMessage: 'Mark as acknowledged', - } -); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.test.tsx index 304f0ac180821..34378594a952d 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.test.tsx @@ -33,13 +33,11 @@ describe('AlertsTableComponent', () => { loadingEventIds={[]} selectedEventIds={{}} isSelectAllChecked={false} - clearSelected={jest.fn()} - setEventsLoading={jest.fn()} - setEventsDeleted={jest.fn()} showBuildingBlockAlerts={false} onShowBuildingBlockAlertsChanged={jest.fn()} showOnlyThreatIndicatorAlerts={false} onShowOnlyThreatIndicatorAlertsChanged={jest.fn()} + dispatch={jest.fn()} /> ); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx index 9c11f4499db95..d4dead20989a6 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx @@ -6,22 +6,15 @@ */ import { isEmpty } from 'lodash/fp'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo } from 'react'; import type { ConnectedProps } from 'react-redux'; import { connect, useDispatch } from 'react-redux'; -import type { Dispatch } from 'redux'; import type { Filter } from '@kbn/es-query'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; import type { Status } from '../../../../common/detection_engine/schemas/common/schemas'; import type { RowRendererId, TimelineIdLiteral } from '../../../../common/types/timeline'; import { StatefulEventsViewer } from '../../../common/components/events_viewer'; -import { - displayErrorToast, - displaySuccessToast, - useStateToaster, -} from '../../../common/components/toasters'; import { useSourcererDataView } from '../../../common/containers/sourcerer'; -import { useAppToasts } from '../../../common/hooks/use_app_toasts'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { useInvalidFilterQuery } from '../../../common/hooks/use_invalid_filter_query'; import { defaultCellActions } from '../../../common/lib/cell_actions/default_cell_actions'; @@ -29,7 +22,6 @@ import { useKibana } from '../../../common/lib/kibana'; import type { inputsModel, State } from '../../../common/store'; import { inputsSelectors } from '../../../common/store'; import { SourcererScopeName } from '../../../common/store/sourcerer/model'; -import * as i18nCommon from '../../../common/translations'; import { DEFAULT_COLUMN_MIN_WIDTH } from '../../../timelines/components/timeline/body/constants'; import { getDefaultControlColumn } from '../../../timelines/components/timeline/body/control_columns'; import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; @@ -38,8 +30,7 @@ import { timelineActions, timelineSelectors } from '../../../timelines/store/tim import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import type { TimelineModel } from '../../../timelines/store/timeline/model'; import { columns, RenderCellValue } from '../../configurations/security_solution_detections'; -import { updateAlertStatusAction } from './actions'; -import { AditionalFiltersAction, AlertsUtilityBar } from './alerts_utility_bar'; +import { AdditionalFiltersAction } from './additional_filters_action'; import { alertsDefaultModel, buildAlertStatusFilter, @@ -47,13 +38,6 @@ import { } from './default_config'; import { buildTimeRangeFilter } from './helpers'; import * as i18n from './translations'; -import type { - SetEventsDeletedProps, - SetEventsLoadingProps, - UpdateAlertsStatusCallback, - UpdateAlertsStatusProps, -} from './types'; - interface OwnProps { defaultFilters?: Filter[]; from: string; @@ -73,7 +57,6 @@ interface OwnProps { type AlertsTableComponentProps = OwnProps & PropsFromRedux; export const AlertsTableComponent: React.FC = ({ - clearSelected, defaultFilters, from, globalFilters, @@ -86,9 +69,6 @@ export const AlertsTableComponent: React.FC = ({ onRuleChange, onShowBuildingBlockAlertsChanged, onShowOnlyThreatIndicatorAlertsChanged, - selectedEventIds, - setEventsDeleted, - setEventsLoading, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts, timelineId, @@ -96,15 +76,12 @@ export const AlertsTableComponent: React.FC = ({ filterGroup = 'open', }) => { const dispatch = useDispatch(); - const [showClearSelectionAction, setShowClearSelectionAction] = useState(false); const { browserFields, indexPattern: indexPatterns, selectedPatterns, } = useSourcererDataView(SourcererScopeName.detections); const kibana = useKibana(); - const [, dispatchToaster] = useStateToaster(); - const { addWarning } = useAppToasts(); const ACTION_BUTTON_COUNT = 5; const getGlobalQuery = useCallback( @@ -123,7 +100,6 @@ export const AlertsTableComponent: React.FC = ({ ], kqlQuery: globalQuery, kqlMode: globalQuery.language, - isEventViewer: true, }); } return null; @@ -140,66 +116,6 @@ export const AlertsTableComponent: React.FC = ({ endDate: to, }); - const setEventsLoadingCallback = useCallback( - ({ eventIds, isLoading }: SetEventsLoadingProps) => { - setEventsLoading({ id: timelineId, eventIds, isLoading }); - }, - [setEventsLoading, timelineId] - ); - - const setEventsDeletedCallback = useCallback( - ({ eventIds, isDeleted }: SetEventsDeletedProps) => { - setEventsDeleted({ id: timelineId, eventIds, isDeleted }); - }, - [setEventsDeleted, timelineId] - ); - - const onAlertStatusUpdateSuccess = useCallback( - (updated: number, conflicts: number, status: Status) => { - if (conflicts > 0) { - // Partial failure - addWarning({ - title: i18nCommon.UPDATE_ALERT_STATUS_FAILED(conflicts), - text: i18nCommon.UPDATE_ALERT_STATUS_FAILED_DETAILED(updated, conflicts), - }); - } else { - let title = ''; - switch (status) { - case 'closed': - title = i18n.CLOSED_ALERT_SUCCESS_TOAST(updated); - break; - case 'open': - title = i18n.OPENED_ALERT_SUCCESS_TOAST(updated); - break; - case 'acknowledged': - case 'in-progress': - title = i18n.ACKNOWLEDGED_ALERT_SUCCESS_TOAST(updated); - } - displaySuccessToast(title, dispatchToaster); - } - }, - [addWarning, dispatchToaster] - ); - - const onAlertStatusUpdateFailure = useCallback( - (status: Status, error: Error) => { - let title = ''; - switch (status) { - case 'closed': - title = i18n.CLOSED_ALERT_FAILED_TOAST; - break; - case 'open': - title = i18n.OPENED_ALERT_FAILED_TOAST; - break; - case 'acknowledged': - case 'in-progress': - title = i18n.ACKNOWLEDGED_ALERT_FAILED_TOAST; - } - displayErrorToast(title, [error.message], dispatchToaster); - }, - [dispatchToaster] - ); - // Catches state change isSelectAllChecked->false upon user selection change to reset utility bar useEffect(() => { if (isSelectAllChecked) { @@ -209,107 +125,12 @@ export const AlertsTableComponent: React.FC = ({ selectAll: false, }) ); - } else { - setShowClearSelectionAction(false); } }, [dispatch, isSelectAllChecked, timelineId]); - // Callback for clearing entire selection from utility bar - const clearSelectionCallback = useCallback(() => { - clearSelected({ id: timelineId }); - dispatch( - timelineActions.setTGridSelectAll({ - id: timelineId, - selectAll: false, - }) - ); - setShowClearSelectionAction(false); - }, [clearSelected, dispatch, timelineId]); - - // Callback for selecting all events on all pages from utility bar - // Dispatches to stateful_body's selectAll via TimelineTypeContext props - // as scope of response data required to actually set selectedEvents - const selectAllOnAllPagesCallback = useCallback(() => { - dispatch( - timelineActions.setTGridSelectAll({ - id: timelineId, - selectAll: true, - }) - ); - setShowClearSelectionAction(true); - }, [dispatch, timelineId]); - - const updateAlertsStatusCallback: UpdateAlertsStatusCallback = useCallback( - async ( - refetchQuery: inputsModel.Refetch, - { status, selectedStatus }: UpdateAlertsStatusProps - ) => { - await updateAlertStatusAction({ - query: showClearSelectionAction - ? getGlobalQuery(buildAlertStatusFilter(status))?.filterQuery - : undefined, - alertIds: Object.keys(selectedEventIds), - selectedStatus, - setEventsDeleted: setEventsDeletedCallback, - setEventsLoading: setEventsLoadingCallback, - onAlertStatusUpdateSuccess, - onAlertStatusUpdateFailure, - }); - refetchQuery(); - }, - [ - getGlobalQuery, - selectedEventIds, - setEventsDeletedCallback, - setEventsLoadingCallback, - showClearSelectionAction, - onAlertStatusUpdateSuccess, - onAlertStatusUpdateFailure, - ] - ); - - // Callback for creating the AlertsUtilityBar which receives totalCount from EventsViewer component - const utilityBarCallback = useCallback( - (refetchQuery: inputsModel.Refetch, totalCount: number) => { - return ( - 0} - clearSelection={clearSelectionCallback} - currentFilter={filterGroup} - hasIndexMaintenance={hasIndexMaintenance} - hasIndexWrite={hasIndexWrite} - onShowBuildingBlockAlertsChanged={onShowBuildingBlockAlertsChanged} - onShowOnlyThreatIndicatorAlertsChanged={onShowOnlyThreatIndicatorAlertsChanged} - selectAll={selectAllOnAllPagesCallback} - selectedEventIds={selectedEventIds} - showBuildingBlockAlerts={showBuildingBlockAlerts} - showClearSelection={showClearSelectionAction} - showOnlyThreatIndicatorAlerts={showOnlyThreatIndicatorAlerts} - totalCount={totalCount} - updateAlertsStatus={updateAlertsStatusCallback.bind(null, refetchQuery)} - /> - ); - }, - [ - clearSelectionCallback, - filterGroup, - hasIndexMaintenance, - hasIndexWrite, - loadingEventIds.length, - onShowBuildingBlockAlertsChanged, - onShowOnlyThreatIndicatorAlertsChanged, - selectAllOnAllPagesCallback, - selectedEventIds, - showBuildingBlockAlerts, - showClearSelectionAction, - showOnlyThreatIndicatorAlerts, - updateAlertsStatusCallback, - ] - ); - const additionalFiltersComponent = useMemo( () => ( - 0} onShowBuildingBlockAlertsChanged={onShowBuildingBlockAlertsChanged} showBuildingBlockAlerts={showBuildingBlockAlerts} @@ -387,7 +208,6 @@ export const AlertsTableComponent: React.FC = ({ rowRenderers={defaultRowRenderers} scopeId={SourcererScopeName.detections} start={from} - utilityBar={utilityBarCallback} /> ); }; @@ -414,29 +234,7 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -const mapDispatchToProps = (dispatch: Dispatch) => ({ - clearSelected: ({ id }: { id: string }) => dispatch(timelineActions.clearSelected({ id })), - setEventsLoading: ({ - id, - eventIds, - isLoading, - }: { - id: string; - eventIds: string[]; - isLoading: boolean; - }) => dispatch(timelineActions.setEventsLoading({ id, eventIds, isLoading })), - setEventsDeleted: ({ - id, - eventIds, - isDeleted, - }: { - id: string; - eventIds: string[]; - isDeleted: boolean; - }) => dispatch(timelineActions.setEventsDeleted({ id, eventIds, isDeleted })), -}); - -const connector = connect(makeMapStateToProps, mapDispatchToProps); +const connector = connect(makeMapStateToProps); type PropsFromRedux = ConnectedProps; diff --git a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx index ea66ebb132d8a..197d655d2420b 100644 --- a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx @@ -10,7 +10,7 @@ import { EuiButton, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types'; import { useResponderActionItem } from '../endpoint_responder'; import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy'; -import { TAKE_ACTION } from '../alerts_table/alerts_utility_bar/translations'; +import { TAKE_ACTION } from '../alerts_table/additional_filters_action/translations'; import { useExceptionActions } from '../alerts_table/timeline_actions/use_add_exception_actions'; import { useAlertsActions } from '../alerts_table/timeline_actions/use_alerts_actions'; import { useInvestigateInTimeline } from '../alerts_table/timeline_actions/use_investigate_in_timeline'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx index 6ecaa56bc12db..681de8ac4cb0c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx @@ -84,11 +84,8 @@ const GraphOverlayComponent: React.FC = ({ const { timelineFullScreen } = useTimelineFullScreen(); const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); - const graphEventId = useDeepEqualSelector( - (state) => (getTimeline(state, timelineId) ?? timelineDefaults).graphEventId - ); - const sessionViewConfig = useDeepEqualSelector( - (state) => (getTimeline(state, timelineId) ?? timelineDefaults).sessionViewConfig + const { graphEventId, sessionViewConfig } = useDeepEqualSelector( + (state) => getTimeline(state, timelineId) ?? timelineDefaults ); const fullScreen = useMemo( diff --git a/x-pack/plugins/timelines/public/components/t_grid/helpers.test.tsx b/x-pack/plugins/timelines/public/components/t_grid/helpers.test.tsx index 535c856d51e8f..7d60cbc5d0e00 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/helpers.test.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/helpers.test.tsx @@ -225,7 +225,7 @@ describe('Combined Queries', () => { ignoreFilterIfFieldNotInIndex: true, dateFormatTZ: 'America/New_York', }; - test('No Data Provider & No kqlQuery & and isEventViewer is false', () => { + test('No Data Provider & No kqlQuery', () => { expect( combineQueries({ config, @@ -239,26 +239,7 @@ describe('Combined Queries', () => { ).toBeNull(); }); - test('No Data Provider & No kqlQuery & isEventViewer is true', () => { - const isEventViewer = true; - expect( - combineQueries({ - config, - dataProviders: [], - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - isEventViewer, - }) - ).toEqual({ - filterQuery: '{"bool":{"must":[],"filter":[],"should":[],"must_not":[]}}', - }); - }); - test('No Data Provider & No kqlQuery & with Filters', () => { - const isEventViewer = true; expect( combineQueries({ config, @@ -293,7 +274,6 @@ describe('Combined Queries', () => { ], kqlQuery: { query: '', language: 'kuery' }, kqlMode: 'search', - isEventViewer, }) ).toEqual({ filterQuery: diff --git a/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx b/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx index 03830339761bc..34fb215e708d5 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx @@ -141,7 +141,6 @@ interface CombineQueries { filters: Filter[]; kqlQuery: Query; kqlMode: string; - isEventViewer?: boolean; } export const combineQueries = ({ @@ -152,23 +151,10 @@ export const combineQueries = ({ filters = [], kqlQuery, kqlMode, - isEventViewer, }: CombineQueries): { filterQuery: string | undefined; kqlError: Error | undefined } | null => { const kuery: Query = { query: '', language: kqlQuery.language }; - if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters) && !isEventViewer) { + if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters)) { return null; - } else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEventViewer) { - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); - - return { - filterQuery, - kqlError, - }; } else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && !isEmpty(filters)) { const [filterQuery, kqlError] = convertToBuildEsQuery({ config, @@ -229,15 +215,6 @@ export const combineQueries = ({ }; }; -export const buildCombinedQuery = (combineQueriesParams: CombineQueries) => { - const combinedQuery = combineQueries(combineQueriesParams); - return combinedQuery?.filterQuery - ? { - filterQuery: combinedQuery.filterQuery, - } - : null; -}; - export const buildTimeRangeFilter = (from: string, to: string): Filter => ({ range: { diff --git a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.test.tsx b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.test.tsx index 15fd4d2ce75cf..d33d2fb5635b8 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.test.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.test.tsx @@ -41,9 +41,6 @@ jest.mock('../helpers', () => { filter: [], }, }), - buildCombinedQuery: () => ({ - filterQuery: '{"bool":{"must":[],"filter":[]}}', - }), }; }); const defaultProps: TGridIntegratedProps = tGridIntegratedProps; diff --git a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx index 7183c164a24be..898611d073a95 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx @@ -39,7 +39,7 @@ import type { import { useDeepEqualSelector } from '../../../hooks/use_selector'; import { defaultHeaders } from '../body/column_headers/default_headers'; -import { buildCombinedQuery, getCombinedFilterQuery, resolverIsShowing } from '../helpers'; +import { getCombinedFilterQuery, resolverIsShowing } from '../helpers'; import { tGridActions, tGridSelectors } from '../../../store/t_grid'; import { useTimelineEvents, InspectResponse, Refetch } from '../../../container'; import { StatefulBody } from '../body'; @@ -194,26 +194,32 @@ const TGridIntegratedComponent: React.FC = ({ }, [dispatch, id, isQueryLoading]); const justTitle = useMemo(() => {title}, [title]); + const esQueryConfig = getEsQueryConfig(uiSettings); - const combinedQueries = buildCombinedQuery({ - config: getEsQueryConfig(uiSettings), - dataProviders, - indexPattern, - browserFields, - filters, - kqlQuery: query, - kqlMode, - isEventViewer: true, - }); + const filterQuery = useMemo( + () => + getCombinedFilterQuery({ + config: esQueryConfig, + browserFields, + dataProviders, + filters, + from: start, + indexPattern, + kqlMode, + kqlQuery: query, + to: end, + }), + [esQueryConfig, dataProviders, indexPattern, browserFields, filters, start, end, query, kqlMode] + ); const canQueryTimeline = useMemo( () => - combinedQueries != null && + filterQuery != null && isLoadingIndexPattern != null && !isLoadingIndexPattern && !isEmpty(start) && !isEmpty(end), - [isLoadingIndexPattern, combinedQueries, start, end] + [isLoadingIndexPattern, filterQuery, start, end] ); const fields = useMemo( @@ -241,7 +247,7 @@ const TGridIntegratedComponent: React.FC = ({ endDate: end, entityType, fields, - filterQuery: combinedQueries?.filterQuery, + filterQuery, id, indexNames, limit: itemsPerPage, @@ -251,23 +257,6 @@ const TGridIntegratedComponent: React.FC = ({ startDate: start, }); - const filterQuery = useMemo( - () => - getCombinedFilterQuery({ - config: getEsQueryConfig(uiSettings), - browserFields, - dataProviders, - filters, - from: start, - indexPattern, - isEventViewer: true, - kqlMode, - kqlQuery: query, - to: end, - }), - [uiSettings, dataProviders, indexPattern, browserFields, filters, start, end, query, kqlMode] - ); - const totalCountMinusDeleted = useMemo( () => (totalCount > 0 ? totalCount - deletedEventIds.length : 0), [deletedEventIds.length, totalCount] diff --git a/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx index 1eb327d95827a..14a03e8bd5049 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx @@ -30,7 +30,7 @@ import type { } from '../../../../common/types/timeline'; import { useDeepEqualSelector } from '../../../hooks/use_selector'; import { defaultHeaders } from '../body/column_headers/default_headers'; -import { combineQueries, getCombinedFilterQuery } from '../helpers'; +import { getCombinedFilterQuery } from '../helpers'; import { tGridActions, tGridSelectors } from '../../../store/t_grid'; import type { State } from '../../../store/t_grid'; import { useTimelineEvents } from '../../../container'; @@ -170,25 +170,32 @@ const TGridStandaloneComponent: React.FC = ({ }, [dispatch, isQueryLoading]); const justTitle = useMemo(() => {title}, [title]); + const esQueryConfig = getEsQueryConfig(uiSettings); - const combinedQueries = useMemo( + const filterQuery = useMemo( () => - combineQueries({ - config: getEsQueryConfig(uiSettings), - dataProviders: EMPTY_DATA_PROVIDERS, - indexPattern: indexPatterns, + getCombinedFilterQuery({ + config: esQueryConfig, browserFields, + dataProviders: EMPTY_DATA_PROVIDERS, filters, - kqlQuery: query, + from: start, + indexPattern: indexPatterns, kqlMode: 'search', - isEventViewer: true, + kqlQuery: query, + to: end, }), - [uiSettings, indexPatterns, browserFields, filters, query] + [esQueryConfig, indexPatterns, browserFields, filters, start, end, query] ); const canQueryTimeline = useMemo( - () => !indexPatternsLoading && combinedQueries != null && !isEmpty(start) && !isEmpty(end), - [indexPatternsLoading, combinedQueries, start, end] + () => + filterQuery != null && + indexPatternsLoading != null && + !indexPatternsLoading && + !isEmpty(start) && + !isEmpty(end), + [indexPatternsLoading, filterQuery, start, end] ); const fields = useMemo( @@ -221,7 +228,7 @@ const TGridStandaloneComponent: React.FC = ({ entityType, excludeEcsData: true, fields, - filterQuery: combinedQueries?.filterQuery, + filterQuery, id: STANDALONE_ID, indexNames, limit: itemsPerPageStore, @@ -266,23 +273,6 @@ const TGridStandaloneComponent: React.FC = ({ [deletedEventIds, events] ); - const filterQuery = useMemo( - () => - getCombinedFilterQuery({ - config: getEsQueryConfig(uiSettings), - dataProviders: EMPTY_DATA_PROVIDERS, - indexPattern: indexPatterns, - browserFields, - filters, - kqlQuery: query, - kqlMode: 'search', - isEventViewer: true, - from: start, - to: end, - }), - [uiSettings, indexPatterns, browserFields, filters, query, start, end] - ); - useEffect(() => { setIsQueryLoading(loading); }, [loading]); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 0b2b72de83099..d7053e47a137a 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -25285,9 +25285,6 @@ "xpack.securitySolution.detectionEngine.alerts.histogram.showingAlertsTitle": "Affichage de : {modifier}{totalAlertsFormatted} {totalAlerts, plural, =1 {alerte} other {alertes}}", "xpack.securitySolution.detectionEngine.alerts.histogram.topNLabel": "Premiers {fieldName}", "xpack.securitySolution.detectionEngine.alerts.openedAlertSuccessToastMessage": "Ouverture réussie de {totalAlerts} {totalAlerts, plural, =1 {alerte} other {alertes}}.", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.selectAllAlertsTitle": "Sélectionner un total de {totalAlertsFormatted} {totalAlerts, plural, =1 {alerte} other {alertes}}", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.selectedAlertsTitle": "{selectedAlertsFormatted} {selectedAlerts, plural, =1 {alerte} other {alertes}} sélectionnée(s)", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.showingAlertsTitle": "Affichage de {totalAlertsFormatted} {totalAlerts, plural, =1 {alerte} other {alertes}}", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmation.confirmButtonLabel": "Modifier {customRulesCount, plural, =1 {# règle personnalisée} other {# règles personnalisées}}", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setIndexPatternsWarningCallout": "Vous êtes sur le point d'écraser les modèles d'indexation pour {rulesCount, plural, one {# règle sélectionnée} other {# règles sélectionnées}}. Sélectionnez Enregistrer pour appliquer les modifications.", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setTagsWarningCallout": "Vous êtes sur le point d'écraser les balises pour {rulesCount, plural, one {# règle sélectionnée} other {# règles sélectionnées}}. Sélectionnez Enregistrer pour appliquer les modifications.", @@ -26167,10 +26164,6 @@ "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showBuildingBlockTitle": "Inclure les alertes fondamentales", "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showOnlyThreatIndicatorAlerts": "Afficher uniquement les alertes d'indicateur de menaces", "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersTitle": "Filtres supplémentaires", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.acknowledgedSelectedTitle": "Marquer comme reconnue", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.closeSelectedTitle": "Fermer la sélection", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.openSelectedTitle": "Ouvrir la sélection", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.clearSelectionTitle": "Effacer la sélection", "xpack.securitySolution.detectionEngine.alerts.utilityBar.takeActionTitle": "Entreprendre une action", "xpack.securitySolution.detectionEngine.alertTitle": "Alertes", "xpack.securitySolution.detectionEngine.buttonManageRules": "Gérer les règles", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 0e8650985261d..f5361e3c867bd 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -25264,9 +25264,6 @@ "xpack.securitySolution.detectionEngine.alerts.histogram.showingAlertsTitle": "{modifier}{totalAlertsFormatted} {totalAlerts, plural, other {件のアラート}}を表示しています", "xpack.securitySolution.detectionEngine.alerts.histogram.topNLabel": "トップ{fieldName}", "xpack.securitySolution.detectionEngine.alerts.openedAlertSuccessToastMessage": "{totalAlerts} {totalAlerts, plural, other {件のアラート}}を正常に開きました。", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.selectAllAlertsTitle": "すべての{totalAlertsFormatted} {totalAlerts, plural, other {件のアラート}}を選択", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.selectedAlertsTitle": "Selected {selectedAlertsFormatted} {selectedAlerts, plural, other {件のアラート}}", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.showingAlertsTitle": "すべての{totalAlertsFormatted} {totalAlerts, plural, other {件のアラート}}を表示しています", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmation.confirmButtonLabel": "{customRulesCount, plural, other {# 個のカスタムルール}}を編集", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setIndexPatternsWarningCallout": "{rulesCount, plural, other {# 個の選択したルール}} のインデックスパターンを上書きしようとしています。[保存]をクリックすると、変更が適用されます。", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setTagsWarningCallout": "{rulesCount, plural, other {# 個の選択したルール}}のタグを上書きしようとしています。[保存]をクリックすると、変更が適用されます。\n", @@ -26144,10 +26141,6 @@ "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showBuildingBlockTitle": "基本アラートを含める", "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showOnlyThreatIndicatorAlerts": "脅威インジケーターアラートのみを表示", "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersTitle": "追加のフィルター", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.acknowledgedSelectedTitle": "確認済みに設定", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.closeSelectedTitle": "選択した項目を閉じる", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.openSelectedTitle": "選択した項目を開く", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.clearSelectionTitle": "選択した項目をクリア", "xpack.securitySolution.detectionEngine.alerts.utilityBar.takeActionTitle": "アクションを実行", "xpack.securitySolution.detectionEngine.alertTitle": "アラート", "xpack.securitySolution.detectionEngine.buttonManageRules": "ルールの管理", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 650d9f9b89da3..3082af48e77af 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -25293,9 +25293,6 @@ "xpack.securitySolution.detectionEngine.alerts.histogram.showingAlertsTitle": "正在显示:{modifier}{totalAlertsFormatted} 个{totalAlerts, plural, other {告警}}", "xpack.securitySolution.detectionEngine.alerts.histogram.topNLabel": "排名靠前的{fieldName}", "xpack.securitySolution.detectionEngine.alerts.openedAlertSuccessToastMessage": "已成功打开 {totalAlerts} 个{totalAlerts, plural, other {告警}}。", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.selectAllAlertsTitle": "选择全部 {totalAlertsFormatted} 个{totalAlerts, plural, other {告警}}", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.selectedAlertsTitle": "已选择 {selectedAlertsFormatted} 个{selectedAlerts, plural, other {告警}}", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.showingAlertsTitle": "正在显示 {totalAlertsFormatted} 个{totalAlerts, plural, other {告警}}", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmation.confirmButtonLabel": "编辑 {customRulesCount, plural, other {# 个定制规则}}", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setIndexPatternsWarningCallout": "您即将覆盖 {rulesCount, plural, other {# 个选定规则}}的索引模式,按“保存”可应用更改。", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setTagsWarningCallout": "您即将覆盖 {rulesCount, plural, other {# 个选定规则}}的标签,按“保存”可应用更改。", @@ -26175,10 +26172,6 @@ "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showBuildingBlockTitle": "包括构建块告警", "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showOnlyThreatIndicatorAlerts": "仅显示威胁指标告警", "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersTitle": "其他筛选", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.acknowledgedSelectedTitle": "标记为已确认", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.closeSelectedTitle": "关闭所选", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.openSelectedTitle": "打开所选", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.clearSelectionTitle": "清除所选内容", "xpack.securitySolution.detectionEngine.alerts.utilityBar.takeActionTitle": "采取操作", "xpack.securitySolution.detectionEngine.alertTitle": "告警", "xpack.securitySolution.detectionEngine.buttonManageRules": "管理规则",