diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx index 8771d75ccf814..589065e0812b1 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx @@ -15,12 +15,12 @@ import { InputsModelId } from '../../store/inputs/constants'; import { useGlobalTime } from '../../containers/use_global_time'; import type { BrowserFields } from '../../containers/source'; import { useKibana } from '../../lib/kibana'; +import { combineQueries } from '../../lib/kuery'; import type { inputsModel, State } from '../../store'; import { inputsSelectors } from '../../store'; import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import { timelineSelectors } from '../../../timelines/store/timeline'; import type { TimelineModel } from '../../../timelines/store/timeline/model'; -import { combineQueries } from '../../../timelines/components/timeline/helpers'; import { getOptions } from './helpers'; import { TopN } from './top_n'; diff --git a/x-pack/plugins/security_solution/public/common/lib/keury/index.ts b/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts similarity index 95% rename from x-pack/plugins/security_solution/public/common/lib/keury/index.ts rename to x-pack/plugins/security_solution/public/common/lib/kuery/index.ts index 735996d762ffc..55be876f3867b 100644 --- a/x-pack/plugins/security_solution/public/common/lib/keury/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts @@ -11,4 +11,5 @@ export { convertToBuildEsQuery, escapeKuery, escapeQueryValue, + combineQueries, } from '@kbn/timelines-plugin/public'; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx index 0850969019bb4..6f2a0dfe07520 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx @@ -57,7 +57,7 @@ import { omitTypenameInTimeline, formatTimelineResultToModel, } from '../../../timelines/components/open_timeline/helpers'; -import { convertKueryToElasticSearchQuery } from '../../../common/lib/keury'; +import { convertKueryToElasticSearchQuery } from '../../../common/lib/kuery'; import { getField, getFieldKey } from '../../../helpers'; import { replaceTemplateFieldFromQuery, 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 bf183ca405728..49927599cb1e8 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 @@ -25,7 +25,7 @@ import { SourcererScopeName } from '../../../common/store/sourcerer/model'; 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'; -import { combineQueries } from '../../../timelines/components/timeline/helpers'; +import { combineQueries } from '../../../common/lib/kuery'; import { timelineActions, timelineSelectors } from '../../../timelines/store/timeline'; import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import type { TimelineModel } from '../../../timelines/store/timeline/model'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/query_bar/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/query_bar/index.tsx index 6d96695d3c791..a5316eabb11f9 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/query_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/query_bar/index.tsx @@ -19,7 +19,7 @@ import type { ActionTimelineToShow } from '../../../../timelines/components/open import { QueryBar } from '../../../../common/components/query_bar'; import { buildGlobalQuery } from '../../../../timelines/components/timeline/helpers'; import { getDataProviderFilter } from '../../../../timelines/components/timeline/query_bar'; -import { convertKueryToElasticSearchQuery } from '../../../../common/lib/keury'; +import { convertKueryToElasticSearchQuery } from '../../../../common/lib/kuery'; import { useKibana } from '../../../../common/lib/kibana'; import type { TimelineModel } from '../../../../timelines/store/timeline/model'; import { useSavedQueryServices } from '../../../../common/utils/saved_query_services'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_histogram.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_histogram.tsx index a0c6e706c19ef..d3814fe1e8c1c 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_histogram.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_histogram.tsx @@ -10,7 +10,7 @@ import { getEsQueryConfig } from '@kbn/data-plugin/common'; import type { DataViewBase } from '@kbn/es-query'; import { useMatrixHistogramCombined } from '../../../../common/containers/matrix_histogram'; import { MatrixHistogramType } from '../../../../../common/search_strategy'; -import { convertToBuildEsQuery } from '../../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../../common/lib/kuery'; import { useKibana } from '../../../../common/lib/kibana'; import { QUERY_PREVIEW_ERROR } from './translations'; import { DEFAULT_PREVIEW_INDEX } from '../../../../../common/constants'; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.ts index 083b75a33c70b..b4de6a95daaf1 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { escapeKuery } from '../../../../common/lib/keury'; +import { escapeKuery } from '../../../../common/lib/kuery'; import type { FilterOptions } from './types'; const SEARCHABLE_RULE_PARAMS = [ diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/helpers.ts b/x-pack/plugins/security_solution/public/hosts/pages/details/helpers.ts index 0a09c7ec6dad5..99cdba73760a0 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/helpers.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/helpers.ts @@ -6,7 +6,7 @@ */ import type { Filter } from '@kbn/es-query'; -import { escapeQueryValue } from '../../../common/lib/keury'; +import { escapeQueryValue } from '../../../common/lib/kuery'; /** Returns the kqlQueryExpression for the `Events` widget on the `Host Details` page */ export const getHostDetailsEventsKqlQueryExpression = ({ diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx index fb39b402c84d2..b801dd825a7a0 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx @@ -40,7 +40,7 @@ import { SiemSearchBar } from '../../../common/components/search_bar'; import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper'; import { useGlobalTime } from '../../../common/containers/use_global_time'; import { useKibana } from '../../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../common/lib/kuery'; import { inputsSelectors } from '../../../common/store'; import { setHostDetailsTablesActivePageToZero } from '../../store/actions'; import { setAbsoluteRangeDatePicker } from '../../../common/store/inputs/actions'; diff --git a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx index 3195137ca3897..b9cefa660a450 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx @@ -30,7 +30,7 @@ import { useGlobalTime } from '../../common/containers/use_global_time'; import { TimelineId } from '../../../common/types/timeline'; import { LastEventIndexKey, RiskScoreEntity } from '../../../common/search_strategy'; import { useKibana } from '../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../common/lib/kuery'; import type { State } from '../../common/store'; import { inputsSelectors } from '../../common/store'; import { setAbsoluteRangeDatePicker } from '../../common/store/inputs/actions'; diff --git a/x-pack/plugins/security_solution/public/kubernetes/pages/index.tsx b/x-pack/plugins/security_solution/public/kubernetes/pages/index.tsx index 58e0ae3914ad2..d938e7a972783 100644 --- a/x-pack/plugins/security_solution/public/kubernetes/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/kubernetes/pages/index.tsx @@ -20,7 +20,7 @@ import { useGlobalFullScreen } from '../../common/containers/use_full_screen'; import { useSourcererDataView } from '../../common/containers/sourcerer'; import { useGlobalTime } from '../../common/containers/use_global_time'; import { useDeepEqualSelector } from '../../common/hooks/use_selector'; -import { convertToBuildEsQuery } from '../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../common/lib/kuery'; import { useInvalidFilterQuery } from '../../common/hooks/use_invalid_filter_query'; import { SessionsView } from '../../common/components/sessions_viewer'; import { TimelineId } from '../../../common/types/timeline'; diff --git a/x-pack/plugins/security_solution/public/network/pages/details/index.tsx b/x-pack/plugins/security_solution/public/network/pages/details/index.tsx index c7c435b608d7e..964e660fed527 100644 --- a/x-pack/plugins/security_solution/public/network/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/details/index.tsx @@ -33,7 +33,7 @@ import { SecuritySolutionPageWrapper } from '../../../common/components/page_wra import { useNetworkDetails, ID } from '../../containers/details'; import { useKibana } from '../../../common/lib/kibana'; import { decodeIpv6 } from '../../../common/lib/helpers'; -import { convertToBuildEsQuery } from '../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../common/lib/kuery'; import { inputsSelectors } from '../../../common/store'; import { setAbsoluteRangeDatePicker } from '../../../common/store/inputs/actions'; import { setNetworkDetailsTablesActivePageToZero } from '../../store/actions'; diff --git a/x-pack/plugins/security_solution/public/network/pages/network.tsx b/x-pack/plugins/security_solution/public/network/pages/network.tsx index a28f251195118..92bc47ba04c70 100644 --- a/x-pack/plugins/security_solution/public/network/pages/network.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/network.tsx @@ -30,7 +30,7 @@ import { useGlobalFullScreen } from '../../common/containers/use_full_screen'; import { useGlobalTime } from '../../common/containers/use_global_time'; import { LastEventIndexKey } from '../../../common/search_strategy'; import { useKibana } from '../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../common/lib/kuery'; import { inputsSelectors } from '../../common/store'; import { setAbsoluteRangeDatePicker } from '../../common/store/inputs/actions'; import { SpyRoute } from '../../common/utils/route/spy_routes'; diff --git a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx index 9f73cbf9a2d48..5194d697c96b1 100644 --- a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx @@ -14,7 +14,7 @@ import { ID as OverviewHostQueryId } from '../../containers/overview_host'; import { OverviewHost } from '../overview_host'; import { OverviewNetwork } from '../overview_network'; import { useKibana } from '../../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../common/lib/kuery'; import type { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import { useInvalidFilterQuery } from '../../../common/hooks/use_invalid_filter_query'; import { diff --git a/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx b/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx index 15768c6359814..4e35cae873344 100644 --- a/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx @@ -22,7 +22,7 @@ import type { MatrixHistogramConfigs, MatrixHistogramOption, } from '../../../common/components/matrix_histogram/types'; -import { convertToBuildEsQuery } from '../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../common/lib/kuery'; import { useKibana, useUiSetting$ } from '../../../common/lib/kibana'; import { eventsStackByOptions, diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx index f7e267de67d09..367a145774d7a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx @@ -49,7 +49,8 @@ import { startSelector, endSelector, } from '../../../../common/components/super_date_picker/selectors'; -import { combineQueries, focusActiveTimelineButton } from '../../timeline/helpers'; +import { focusActiveTimelineButton } from '../../timeline/helpers'; +import { combineQueries } from '../../../../common/lib/kuery'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; import { ActiveTimelines } from './active_timelines'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx index 05421e9891e51..8841a53f43d69 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx @@ -21,7 +21,7 @@ import { useGlobalTime } from '../../../../common/containers/use_global_time'; import { networkToCriteria } from '../../../../common/components/ml/criteria/network_to_criteria'; import { scoreIntervalToDateTime } from '../../../../common/components/ml/score/score_interval_to_datetime'; import { useKibana } from '../../../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../../common/lib/kuery'; import { inputsSelectors } from '../../../../common/store'; import { setAbsoluteRangeDatePicker } from '../../../../common/store/inputs/actions'; import { useSourcererDataView } from '../../../../common/containers/sourcerer'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx index 5f6713c82c42c..4e391a95fc05a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx @@ -6,14 +6,11 @@ */ import { cloneDeep } from 'lodash/fp'; -import { mockIndexPattern } from '../../../common/mock'; import { DataProviderType } from './data_providers/data_provider'; import { mockDataProviders } from './data_providers/mock/mock_data_providers'; -import { buildGlobalQuery, combineQueries, resolverIsShowing, showGlobalFilters } from './helpers'; +import { buildGlobalQuery } from './helpers'; import { mockBrowserFields } from '../../../common/containers/source/mock'; -import type { EsQueryConfig, Filter } from '@kbn/es-query'; -import { FilterStateStore } from '@kbn/es-query'; const cleanUpKqlQuery = (str: string) => str.replace(/\n/g, '').replace(/\s\s+/g, ' '); @@ -220,388 +217,3 @@ describe('Build KQL Query', () => { ); }); }); - -describe('Combined Queries', () => { - const config: EsQueryConfig = { - allowLeadingWildcards: true, - queryStringOptions: {}, - ignoreFilterIfFieldNotInIndex: true, - dateFormatTZ: 'America/New_York', - }; - test('No Data Provider & No kqlQuery & and isEventViewer is false', () => { - expect( - combineQueries({ - config, - dataProviders: [], - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - }) - ).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, - dataProviders: [], - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [ - { - $state: { store: FilterStateStore.APP_STATE }, - meta: { - alias: null, - disabled: false, - key: 'event.category', - negate: false, - params: { query: 'file' }, - type: 'phrase', - }, - query: { match_phrase: { 'event.category': 'file' } }, - }, - { - $state: { store: FilterStateStore.APP_STATE }, - meta: { - alias: null, - disabled: false, - key: 'host.name', - negate: false, - type: 'exists', - value: 'exists', - }, - query: { exists: { field: 'host.name' } }, - } as Filter, - ], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - isEventViewer, - }) - ).toEqual({ - filterQuery: - '{"bool":{"must":[],"filter":[{"exists":{"field":"host.name"}}],"should":[],"must_not":[]}}', - }); - }); - - test('Only Data Provider', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toEqual( - '{"bool":{"must":[],"filter":[{"bool":{"should":[{"match_phrase":{"name":"Provider 1"}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}' - ); - expect(kqlError).toBeUndefined(); - }); - - test('Only Data Provider with timestamp (string input)', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - dataProviders[0].queryMatch.field = '@timestamp'; - dataProviders[0].queryMatch.value = '2018-03-23T23:36:23.232Z'; - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"range\\":{\\"@timestamp\\":{\\"gte\\":\\"1521848183232\\",\\"lte\\":\\"1521848183232\\"}}}],\\"minimum_should_match\\":1}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - expect(kqlError).toBeUndefined(); - }); - - test('Only Data Provider with timestamp (numeric input)', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - dataProviders[0].queryMatch.field = '@timestamp'; - dataProviders[0].queryMatch.value = 1521848183232; - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"range\\":{\\"@timestamp\\":{\\"gte\\":\\"1521848183232\\",\\"lte\\":\\"1521848183232\\"}}}],\\"minimum_should_match\\":1}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - expect(kqlError).toBeUndefined(); - }); - - test('Only Data Provider with a date type (string input)', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - dataProviders[0].queryMatch.field = 'event.end'; - dataProviders[0].queryMatch.value = '2018-03-23T23:36:23.232Z'; - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"event.end\\":\\"1521848183232\\"}}],\\"minimum_should_match\\":1}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - expect(kqlError).toBeUndefined(); - }); - - test('Only Data Provider with date type (numeric input)', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - dataProviders[0].queryMatch.field = 'event.end'; - dataProviders[0].queryMatch.value = 1521848183232; - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"event.end\\":\\"1521848183232\\"}}],\\"minimum_should_match\\":1}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - expect(kqlError).toBeUndefined(); - }); - - test('Only KQL search/filter query', () => { - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders: [], - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toEqual( - '{"bool":{"must":[],"filter":[{"bool":{"should":[{"match_phrase":{"host.name":"host-1"}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}' - ); - expect(kqlError).toBeUndefined(); - }); - - test('Invalid KQL search/filter query', () => { - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders: [], - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: 'host.name: "host-1', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toBeUndefined(); - expect(kqlError).toBeDefined(); // Not testing on the error message since we don't control changes to them - }); - - test('Data Provider & KQL search query', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toEqual( - '{"bool":{"must":[],"filter":[{"bool":{"should":[{"bool":{"should":[{"match_phrase":{"name":"Provider 1"}}],"minimum_should_match":1}},{"bool":{"should":[{"match_phrase":{"host.name":"host-1"}}],"minimum_should_match":1}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}' - ); - expect(kqlError).toBeUndefined(); - }); - - test('Data Provider & KQL filter query', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' }, - kqlMode: 'filter', - })!; - expect(filterQuery).toEqual( - '{"bool":{"must":[],"filter":[{"bool":{"filter":[{"bool":{"should":[{"match_phrase":{"name":"Provider 1"}}],"minimum_should_match":1}},{"bool":{"should":[{"match_phrase":{"host.name":"host-1"}}],"minimum_should_match":1}}]}}],"should":[],"must_not":[]}}' - ); - expect(kqlError).toBeUndefined(); - }); - - test('Data Provider & KQL search query multiple', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 2)); - dataProviders[0].and = cloneDeep(mockDataProviders.slice(2, 4)); - dataProviders[1].and = cloneDeep(mockDataProviders.slice(4, 5)); - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"bool\\":{\\"should\\":[{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 1\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 3\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 4\\"}}],\\"minimum_should_match\\":1}}]}},{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 2\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 5\\"}}],\\"minimum_should_match\\":1}}]}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"host.name\\":\\"host-1\\"}}],\\"minimum_should_match\\":1}}],\\"minimum_should_match\\":1}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - expect(kqlError).toBeUndefined(); - }); - - test('Data Provider & KQL filter query multiple', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 2)); - dataProviders[0].and = cloneDeep(mockDataProviders.slice(2, 4)); - dataProviders[1].and = cloneDeep(mockDataProviders.slice(4, 5)); - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' }, - kqlMode: 'filter', - })!; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 1\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 3\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 4\\"}}],\\"minimum_should_match\\":1}}]}},{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 2\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 5\\"}}],\\"minimum_should_match\\":1}}]}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"host.name\\":\\"host-1\\"}}],\\"minimum_should_match\\":1}}]}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - expect(kqlError).toBeUndefined(); - }); - - test('Data Provider & kql filter query with nested field that exists', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - const query = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [ - { - meta: { - alias: null, - negate: false, - disabled: false, - type: 'exists', - key: 'nestedField.firstAttributes', - value: 'exists', - }, - query: { - exists: { - field: 'nestedField.firstAttributes', - }, - }, - $state: { - store: FilterStateStore.APP_STATE, - }, - } as Filter, - ], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'filter', - }); - const filterQuery = query && query.filterQuery; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 1\\"}}],\\"minimum_should_match\\":1}},{\\"exists\\":{\\"field\\":\\"nestedField.firstAttributes\\"}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - }); - - test('Data Provider & kql filter query with nested field of a particular value', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - const query = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [ - { - $state: { store: FilterStateStore.APP_STATE }, - meta: { - alias: null, - disabled: false, - key: 'nestedField.secondAttributes', - negate: false, - params: { query: 'test' }, - type: 'phrase', - }, - query: { match_phrase: { 'nestedField.secondAttributes': 'test' } }, - }, - ], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'filter', - }); - const filterQuery = query && query.filterQuery; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 1\\"}}],\\"minimum_should_match\\":1}},{\\"match_phrase\\":{\\"nestedField.secondAttributes\\":\\"test\\"}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - }); - - describe('resolverIsShowing', () => { - test('it returns true when graphEventId is NOT an empty string', () => { - expect(resolverIsShowing('a valid id')).toBe(true); - }); - - test('it returns false when graphEventId is undefined', () => { - expect(resolverIsShowing(undefined)).toBe(false); - }); - - test('it returns false when graphEventId is an empty string', () => { - expect(resolverIsShowing('')).toBe(false); - }); - }); - - describe('showGlobalFilters', () => { - test('it returns false when `globalFullScreen` is true and `graphEventId` is NOT an empty string, because Resolver IS showing', () => { - expect(showGlobalFilters({ globalFullScreen: true, graphEventId: 'a valid id' })).toBe(false); - }); - - test('it returns true when `globalFullScreen` is true and `graphEventId` is undefined, because Resolver is NOT showing', () => { - expect(showGlobalFilters({ globalFullScreen: true, graphEventId: undefined })).toBe(true); - }); - - test('it returns true when `globalFullScreen` is true and `graphEventId` is an empty string, because Resolver is NOT showing', () => { - expect(showGlobalFilters({ globalFullScreen: true, graphEventId: '' })).toBe(true); - }); - - test('it returns true when `globalFullScreen` is false and `graphEventId` is NOT an empty string, because Resolver IS showing', () => { - expect(showGlobalFilters({ globalFullScreen: false, graphEventId: 'a valid id' })).toBe(true); - }); - - test('it returns true when `globalFullScreen` is false and `graphEventId` is undefined, because Resolver is NOT showing', () => { - expect(showGlobalFilters({ globalFullScreen: false, graphEventId: undefined })).toBe(true); - }); - - test('it returns true when `globalFullScreen` is false and `graphEventId` is an empty string, because Resolver is NOT showing', () => { - expect(showGlobalFilters({ globalFullScreen: false, graphEventId: '' })).toBe(true); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx index 592130a2db170..9cb0e3d6e60bd 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx @@ -8,7 +8,6 @@ import { isEmpty, get } from 'lodash/fp'; import memoizeOne from 'memoize-one'; -import type { DataViewBase, EsQueryConfig, Filter, Query } from '@kbn/es-query'; import { handleSkipFocus, elementOrChildrenHasFocus, @@ -16,7 +15,7 @@ import { getTableSkipFocus, stopPropagationAndPreventDefault, } from '@kbn/timelines-plugin/public'; -import { escapeQueryValue, convertToBuildEsQuery } from '../../../common/lib/keury'; +import { escapeQueryValue } from '../../../common/lib/kuery'; import type { DataProvider, DataProvidersAnd } from './data_providers/data_provider'; import { DataProviderType, EXISTS_OPERATOR } from './data_providers/data_provider'; @@ -134,85 +133,6 @@ export const buildGlobalQuery = (dataProviders: DataProvider[], browserFields: B return !index ? `(${queryMatch})` : `${globalQuery} or (${queryMatch})`; }, ''); -export const combineQueries = ({ - config, - dataProviders, - indexPattern, - browserFields, - filters = [], - kqlQuery, - kqlMode, - isEventViewer, -}: { - config: EsQueryConfig; - dataProviders: DataProvider[]; - indexPattern: DataViewBase; - browserFields: BrowserFields; - filters: Filter[]; - kqlQuery: Query; - kqlMode: string; - isEventViewer?: boolean; -}): { filterQuery?: string; kqlError?: Error } | null => { - const kuery: Query = { query: '', language: kqlQuery.language }; - if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters) && !isEventViewer) { - return null; - } else if ( - isEmpty(dataProviders) && - isEmpty(kqlQuery.query) && - (isEventViewer || !isEmpty(filters)) - ) { - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); - return { - filterQuery, - kqlError, - }; - } else if (isEmpty(dataProviders) && !isEmpty(kqlQuery.query)) { - kuery.query = `(${kqlQuery.query})`; - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); - return { - filterQuery, - kqlError, - }; - } else if (!isEmpty(dataProviders) && isEmpty(kqlQuery)) { - kuery.query = `(${buildGlobalQuery(dataProviders, browserFields)})`; - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); - return { - filterQuery, - kqlError, - }; - } - const operatorKqlQuery = kqlMode === 'filter' ? 'and' : 'or'; - const postpend = (q: string) => `${!isEmpty(q) ? ` ${operatorKqlQuery} (${q})` : ''}`; - kuery.query = `((${buildGlobalQuery(dataProviders, browserFields)})${postpend( - kqlQuery.query as string - )})`; - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); - return { - filterQuery, - kqlError, - }; -}; - /** * The CSS class name of a "stateful event", which appears in both * the `Timeline` and the `Events Viewer` widget diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.test.tsx index 3cf7acdef93fb..153b24dcf0bf8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { coreMock } from '@kbn/core/public/mocks'; import { DEFAULT_FROM, DEFAULT_TO } from '../../../../../common/constants'; import { mockBrowserFields } from '../../../../common/containers/source/mock'; -import { convertKueryToElasticSearchQuery } from '../../../../common/lib/keury'; +import { convertKueryToElasticSearchQuery } from '../../../../common/lib/kuery'; import { mockIndexPattern, TestProviders } from '../../../../common/mock'; import { QueryBar } from '../../../../common/components/query_bar'; import { FilterStateStore } from '@kbn/es-query'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx index ed5b4d6d45151..c040f0c6b1abe 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx @@ -18,7 +18,7 @@ import { InputsModelId } from '../../../../common/store/inputs/constants'; import { useSourcererDataView } from '../../../../common/containers/sourcerer'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; -import { convertKueryToElasticSearchQuery } from '../../../../common/lib/keury'; +import { convertKueryToElasticSearchQuery } from '../../../../common/lib/kuery'; import type { KqlMode } from '../../../store/timeline/model'; import { useSavedQueryServices } from '../../../../common/utils/saved_query_services'; import type { DispatchUpdateReduxTime } from '../../../../common/components/super_date_picker'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx index c7a30a4f501b8..b610adbe6da50 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx @@ -26,8 +26,8 @@ import { useTimelineEventsDetails } from '../../../containers/details'; import { useSourcererDataView } from '../../../../common/containers/sourcerer'; import { mockSourcererScope } from '../../../../common/containers/sourcerer/mocks'; import { Direction } from '../../../../../common/search_strategy'; -import * as helpers from '../helpers'; import { mockCasesContext } from '@kbn/cases-plugin/public/mocks/mock_cases_context'; +import * as helpers from '../../../../common/lib/kuery'; jest.mock('../../../containers', () => ({ useTimelineEvents: jest.fn(), @@ -47,6 +47,8 @@ jest.mock('../../../../common/containers/sourcerer/use_signal_helpers', () => ({ useSignalHelpers: () => ({ signalIndexNeedsInit: false }), })); +jest.mock('../../../../common/lib/kuery'); + const mockUseResizeObserver: jest.Mock = useResizeObserver as jest.Mock; jest.mock('use-resize-observer/polyfilled'); mockUseResizeObserver.mockImplementation(() => ({})); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx index 5797009535e23..c38304d798418 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx @@ -35,7 +35,8 @@ import { defaultHeaders } from '../body/column_headers/default_headers'; import { StatefulBody } from '../body'; import { Footer, footerHeight } from '../footer'; import { TimelineHeader } from '../header'; -import { calculateTotalPages, combineQueries } from '../helpers'; +import { calculateTotalPages } from '../helpers'; +import { combineQueries } from '../../../../common/lib/kuery'; import { TimelineRefetch } from '../refetch_timeline'; import type { ControlColumnProps, diff --git a/x-pack/plugins/security_solution/public/users/pages/details/index.tsx b/x-pack/plugins/security_solution/public/users/pages/details/index.tsx index 4e2c093803096..906312d6e1abc 100644 --- a/x-pack/plugins/security_solution/public/users/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/details/index.tsx @@ -31,7 +31,7 @@ import { SiemSearchBar } from '../../../common/components/search_bar'; import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper'; import { useGlobalTime } from '../../../common/containers/use_global_time'; import { useKibana } from '../../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../common/lib/kuery'; import { inputsSelectors } from '../../../common/store'; import { useAlertsPrivileges } from '../../../detections/containers/detection_engine/alerts/use_alerts_privileges'; import { setUsersDetailsTablesActivePageToZero } from '../../store/actions'; diff --git a/x-pack/plugins/security_solution/public/users/pages/users.tsx b/x-pack/plugins/security_solution/public/users/pages/users.tsx index d3140a330da63..df5b891c24e8d 100644 --- a/x-pack/plugins/security_solution/public/users/pages/users.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/users.tsx @@ -26,7 +26,7 @@ import { LastEventTime } from '../../common/components/last_event_time'; import { useGlobalFullScreen } from '../../common/containers/use_full_screen'; import { useGlobalTime } from '../../common/containers/use_global_time'; import { useKibana } from '../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../common/lib/kuery'; import type { State } from '../../common/store'; import { inputsSelectors } from '../../common/store'; import { setAbsoluteRangeDatePicker } from '../../common/store/inputs/actions'; 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 d0d656d64e4de..288ad46d326f1 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 @@ -526,6 +526,101 @@ describe('Combined Queries', () => { ); }); + test('Disabled Data Provider and kqlQuery', () => { + const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); + dataProviders[0].enabled = false; + const { filterQuery } = combineQueries({ + config, + dataProviders, + indexPattern: mockIndexPattern, + browserFields: mockBrowserFields, + filters: [], + kqlQuery: { query: '_id:*', language: 'kuery' }, + kqlMode: 'search', + })!; + + const expectQueryString = JSON.stringify({ + bool: { + must: [], + filter: [ + { + bool: { + should: [ + { + exists: { + field: '_id', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + should: [], + must_not: [], + }, + }); + + expect(filterQuery).toStrictEqual(expectQueryString); + }); + + test('Both disabled & enabled data provider and kqlQuery', () => { + const dataProviders = cloneDeep(mockDataProviders.slice(0, 2)); + dataProviders[0].enabled = false; + const { filterQuery } = combineQueries({ + config, + dataProviders, + indexPattern: mockIndexPattern, + browserFields: mockBrowserFields, + filters: [], + kqlQuery: { query: '_id:*', language: 'kuery' }, + kqlMode: 'search', + })!; + + const expectQueryString = JSON.stringify({ + bool: { + must: [], + filter: [ + { + bool: { + should: [ + { + bool: { + should: [ + { + match_phrase: { + [dataProviders[1].queryMatch.field]: dataProviders[1].queryMatch.value, + }, + }, + ], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [ + { + exists: { + field: '_id', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + should: [], + must_not: [], + }, + }); + + expect(filterQuery).toStrictEqual(expectQueryString); + }); + describe('resolverIsShowing', () => { test('it returns true when graphEventId is NOT an empty string', () => { expect(resolverIsShowing('a valid id')).toBe(true); 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 4de43ef249397..497787166510d 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx @@ -144,6 +144,10 @@ interface CombineQueries { kqlMode: string; } +export const isDataProviderEmpty = (dataProviders: DataProvider[]) => { + return isEmpty(dataProviders) || isEmpty(dataProviders.filter((d) => d.enabled === true)); +}; + export const combineQueries = ({ config, dataProviders, @@ -154,9 +158,9 @@ export const combineQueries = ({ kqlMode, }: CombineQueries): { filterQuery: string | undefined; kqlError: Error | undefined } | null => { const kuery: Query = { query: '', language: kqlQuery.language }; - if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters)) { + if (isDataProviderEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters)) { return null; - } else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && !isEmpty(filters)) { + } else if (isDataProviderEmpty(dataProviders) && isEmpty(kqlQuery.query) && !isEmpty(filters)) { const [filterQuery, kqlError] = convertToBuildEsQuery({ config, queries: [kuery], @@ -168,40 +172,21 @@ export const combineQueries = ({ filterQuery, kqlError, }; - } else if (isEmpty(dataProviders) && !isEmpty(kqlQuery.query)) { - kuery.query = `(${kqlQuery.query})`; + } - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); + const operatorKqlQuery = kqlMode === 'filter' ? 'and' : 'or'; - return { - filterQuery, - kqlError, - }; - } else if (!isEmpty(dataProviders) && isEmpty(kqlQuery)) { - kuery.query = `(${buildGlobalQuery(dataProviders, browserFields)})`; + const postpend = (q: string) => `${!isEmpty(q) ? `(${q})` : ''}`; - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); + const globalQuery = buildGlobalQuery(dataProviders, browserFields); // based on Data Providers - return { - filterQuery, - kqlError, - }; - } - const operatorKqlQuery = kqlMode === 'filter' ? 'and' : 'or'; - const postpend = (q: string) => `${!isEmpty(q) ? ` ${operatorKqlQuery} (${q})` : ''}`; - kuery.query = `((${buildGlobalQuery(dataProviders, browserFields)})${postpend( - kqlQuery.query as string - )})`; + const querySuffix = postpend(kqlQuery.query as string); // based on Unified Search bar + + const queryPrefix = globalQuery ? `(${globalQuery})` : ''; + + const queryOperator = queryPrefix && querySuffix ? operatorKqlQuery : ''; + + kuery.query = `(${queryPrefix} ${queryOperator} ${querySuffix})`; const [filterQuery, kqlError] = convertToBuildEsQuery({ config, diff --git a/x-pack/plugins/timelines/public/index.ts b/x-pack/plugins/timelines/public/index.ts index b31f01c0663c4..8ed9bc7cd092e 100644 --- a/x-pack/plugins/timelines/public/index.ts +++ b/x-pack/plugins/timelines/public/index.ts @@ -95,3 +95,5 @@ export { StatefulEventContext } from './components/stateful_event_context'; export { TimelineContext } from './components/t_grid/shared'; export type { AddToTimelineButtonProps } from './components/hover_actions/actions/add_to_timeline'; + +export { combineQueries } from './components/t_grid/helpers';