From 5c42492b5509d4d3ce62f0ece265a3b6c5c307ac Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 6 Sep 2019 04:41:36 -0700 Subject: [PATCH 1/5] [ML] Single metric viewer: Fix top nav refresh behaviour. (#44860) This PR fixes a regression which didn't stop the date picker refresh when switching from the anomaly detection jobs list to single metric viewer. Includes unit tests which would fail without the fix. --- .../__snapshots__/top_nav.test.tsx.snap | 75 ++++++++++++++ .../navigation_menu/top_nav/top_nav.test.tsx | 99 +++++++++++++++++++ .../navigation_menu/top_nav/top_nav.tsx | 37 +++++-- .../ml/public/contexts/ui/__mocks__/mocks.ts | 41 +++++++- .../timeseriesexplorer/timeseriesexplorer.js | 4 + 5 files changed, 242 insertions(+), 14 deletions(-) create mode 100644 x-pack/legacy/plugins/ml/public/components/navigation_menu/top_nav/__snapshots__/top_nav.test.tsx.snap create mode 100644 x-pack/legacy/plugins/ml/public/components/navigation_menu/top_nav/top_nav.test.tsx diff --git a/x-pack/legacy/plugins/ml/public/components/navigation_menu/top_nav/__snapshots__/top_nav.test.tsx.snap b/x-pack/legacy/plugins/ml/public/components/navigation_menu/top_nav/__snapshots__/top_nav.test.tsx.snap new file mode 100644 index 00000000000000..61bba452f49ca1 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/components/navigation_menu/top_nav/__snapshots__/top_nav.test.tsx.snap @@ -0,0 +1,75 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Navigation Menu: Minimal initialization. 1`] = ` + +
+ +
+
+`; diff --git a/x-pack/legacy/plugins/ml/public/components/navigation_menu/top_nav/top_nav.test.tsx b/x-pack/legacy/plugins/ml/public/components/navigation_menu/top_nav/top_nav.test.tsx new file mode 100644 index 00000000000000..d98077da230c88 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/components/navigation_menu/top_nav/top_nav.test.tsx @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { mount, shallow } from 'enzyme'; +import React from 'react'; + +import { uiTimefilterMock } from '../../../contexts/ui/__mocks__/mocks'; +import { mlTimefilterRefresh$ } from '../../../services/timefilter_refresh_service'; + +import { MlSuperDatePickerWithUpdate, TopNav } from './top_nav'; + +uiTimefilterMock.enableAutoRefreshSelector(); +uiTimefilterMock.enableTimeRangeSelector(); + +jest.mock('../../../contexts/ui/use_ui_context'); + +const noop = () => {}; + +describe('Navigation Menu: ', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + test('Minimal initialization.', () => { + const refreshListener = jest.fn(); + const refreshSubscription = mlTimefilterRefresh$.subscribe(refreshListener); + + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + expect(refreshListener).toBeCalledTimes(0); + + refreshSubscription.unsubscribe(); + }); + + // The following tests are written against MlSuperDatePickerWithUpdate + // instead of TopNav. TopNav uses hooks and we cannot writing tests + // with async hook updates yet until React 16.9 is available. + + // MlSuperDatePickerWithUpdate fixes an issue with EuiSuperDatePicker + // which didn't make it into Kibana 7.4. We should be able to just + // use EuiSuperDatePicker again once the following PR is in EUI: + // https://github.com/elastic/eui/pull/2298 + + test('Listen for consecutive super date picker refreshs.', async () => { + const onRefresh = jest.fn(); + + const componentRefresh = mount( + + ); + + const instanceRefresh = componentRefresh.instance(); + + jest.advanceTimersByTime(10); + // @ts-ignore + await instanceRefresh.asyncInterval.__pendingFn; + jest.advanceTimersByTime(10); + // @ts-ignore + await instanceRefresh.asyncInterval.__pendingFn; + + expect(onRefresh).toBeCalledTimes(2); + }); + + test('Switching refresh interval to pause should stop onRefresh being called.', async () => { + const onRefresh = jest.fn(); + + const componentRefresh = mount( + + ); + + const instanceRefresh = componentRefresh.instance(); + + jest.advanceTimersByTime(10); + // @ts-ignore + await instanceRefresh.asyncInterval.__pendingFn; + componentRefresh.setProps({ isPaused: true, refreshInterval: 0 }); + jest.advanceTimersByTime(10); + // @ts-ignore + await instanceRefresh.asyncInterval.__pendingFn; + + expect(onRefresh).toBeCalledTimes(1); + }); +}); diff --git a/x-pack/legacy/plugins/ml/public/components/navigation_menu/top_nav/top_nav.tsx b/x-pack/legacy/plugins/ml/public/components/navigation_menu/top_nav/top_nav.tsx index 0596df80fa4499..f32632cd321ae2 100644 --- a/x-pack/legacy/plugins/ml/public/components/navigation_menu/top_nav/top_nav.tsx +++ b/x-pack/legacy/plugins/ml/public/components/navigation_menu/top_nav/top_nav.tsx @@ -4,15 +4,38 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FC, Fragment, useState, useEffect } from 'react'; +import React, { Component, FC, Fragment, useState, useEffect } from 'react'; import { Subscription } from 'rxjs'; -import { EuiSuperDatePicker } from '@elastic/eui'; +import { EuiSuperDatePicker, EuiSuperDatePickerProps } from '@elastic/eui'; import { TimeHistory } from 'ui/timefilter'; import { TimeRange } from 'src/plugins/data/public'; import { mlTimefilterRefresh$ } from '../../../services/timefilter_refresh_service'; import { useUiContext } from '../../../contexts/ui/use_ui_context'; +interface ComponentWithConstructor extends Component { + new (): Component; +} + +const MlSuperDatePicker = (EuiSuperDatePicker as any) as ComponentWithConstructor< + EuiSuperDatePickerProps +>; + +// This part fixes a problem with EuiSuperDater picker where it would not reflect +// a prop change of isPaused on the internal interval. This fix will be released +// with EUI 13.7.0 but only 13.6.1 without the fix made it into Kibana 7.4 so +// it's copied here. +export class MlSuperDatePickerWithUpdate extends MlSuperDatePicker { + componentDidUpdate = () => { + // @ts-ignore + this.stopInterval(); + if (!this.props.isPaused) { + // @ts-ignore + this.startInterval(this.props.refreshInterval); + } + }; +} + interface Duration { start: string; end: string; @@ -97,20 +120,14 @@ export const TopNav: FC = () => { {(isAutoRefreshSelectorEnabled || isTimeRangeSelectorEnabled) && (
- { - // This check is a workaround to catch a bug in EuiSuperDatePicker which - // might not have disabled the refresh interval after a props change. - if (!refreshInterval.pause) { - mlTimefilterRefresh$.next(); - } - }} + onRefresh={() => mlTimefilterRefresh$.next()} onRefreshChange={updateInterval} recentlyUsedRanges={recentlyUsedRanges} dateFormat={dateFormat} diff --git a/x-pack/legacy/plugins/ml/public/contexts/ui/__mocks__/mocks.ts b/x-pack/legacy/plugins/ml/public/contexts/ui/__mocks__/mocks.ts index 90bc028a7cd377..e6e51f0bdecf4c 100644 --- a/x-pack/legacy/plugins/ml/public/contexts/ui/__mocks__/mocks.ts +++ b/x-pack/legacy/plugins/ml/public/contexts/ui/__mocks__/mocks.ts @@ -11,7 +11,7 @@ export const uiChromeMock = { get: (key: string) => { switch (key) { case 'dateFormat': - return {}; + return 'MMM D, YYYY @ HH:mm:ss.SSS'; case 'theme:darkMode': return false; case 'timepicker:timeDefaults': @@ -26,12 +26,45 @@ export const uiChromeMock = { }, }; +interface RefreshInterval { + value: number; + pause: boolean; +} + +const time = { + from: 'Thu Aug 29 2019 02:04:19 GMT+0200', + to: 'Sun Sep 29 2019 01:45:36 GMT+0200', +}; + export const uiTimefilterMock = { - getRefreshInterval: () => '30s', - getTime: () => ({ from: 0, to: 0 }), + enableAutoRefreshSelector() { + this.isAutoRefreshSelectorEnabled = true; + }, + enableTimeRangeSelector() { + this.isTimeRangeSelectorEnabled = true; + }, + getEnabledUpdated$() { + return { subscribe: jest.fn() }; + }, + getRefreshInterval() { + return this.refreshInterval; + }, + getRefreshIntervalUpdate$() { + return { subscribe: jest.fn() }; + }, + getTime: () => time, + getTimeUpdate$() { + return { subscribe: jest.fn() }; + }, + isAutoRefreshSelectorEnabled: false, + isTimeRangeSelectorEnabled: false, + refreshInterval: { value: 0, pause: true }, on: (event: string, reload: () => void) => {}, + setRefreshInterval(refreshInterval: RefreshInterval) { + this.refreshInterval = refreshInterval; + }, }; export const uiTimeHistoryMock = { - get: () => [{ from: 0, to: 0 }], + get: () => [time], }; diff --git a/x-pack/legacy/plugins/ml/public/timeseriesexplorer/timeseriesexplorer.js b/x-pack/legacy/plugins/ml/public/timeseriesexplorer/timeseriesexplorer.js index db316f67688fe9..ab29e0ba303a92 100644 --- a/x-pack/legacy/plugins/ml/public/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/legacy/plugins/ml/public/timeseriesexplorer/timeseriesexplorer.js @@ -467,6 +467,10 @@ export class TimeSeriesExplorer extends React.Component { } refresh = () => { + if (this.state.loading) { + return; + } + const { appStateHandler, timefilter } = this.props; const { detectorId: currentDetectorId, From 6d1be8ea87ed9ac5ce3ca9f5802d6dfcee03f56c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Fri, 6 Sep 2019 14:16:02 +0200 Subject: [PATCH 2/5] [APM] Make number of x ticks responsive to the plot width (#44870) * [APM] Make number of x ticks responsive to the plot width * Fix snapshots --- .../shared/charts/CustomPlot/StaticPlot.js | 20 ++++++++--- .../shared/charts/CustomPlot/index.js | 1 + .../charts/CustomPlot/test/CustomPlot.test.js | 2 +- .../__snapshots__/CustomPlot.test.js.snap | 34 +++++++++---------- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/StaticPlot.js b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/StaticPlot.js index 57e83ef62c44ba..5a1cdc185ac4f0 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/StaticPlot.js +++ b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/StaticPlot.js @@ -27,8 +27,6 @@ import { isValidCoordinateValue } from '../../../../utils/isValidCoordinateValue // see https://github.com/uber/react-vis/issues/1214 const getNull = d => isValidCoordinateValue(d.y) && !isNaN(d.y); -const X_TICK_TOTAL = 7; - class StaticPlot extends PureComponent { getVisSeries(series, plotValues) { return series @@ -141,12 +139,23 @@ class StaticPlot extends PureComponent { } render() { - const { series, tickFormatX, tickFormatY, plotValues, noHits } = this.props; + const { + width, + series, + tickFormatX, + tickFormatY, + plotValues, + noHits + } = this.props; const { yTickValues } = plotValues; + // approximate number of x-axis ticks based on the width of the plot. There should by approx 1 tick per 100px + // d3 will determine the exact number of ticks based on the selected range + const xTickTotal = Math.floor(width / 100); + return ( - + {noHits ? (
{ onHover={onHover} onMouseLeave={onMouseLeave} onSelectionEnd={onSelectionEnd} - width={100} + width={800} tickFormatX={x => x.getTime()} // Avoid timezone issues in snapshots /> ); diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap index ad3b3d25fa4c69..aeef8ed995e929 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap +++ b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap @@ -5836,7 +5836,7 @@ Array [ style={ Object { "height": "256px", - "width": "100px", + "width": "800px", } } > @@ -5850,7 +5850,7 @@ Array [ onMouseLeave={[Function]} onMouseMove={[Function]} onWheel={[Function]} - width={100} + width={800} > @@ -5895,7 +5895,7 @@ Array [ @@ -6213,7 +6213,7 @@ Array [ onMouseLeave={[Function]} onMouseMove={[Function]} onWheel={[Function]} - width={100} + width={800} />
From 5d8b8feb2954fb97542808537eb216e397954c4d Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Fri, 6 Sep 2019 14:56:29 +0100 Subject: [PATCH 3/5] refactor(webhook-whitelisting): Removed unneeded schema config (#44974) Removed an unnecessary Actions schema configuration --- x-pack/legacy/plugins/actions/index.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/x-pack/legacy/plugins/actions/index.ts b/x-pack/legacy/plugins/actions/index.ts index bb982dd59b5a67..0a9acc13c3ac07 100644 --- a/x-pack/legacy/plugins/actions/index.ts +++ b/x-pack/legacy/plugins/actions/index.ts @@ -27,12 +27,9 @@ export function actions(kibana: any) { return Joi.object() .keys({ enabled: Joi.boolean().default(false), - whitelistedHosts: Joi.alternatives() - .try( - Joi.array() - .items(Joi.string().hostname()) - .sparse(false) - ) + whitelistedHosts: Joi.array() + .items(Joi.string().hostname()) + .sparse(false) .default([]), }) .default(); From e18606ce619e337cc1c15832a539360067c1ee5c Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 6 Sep 2019 10:22:49 -0400 Subject: [PATCH 4/5] Export saved objects based on search criteria (#44723) * export all saved objects returned from search, not all saved objects that exist * remove unused mock --- .../__jest__/objects_table.test.js | 12 +++---- .../__jest__/relationships.test.js | 4 --- .../components/objects_table/objects_table.js | 17 +++------- .../objects/lib/fetch_export_by_type.js | 31 ------------------- .../management/sections/objects/lib/index.js | 1 - 5 files changed, 9 insertions(+), 56 deletions(-) delete mode 100644 src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type.js diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js index 51f33f7568369e..0be6a98260554a 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/objects_table.test.js @@ -20,7 +20,7 @@ import React from 'react'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; -import { ObjectsTable, POSSIBLE_TYPES } from '../objects_table'; +import { ObjectsTable } from '../objects_table'; import { Flyout } from '../components/flyout/'; import { Relationships } from '../components/relationships/'; import { findObjects } from '../../../lib'; @@ -57,10 +57,6 @@ jest.mock('../../../lib/fetch_export_objects', () => ({ fetchExportObjects: jest.fn(), })); -jest.mock('../../../lib/fetch_export_by_type', () => ({ - fetchExportByType: jest.fn(), -})); - jest.mock('../../../lib/get_saved_object_counts', () => ({ getSavedObjectCounts: jest.fn().mockImplementation(() => { return { @@ -318,7 +314,7 @@ describe('ObjectsTable', () => { }); it('should export all', async () => { - const { fetchExportByType } = require('../../../lib/fetch_export_by_type'); + const { fetchExportObjects } = require('../../../lib/fetch_export_objects'); const { saveAs } = require('@elastic/filesaver'); const component = shallowWithIntl( { // Set up mocks const blob = new Blob([JSON.stringify(allSavedObjects)], { type: 'application/ndjson' }); - fetchExportByType.mockImplementation(() => blob); + fetchExportObjects.mockImplementation(() => blob); await component.instance().onExportAll(); - expect(fetchExportByType).toHaveBeenCalledWith(POSSIBLE_TYPES, true); + expect(fetchExportObjects).toHaveBeenCalledWith(allSavedObjects.map(so => ({ type: so.type, id: so.id })), true); expect(saveAs).toHaveBeenCalledWith(blob, 'export.ndjson'); expect(addSuccessMock).toHaveBeenCalledWith({ title: 'Your file is downloading in the background' }); }); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js index 9ad6190bc30d52..abb4df74275b2f 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js @@ -39,10 +39,6 @@ jest.mock('ui/chrome', () => ({ addBasePath: () => '' })); -jest.mock('../../../../../lib/fetch_export_by_type', () => ({ - fetchExportByType: jest.fn(), -})); - jest.mock('../../../../../lib/fetch_export_objects', () => ({ fetchExportObjects: jest.fn(), })); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js index 263b23859c8a5a..e1cda703e64b10 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js @@ -58,7 +58,6 @@ import { getRelationships, getSavedObjectLabel, fetchExportObjects, - fetchExportByType, findObjects, } from '../../lib'; import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; @@ -303,20 +302,14 @@ class ObjectsTableUI extends Component { onExportAll = async () => { const { intl } = this.props; - const { exportAllSelectedOptions, isIncludeReferencesDeepChecked } = this.state; - const exportTypes = Object.entries(exportAllSelectedOptions).reduce( - (accum, [id, selected]) => { - if (selected) { - accum.push(id); - } - return accum; - }, - [] - ); + + const { exportAllSelectedOptions, isIncludeReferencesDeepChecked, savedObjects } = this.state; + + const exportObjects = savedObjects.filter(so => exportAllSelectedOptions[so.type]).map(so => ({ type: so.type, id: so.id })); let blob; try { - blob = await fetchExportByType(exportTypes, isIncludeReferencesDeepChecked); + blob = await fetchExportObjects(exportObjects, isIncludeReferencesDeepChecked); } catch (e) { toastNotifications.addDanger({ title: intl.formatMessage({ diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type.js deleted file mode 100644 index 71c022b9d3998f..00000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/fetch_export_by_type.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { kfetch } from 'ui/kfetch'; - -export async function fetchExportByType(types, includeReferencesDeep = false) { - return await kfetch({ - method: 'POST', - pathname: '/api/saved_objects/_export', - body: JSON.stringify({ - type: types, - includeReferencesDeep, - }), - }); -} diff --git a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.js b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.js index 2818f0d8a6cb45..d79467f8d6dfad 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/objects/lib/index.js @@ -17,7 +17,6 @@ * under the License. */ -export * from './fetch_export_by_type'; export * from './fetch_export_objects'; export * from './in_app_url'; export * from './get_relationships'; From d9094574e8aa16565643dfb14f43b246d1760509 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Fri, 6 Sep 2019 08:31:23 -0600 Subject: [PATCH 5/5] [SIEM] Fixes escape bug for filterQuery (#43030) --- .../add_to_kql/__snapshots__/index.test.tsx.snap | 2 +- .../public/components/page/add_to_kql/index.test.tsx | 12 ++++++------ .../components/page/hosts/hosts_table/columns.tsx | 6 +++--- .../page/network/domains_table/columns.tsx | 2 +- .../plugins/siem/public/lib/keury/index.test.ts | 6 +++--- x-pack/legacy/plugins/siem/public/lib/keury/index.ts | 4 ++-- .../plugins/siem/public/pages/hosts/details/utils.ts | 2 +- .../plugins/siem/public/pages/hosts/helpers.ts | 4 ++-- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/page/add_to_kql/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/page/add_to_kql/__snapshots__/index.test.tsx.snap index 91f29aaf2a7fa2..a3d7e80d35d89f 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/add_to_kql/__snapshots__/index.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/page/add_to_kql/__snapshots__/index.test.tsx.snap @@ -14,7 +14,7 @@ exports[`AddToKql Component Rendering 1`] = ` > { filterQuery: { kuery: { kind: 'kuery', - expression: 'host.name: siem-kibana', + expression: 'host.name: "siem-kibana"', }, serializedQuery: - '{"bool":{"should":[{"match":{"host.name":"siem-kibana"}}],"minimum_should_match":1}}', + '{"bool":{"should":[{"match_phrase":{"host.name":"siem-kibana"}}],"minimum_should_match":1}}', }, filterQueryDraft: { kind: 'kuery', - expression: 'host.name: siem-kibana', + expression: 'host.name: "siem-kibana"', }, }); }); @@ -173,14 +173,14 @@ describe('AddToKql Component', () => { filterQuery: { kuery: { kind: 'kuery', - expression: 'host.name: siem-kibana', + expression: 'host.name: "siem-kibana"', }, serializedQuery: - '{"bool":{"should":[{"match":{"host.name":"siem-kibana"}}],"minimum_should_match":1}}', + '{"bool":{"should":[{"match_phrase":{"host.name":"siem-kibana"}}],"minimum_should_match":1}}', }, filterQueryDraft: { kind: 'kuery', - expression: 'host.name: siem-kibana', + expression: 'host.name: "siem-kibana"', }, }); }); diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/columns.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/columns.tsx index 1b72601a8cef2e..3391091b801c49 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/columns.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/hosts_table/columns.tsx @@ -57,7 +57,7 @@ export const getHostsColumns = ( ) : ( @@ -106,7 +106,7 @@ export const getHostsColumns = ( return ( @@ -128,7 +128,7 @@ export const getHostsColumns = ( return ( diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/domains_table/columns.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/domains_table/columns.tsx index c0342eca08b47b..24820b637d388e 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/domains_table/columns.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/domains_table/columns.tsx @@ -106,7 +106,7 @@ export const getDomainsColumns = ( key={escapeDataProviderId( `${tableId}-table-${flowTarget}-${flowDirection}-direction-${direction}` )} - expression={`network.direction: "${escapeQueryValue(direction)}"`} + expression={`network.direction: ${escapeQueryValue(direction)}`} type={type} componentFilterType={'network'} > diff --git a/x-pack/legacy/plugins/siem/public/lib/keury/index.test.ts b/x-pack/legacy/plugins/siem/public/lib/keury/index.test.ts index 889ff480cd8dde..4e2b11b24e5a98 100644 --- a/x-pack/legacy/plugins/siem/public/lib/keury/index.test.ts +++ b/x-pack/legacy/plugins/siem/public/lib/keury/index.test.ts @@ -22,7 +22,7 @@ describe('Kuery escape', () => { it('should escape special characters', () => { const value = `This \\ has (a lot of) characters, don't you *think*? "Yes."`; - const expected = `This \\\\ has \\(a lot of\\) \\ characters, don't you \\*think\\*? \\"Yes.\\"`; + const expected = `This \\ has (a lot of) characters, don't you *think*? \\"Yes.\\"`; expect(escapeKuery(value)).to.be(expected); }); @@ -51,8 +51,8 @@ describe('Kuery escape', () => { }); it('should escape both keywords and special characters', () => { - const value = 'Hello, world, and to meet you!'; - const expected = 'Hello, world, \\and \\ to meet you!'; + const value = 'Hello, "world", and to meet you!'; + const expected = 'Hello, \\"world\\", \\and to meet you!'; expect(escapeKuery(value)).to.be(expected); }); diff --git a/x-pack/legacy/plugins/siem/public/lib/keury/index.ts b/x-pack/legacy/plugins/siem/public/lib/keury/index.ts index c8c4319eeb1344..9cbe17ee6eb37e 100644 --- a/x-pack/legacy/plugins/siem/public/lib/keury/index.ts +++ b/x-pack/legacy/plugins/siem/public/lib/keury/index.ts @@ -28,7 +28,7 @@ export const escapeQueryValue = (val: number | string = ''): string | number => if (isEmpty(val)) { return '""'; } - return val.split(' ').length > 1 ? `"${escapeKuery(val)}"` : escapeKuery(val); + return `"${escapeKuery(val)}"`; } return val; @@ -52,7 +52,7 @@ const escapeWhitespace = (val: string) => .replace(/\n/g, '\\n'); // See the SpecialCharacter rule in kuery.peg -const escapeSpecialCharacters = (val: string) => val.replace(/[\\():<>"*]/g, '\\$&'); // $& means the whole matched string +const escapeSpecialCharacters = (val: string) => val.replace(/["]/g, '\\$&'); // $& means the whole matched string // See the Keyword rule in kuery.peg const escapeAndOr = (val: string) => val.replace(/(\s+)(and|or)(\s+)/gi, '$1\\$2$3'); diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/utils.ts b/x-pack/legacy/plugins/siem/public/pages/hosts/details/utils.ts index cd4239f00cac7f..f1c393dec04c70 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/utils.ts +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/utils.ts @@ -75,7 +75,7 @@ export const getFilterQuery = ( : '' : convertKueryToElasticSearchQuery( `${filterQueryExpression} ${ - hostName ? `and host.name: "${escapeQueryValue(hostName)}"` : '' + hostName ? `and host.name: ${escapeQueryValue(hostName)}` : '' }`, indexPattern ); diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/helpers.ts b/x-pack/legacy/plugins/siem/public/pages/hosts/helpers.ts index 35dd9b865d56c5..03d84c032c024c 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/helpers.ts +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/helpers.ts @@ -16,9 +16,9 @@ export const getHostDetailsEventsKqlQueryExpression = ({ }): string => { if (filterQueryExpression.length) { return `${filterQueryExpression}${ - hostName.length ? ` and host.name: "${escapeQueryValue(hostName)}"` : '' + hostName.length ? ` and host.name: ${escapeQueryValue(hostName)}` : '' }`; } else { - return hostName.length ? `host.name: "${escapeQueryValue(hostName)}"` : ''; + return hostName.length ? `host.name: ${escapeQueryValue(hostName)}` : ''; } };