From af21c66d5c19889a151dcaf2a5d59bb8d76dd68c Mon Sep 17 00:00:00 2001
From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com>
Date: Tue, 25 Jun 2019 14:41:44 -0400
Subject: [PATCH] happy merging back to legacy (#39166)
---
.../components/scroll_to_top/index.test.tsx | 9 +-
.../__snapshots__/index.test.tsx.snap | 14 +-
.../components/url_state/index.test.tsx | 197 +++++++++----
.../public/components/url_state/index.tsx | 221 +--------------
.../url_state/index_mocked.test.tsx | 116 ++++----
.../components/url_state/test_dependencies.ts | 1 +
.../siem/public/components/url_state/types.ts | 13 +-
.../components/url_state/use_url_state.tsx | 246 ++++++++++++++++
.../containers/authentications/index.tsx | 2 +
.../siem/public/containers/domains/index.tsx | 2 +
.../siem/public/containers/events/index.tsx | 2 +
.../siem/public/containers/hosts/index.tsx | 2 +
.../containers/hosts/overview/index.tsx | 2 +
.../public/containers/ip_overview/index.tsx | 3 +-
.../public/containers/kpi_hosts/index.tsx | 3 +-
.../public/containers/kpi_network/index.tsx | 3 +-
.../public/containers/network_dns/index.tsx | 2 +
.../containers/network_top_n_flow/index.tsx | 2 +
.../siem/public/containers/query_template.tsx | 5 +-
.../siem/public/containers/tls/index.tsx | 2 +
.../containers/uncommon_processes/index.tsx | 2 +
.../siem/public/containers/users/index.tsx | 2 +
.../plugins/siem/public/mock/hook_wrapper.tsx | 2 +-
.../legacy/plugins/siem/public/mock/index.ts | 2 +
.../legacy/plugins/siem/public/mock/utils.ts | 12 +
.../plugins/siem/public/pages/home/index.tsx | 2 -
.../siem/public/pages/hosts/host_details.tsx | 223 ++++++++-------
.../plugins/siem/public/pages/hosts/hosts.tsx | 267 ++++++++++--------
.../siem/public/pages/network/ip_details.tsx | 211 +++++++-------
.../siem/public/pages/network/network.tsx | 142 +++++-----
30 files changed, 971 insertions(+), 741 deletions(-)
create mode 100644 x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx
create mode 100644 x-pack/legacy/plugins/siem/public/mock/utils.ts
diff --git a/x-pack/legacy/plugins/siem/public/components/scroll_to_top/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/scroll_to_top/index.test.tsx
index 3c0cb3096e915..66d7d2764511f 100644
--- a/x-pack/legacy/plugins/siem/public/components/scroll_to_top/index.test.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/scroll_to_top/index.test.tsx
@@ -7,16 +7,9 @@
import { mount } from 'enzyme';
import * as React from 'react';
-import { HookWrapper } from '../../mock/hook_wrapper';
+import { globalNode, HookWrapper } from '../../mock';
import { scrollToTop } from '.';
-interface Global extends NodeJS.Global {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- window?: any;
-}
-
-const globalNode: Global = global;
-
const spyScroll = jest.fn();
const spyScrollTo = jest.fn();
diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/url_state/__snapshots__/index.test.tsx.snap
index e5ac56086af37..34b1175bcb2fc 100644
--- a/x-pack/legacy/plugins/siem/public/components/url_state/__snapshots__/index.test.tsx.snap
+++ b/x-pack/legacy/plugins/siem/public/components/url_state/__snapshots__/index.test.tsx.snap
@@ -353,7 +353,7 @@ exports[`UrlStateContainer mounts and renders 1`] = `
}
}
>
-
-
-
-
+ >
+
+
+
-
+
diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/index.test.tsx
index fe0e3d077a3e1..2b3b1f463daa0 100644
--- a/x-pack/legacy/plugins/siem/public/components/url_state/index.test.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/url_state/index.test.tsx
@@ -3,16 +3,24 @@
* 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 { Location } from 'history';
+import { mount } from 'enzyme';
import toJson from 'enzyme-to-json';
import * as React from 'react';
import { Router } from 'react-router-dom';
import { MockedProvider } from 'react-apollo/test-utils';
import { StaticIndexPattern } from 'ui/index_patterns';
-import { UrlStateContainer, UrlStateContainerLifecycle } from './';
-import { UrlStateContainerPropTypes } from './types';
+import {
+ apolloClientObservable,
+ globalNode,
+ HookWrapper,
+ mockGlobalState,
+ TestProviders,
+} from '../../mock';
+import { createStore, State } from '../../store';
+
+import { UseUrlState } from './';
import {
defaultProps,
getMockPropsObj,
@@ -20,8 +28,9 @@ import {
serializedFilterQuery,
testCases,
} from './test_dependencies';
-import { apolloClientObservable, mockGlobalState, TestProviders } from '../../mock';
-import { createStore, State } from '../../store';
+import { UrlStateContainerPropTypes } from './types';
+import { useUrlStateHooks, initializeLocation } from './use_url_state';
+import { wait } from 'react-testing-library';
let mockProps: UrlStateContainerPropTypes;
@@ -52,7 +61,9 @@ describe('UrlStateContainer', () => {
-
+
+ {({ isInitializing }) => {isInitializing}}
+
@@ -68,24 +79,27 @@ describe('UrlStateContainer', () => {
test.each(testCases)('%o', (page, namespaceLower, namespaceUpper, examplePath, type) => {
mockProps = getMockPropsObj({ page, examplePath, namespaceLower, type })
.relativeTimeSearch.undefinedQuery;
- shallow();
- // @ts-ignore property mock does not exists
- expect(defaultProps.setRelativeTimerange.mock.calls[0][0]).toEqual({
- from: 1558591200000,
- fromStr: 'now-1d/d',
- kind: 'relative',
- to: 1558677599999,
- toStr: 'now-1d/d',
- id: 'global',
- });
- // @ts-ignore property mock does not exists
- expect(defaultProps.setRelativeTimerange.mock.calls[1][0]).toEqual({
- from: 1558732849370,
- fromStr: 'now-15m',
- kind: 'relative',
- to: 1558733749370,
- toStr: 'now',
- id: 'timeline',
+ mount( useUrlStateHooks(mockProps)} />);
+
+ wait(() => {
+ // @ts-ignore property mock does not exists
+ expect(defaultProps.setRelativeTimerange.mock.calls[0][0]).toEqual({
+ from: 1558591200000,
+ fromStr: 'now-1d/d',
+ kind: 'relative',
+ to: 1558677599999,
+ toStr: 'now-1d/d',
+ id: 'global',
+ });
+ // @ts-ignore property mock does not exists
+ expect(defaultProps.setRelativeTimerange.mock.calls[1][0]).toEqual({
+ from: 1558732849370,
+ fromStr: 'now-15m',
+ kind: 'relative',
+ to: 1558733749370,
+ toStr: 'now',
+ id: 'timeline',
+ });
});
});
});
@@ -93,20 +107,23 @@ describe('UrlStateContainer', () => {
test.each(testCases)('%o', (page, namespaceLower, namespaceUpper, examplePath, type) => {
mockProps = getMockPropsObj({ page, examplePath, namespaceLower, type })
.absoluteTimeSearch.undefinedQuery;
- shallow();
- // @ts-ignore property mock does not exists
- expect(defaultProps.setAbsoluteTimerange.mock.calls[0][0]).toEqual({
- from: 1556736012685,
- kind: 'absolute',
- to: 1556822416082,
- id: 'global',
- });
- // @ts-ignore property mock does not exists
- expect(defaultProps.setAbsoluteTimerange.mock.calls[1][0]).toEqual({
- from: 1556736012685,
- kind: 'absolute',
- to: 1556822416082,
- id: 'timeline',
+ mount( useUrlStateHooks(mockProps)} />);
+
+ wait(() => {
+ // @ts-ignore property mock does not exists
+ expect(defaultProps.setAbsoluteTimerange.mock.calls[0][0]).toEqual({
+ from: 1556736012685,
+ kind: 'absolute',
+ to: 1556822416082,
+ id: 'global',
+ });
+ // @ts-ignore property mock does not exists
+ expect(defaultProps.setAbsoluteTimerange.mock.calls[1][0]).toEqual({
+ from: 1556736012685,
+ kind: 'absolute',
+ to: 1556822416082,
+ id: 'timeline',
+ });
});
});
});
@@ -114,13 +131,15 @@ describe('UrlStateContainer', () => {
test.each(testCases)(' %o', (page, namespaceLower, namespaceUpper, examplePath, type) => {
mockProps = getMockPropsObj({ page, examplePath, namespaceLower, type })
.relativeTimeSearch.undefinedQuery;
- shallow();
- const functionName =
- namespaceUpper === 'Network' ? defaultProps.setNetworkKql : defaultProps.setHostsKql;
- // @ts-ignore property mock does not exists
- expect(functionName.mock.calls[0][0]).toEqual({
- filterQuery: serializedFilterQuery,
- [`${namespaceLower}Type`]: type,
+ mount( useUrlStateHooks(mockProps)} />);
+ wait(() => {
+ const functionName =
+ namespaceUpper === 'Network' ? defaultProps.setNetworkKql : defaultProps.setHostsKql;
+ // @ts-ignore property mock does not exists
+ expect(functionName.mock.calls[0][0]).toEqual({
+ filterQuery: serializedFilterQuery,
+ [`${namespaceLower}Type`]: type,
+ });
});
});
});
@@ -130,11 +149,15 @@ describe('UrlStateContainer', () => {
async (page, namespaceLower, namespaceUpper, examplePath, type) => {
mockProps = getMockPropsObj({ page, examplePath, namespaceLower, type })
.oppositeQueryLocationSearch.undefinedQuery;
- shallow();
- const functionName =
- namespaceUpper === 'Network' ? defaultProps.setNetworkKql : defaultProps.setHostsKql;
- // @ts-ignore property mock does not exists
- expect(functionName.mock.calls.length).toEqual(0);
+ mount( useUrlStateHooks(mockProps)} />);
+ wait(() => {
+ const functionName =
+ namespaceUpper === 'Network'
+ ? defaultProps.setNetworkKql
+ : defaultProps.setHostsKql;
+ // @ts-ignore property mock does not exists
+ expect(functionName.mock.calls.length).toEqual(0);
+ });
}
);
});
@@ -147,18 +170,76 @@ describe('UrlStateContainer', () => {
async (page, namespaceLower, namespaceUpper, examplePath, type) => {
mockProps = getMockPropsObj({ page, examplePath, namespaceLower, type }).noSearch
.definedQuery;
- shallow();
+ mount( useUrlStateHooks(mockProps)} />);
- // @ts-ignore property mock does not exists
- expect(mockHistory.replace.mock.calls[0][0]).toEqual({
- hash: '',
- pathname: examplePath,
- search: `?_g=()&kqlQuery=(filterQuery:(expression:'host.name:%22siem-es%22',kind:kuery),queryLocation:${page},type:${type})`,
- state: '',
+ wait(() => {
+ // @ts-ignore property mock does not exists
+ expect(mockHistory.replace.mock.calls[0][0]).toEqual({
+ hash: '',
+ pathname: examplePath,
+ search: `?_g=()&kqlQuery=(filterQuery:(expression:'host.name:%22siem-es%22',kind:kuery),queryLocation:${page},type:${type})`,
+ state: '',
+ });
});
}
);
});
});
});
+
+ describe('initializeLocation', () => {
+ test('basic functionality with no search', () => {
+ Object.defineProperty(globalNode.window, 'location', {
+ value: {
+ href: 'http://localhost:5601/app/siem#/hosts?_g=()',
+ },
+ writable: true,
+ });
+ const location: Location = {
+ hash: '',
+ pathname: '/hosts',
+ search: '?_g=()',
+ state: null,
+ };
+ expect(initializeLocation(location).search).toEqual('?_g=()');
+ });
+ test('basic functionality with search', () => {
+ Object.defineProperty(globalNode.window, 'location', {
+ value: {
+ href:
+ "http://localhost:5601/app/siem#/hosts?_g=()&kqlQuery=(filterQuery:(expression:'%20host.name:%20%22beats-ci-immutable-ubuntu-1604-1560801145745062645%22%20and%20process.name:*',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1560714985274,fromStr:now-24h,kind:relative,to:1560801385274,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1560714985274,fromStr:now-24h,kind:relative,to:1560801385274,toStr:now)))",
+ },
+ writable: true,
+ });
+ const location: Location = {
+ hash: '',
+ pathname: '/hosts',
+ search:
+ "?_g=()&kqlQuery=(filterQuery:(expression:'%2Bhost.name:%2B%22beats-ci-immutable-ubuntu-1604-1560801145745062645%22%2Band%2Bprocess.name:*',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1560714985274,fromStr:now-24h,kind:relative,to:1560801385274,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1560714985274,fromStr:now-24h,kind:relative,to:1560801385274,toStr:now)))",
+ state: null,
+ };
+ expect(initializeLocation(location).search).toEqual(
+ "?_g=()&kqlQuery=(filterQuery:(expression:'%20host.name:%20%22beats-ci-immutable-ubuntu-1604-1560801145745062645%22%20and%20process.name:*',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1560714985274,fromStr:now-24h,kind:relative,to:1560801385274,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1560714985274,fromStr:now-24h,kind:relative,to:1560801385274,toStr:now)))"
+ );
+ });
+ test('If hash and pathname do not match href from the hash, do not do anything', () => {
+ Object.defineProperty(globalNode.window, 'location', {
+ value: {
+ href:
+ "http://localhost:5601/app/siem#/hosts?_g=()&kqlQuery=(filterQuery:(expression:'%20host.name:%20%22beats-ci-immutable-ubuntu-1604-1560801145745062645%22%20and%20process.name:*',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1560714985274,fromStr:now-24h,kind:relative,to:1560801385274,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1560714985274,fromStr:now-24h,kind:relative,to:1560801385274,toStr:now)))",
+ },
+ writable: true,
+ });
+ const location: Location = {
+ hash: '',
+ pathname: '/network',
+ search:
+ "?_g=()&kqlQuery=(filterQuery:(expression:'%2Bhost.name:%2B%22beats-ci-immutable-ubuntu-1604-1560801145745062645%22%2Band%2Bprocess.name:*',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1560714985274,fromStr:now-24h,kind:relative,to:1560801385274,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1560714985274,fromStr:now-24h,kind:relative,to:1560801385274,toStr:now)))",
+ state: null,
+ };
+ expect(initializeLocation(location).search).toEqual(
+ "?_g=()&kqlQuery=(filterQuery:(expression:'%2Bhost.name:%2B%22beats-ci-immutable-ubuntu-1604-1560801145745062645%22%2Band%2Bprocess.name:*',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1560714985274,fromStr:now-24h,kind:relative,to:1560801385274,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1560714985274,fromStr:now-24h,kind:relative,to:1560801385274,toStr:now)))"
+ );
+ });
+ });
});
diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx
index f46d8bf8f8b3a..23b02bdb90220 100644
--- a/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx
@@ -4,14 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { Location } from 'history';
-import { get, throttle } from 'lodash/fp';
import React from 'react';
import { compose } from 'redux';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
-import { hostsActions, inputsActions, networkActions } from '../../store/actions';
import {
hostsModel,
hostsSelectors,
@@ -20,214 +17,16 @@ import {
networkSelectors,
State,
} from '../../store';
-import {
- AbsoluteTimeRange,
- LinkTo,
- RelativeTimeRange,
- UrlInputsModel,
-} from '../../store/inputs/model';
-import { convertKueryToElasticSearchQuery } from '../../lib/keury';
-import { URL_STATE_KEYS, LOCATION_MAPPED_TO_MODEL, LOCATION_KEYS } from './types';
-import {
- decodeRisonUrlState,
- getCurrentLocation,
- getParamFromQueryString,
- getQueryStringFromLocation,
- isKqlForRoute,
- replaceQueryStringInLocation,
- replaceStateKeyInQueryString,
-} from './helpers';
-import {
- KeyUrlState,
- KqlQuery,
- KqlQueryObject,
- LocationKeysType,
- LocationTypes,
- UrlStateContainerPropTypes,
- UrlStateProps,
-} from './types';
-import { CONSTANTS } from './constants';
-import { InputsModelId, TimeRangeKinds } from '../../store/inputs/constants';
-import { normalizeTimeRange } from './normalize_time_range';
-
-export class UrlStateContainerLifecycle extends React.Component {
- public render() {
- return null;
- }
-
- public componentDidUpdate({
- location: prevLocation,
- urlState: prevUrlState,
- }: UrlStateContainerPropTypes) {
- const { location, urlState } = this.props;
-
- if (JSON.stringify(urlState) !== JSON.stringify(prevUrlState)) {
- URL_STATE_KEYS.forEach((urlKey: KeyUrlState) => {
- if (
- urlState[urlKey] &&
- JSON.stringify(urlState[urlKey]) !== JSON.stringify(prevUrlState[urlKey])
- ) {
- if (urlKey === CONSTANTS.kqlQuery) {
- LOCATION_KEYS.forEach((queryLocation: LocationKeysType) => {
- if (
- !!urlState[CONSTANTS.kqlQuery][queryLocation] &&
- JSON.stringify(urlState[CONSTANTS.kqlQuery][queryLocation]) !==
- JSON.stringify(prevUrlState[CONSTANTS.kqlQuery][queryLocation])
- ) {
- this.replaceStateInLocation(
- urlState[CONSTANTS.kqlQuery][queryLocation],
- CONSTANTS.kqlQuery
- );
- }
- });
- } else {
- this.replaceStateInLocation(urlState[urlKey], urlKey);
- }
- }
- });
- } else if (location.pathname !== prevLocation.pathname) {
- this.handleInitialize(location);
- }
- }
-
- public componentWillMount() {
- const { location } = this.props;
- this.handleInitialize(location);
- }
-
- private replaceStateInLocation = throttle(
- 1000,
- (urlState: UrlInputsModel | KqlQuery, urlStateKey: string) => {
- const { history, location } = this.props;
- const newLocation = replaceQueryStringInLocation(
- location,
- replaceStateKeyInQueryString(urlStateKey, urlState)(getQueryStringFromLocation(location))
- );
- if (newLocation !== location) {
- history.replace(newLocation);
- }
- }
- );
+import { hostsActions, inputsActions, networkActions } from '../../store/actions';
- private setInitialStateFromUrl = (
- urlKey: KeyUrlState,
- newUrlStateString: string,
- location: Location
- ) => {
- if (urlKey === CONSTANTS.timerange) {
- const timerangeStateData: UrlInputsModel = decodeRisonUrlState(newUrlStateString);
- const globalId: InputsModelId = 'global';
- const globalLinkTo: LinkTo = { linkTo: get('global.linkTo', timerangeStateData) };
- const globalType: TimeRangeKinds = get('global.timerange.kind', timerangeStateData);
- if (globalType) {
- if (globalLinkTo.linkTo.length === 0) {
- this.props.toggleTimelineLinkTo({ linkToId: 'global' });
- }
- if (globalType === 'absolute') {
- const absoluteRange = normalizeTimeRange(
- get('global.timerange', timerangeStateData)
- );
- this.props.setAbsoluteTimerange({
- ...absoluteRange,
- id: globalId,
- });
- }
- if (globalType === 'relative') {
- const relativeRange = normalizeTimeRange(
- get('global.timerange', timerangeStateData)
- );
- this.props.setRelativeTimerange({
- ...relativeRange,
- id: globalId,
- });
- }
- }
- const timelineId: InputsModelId = 'timeline';
- const timelineLinkTo: LinkTo = { linkTo: get('timeline.linkTo', timerangeStateData) };
- const timelineType: TimeRangeKinds = get('timeline.timerange.kind', timerangeStateData);
- if (timelineType) {
- if (timelineLinkTo.linkTo.length === 0) {
- this.props.toggleTimelineLinkTo({ linkToId: 'timeline' });
- }
- if (timelineType === 'absolute') {
- const absoluteRange = normalizeTimeRange(
- get('timeline.timerange', timerangeStateData)
- );
- this.props.setAbsoluteTimerange({
- ...absoluteRange,
- id: timelineId,
- });
- }
- if (timelineType === 'relative') {
- const relativeRange = normalizeTimeRange(
- get('timeline.timerange', timerangeStateData)
- );
- this.props.setRelativeTimerange({
- ...relativeRange,
- id: timelineId,
- });
- }
- }
- }
- if (urlKey === CONSTANTS.kqlQuery) {
- const kqlQueryStateData: KqlQuery = decodeRisonUrlState(newUrlStateString);
- if (isKqlForRoute(location.pathname, kqlQueryStateData)) {
- const filterQuery = {
- kuery: kqlQueryStateData.filterQuery,
- serializedQuery: convertKueryToElasticSearchQuery(
- kqlQueryStateData.filterQuery ? kqlQueryStateData.filterQuery.expression : '',
- this.props.indexPattern
- ),
- };
- if (
- kqlQueryStateData.queryLocation === CONSTANTS.hostsPage ||
- kqlQueryStateData.queryLocation === CONSTANTS.hostsDetails
- ) {
- const hostsType = LOCATION_MAPPED_TO_MODEL[kqlQueryStateData.queryLocation];
- this.props.setHostsKql({
- filterQuery,
- hostsType,
- });
- }
- if (
- kqlQueryStateData.queryLocation === CONSTANTS.networkPage ||
- kqlQueryStateData.queryLocation === CONSTANTS.networkDetails
- ) {
- const networkType = LOCATION_MAPPED_TO_MODEL[kqlQueryStateData.queryLocation];
- this.props.setNetworkKql({
- filterQuery,
- networkType,
- });
- }
- }
- }
- };
+import { CONSTANTS } from './constants';
+import { UrlStateContainerPropTypes, UrlStateProps, KqlQueryObject } from './types';
+import { useUrlStateHooks } from './use_url_state';
- private handleInitialize = (location: Location) => {
- URL_STATE_KEYS.forEach((urlKey: KeyUrlState) => {
- const newUrlStateString = getParamFromQueryString(
- getQueryStringFromLocation(location),
- urlKey
- );
- if (newUrlStateString) {
- this.setInitialStateFromUrl(urlKey, newUrlStateString, location);
- } else {
- if (urlKey === CONSTANTS.timerange) {
- this.replaceStateInLocation(this.props.urlState[urlKey], urlKey);
- }
- if (urlKey === CONSTANTS.kqlQuery) {
- const currentLocation: LocationTypes = getCurrentLocation(location.pathname);
- if (currentLocation !== null) {
- this.replaceStateInLocation(
- this.props.urlState[CONSTANTS.kqlQuery][currentLocation],
- urlKey
- );
- }
- }
- }
- });
- };
-}
+export const UrlStateContainer = (props: UrlStateContainerPropTypes) => {
+ const { isInitializing } = useUrlStateHooks(props);
+ return props.children({ isInitializing });
+};
const makeMapStateToProps = () => {
const getInputsSelector = inputsSelectors.inputsSelector();
@@ -281,7 +80,7 @@ const makeMapStateToProps = () => {
return mapStateToProps;
};
-export const UrlStateContainer = compose>(
+export const UseUrlState = compose>(
withRouter,
connect(
makeMapStateToProps,
@@ -293,4 +92,4 @@ export const UrlStateContainer = compose>(
toggleTimelineLinkTo: inputsActions.toggleTimelineLinkTo,
}
)
-)(UrlStateContainerLifecycle);
+)(UrlStateContainer);
diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/index_mocked.test.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/index_mocked.test.tsx
index 309d1b39f3486..04d23835aeb96 100644
--- a/x-pack/legacy/plugins/siem/public/components/url_state/index_mocked.test.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/url_state/index_mocked.test.tsx
@@ -4,14 +4,18 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { shallow } from 'enzyme';
+import { mount } from 'enzyme';
import { throttle } from 'lodash/fp';
import * as React from 'react';
-import { UrlStateContainerLifecycle } from './';
-import { getMockPropsObj, mockHistory, filterQuery, testCases } from './test_dependencies';
+
+import { HookWrapper } from '../../mock/hook_wrapper';
import { hostsModel, networkModel } from '../../store';
-import { UrlStateContainerPropTypes } from './types';
+
import { CONSTANTS } from './constants';
+import { getMockPropsObj, mockHistory, filterQuery, testCases } from './test_dependencies';
+import { UrlStateContainerPropTypes } from './types';
+import { useUrlStateHooks } from './use_url_state';
+import { wait } from 'react-testing-library';
jest.mock('lodash/fp');
@@ -34,7 +38,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () =>
namespaceLower: 'network',
type: networkModel.NetworkType.page,
}).noSearch.definedQuery;
- const wrapper = shallow();
+ const wrapper = mount( useUrlStateHooks(mockProps)} />);
const newUrlState = {
...mockProps.urlState,
@@ -61,17 +65,19 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () =>
},
},
};
-
- wrapper.setProps({ urlState: newUrlState });
- wrapper.update();
- expect(mockHistory.replace.mock.calls[2][0]).toStrictEqual({
- hash: '',
- pathname: '/network',
- search:
- '?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:0,fromStr:now-24h,kind:relative,to:1,toStr:now)),timeline:(linkTo:!(global),timerange:(from:0,fromStr:now-24h,kind:relative,to:1,toStr:now)))',
- state: '',
+ wait(() => {
+ wrapper.setProps({ urlState: newUrlState });
+ wrapper.update();
+ expect(mockHistory.replace.mock.calls[2][0]).toStrictEqual({
+ hash: '',
+ pathname: '/network',
+ search:
+ '?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:0,fromStr:now-24h,kind:relative,to:1,toStr:now)),timeline:(linkTo:!(global),timerange:(from:0,fromStr:now-24h,kind:relative,to:1,toStr:now)))',
+ state: '',
+ });
});
});
+
test('kql query redux state updates the url', () => {
mockProps = getMockPropsObj({
page: CONSTANTS.networkPage,
@@ -79,7 +85,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () =>
namespaceLower: 'network',
type: networkModel.NetworkType.page,
}).noSearch.definedQuery;
- const wrapper = shallow();
+ const wrapper = mount( useUrlStateHooks(mockProps)} />);
const newUrlState = {
[CONSTANTS.kqlQuery]: {
@@ -91,15 +97,17 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () =>
},
};
- wrapper.setProps({ urlState: newUrlState });
- wrapper.update();
+ wait(() => {
+ wrapper.setProps({ urlState: newUrlState });
+ wrapper.update();
- expect(mockHistory.replace.mock.calls[0][0]).toStrictEqual({
- hash: '',
- pathname: '/network',
- search:
- "?_g=()&kqlQuery=(filterQuery:(expression:'host.name:%22siem-es%22',kind:kuery),queryLocation:network.page,type:page)",
- state: '',
+ expect(mockHistory.replace.mock.calls[0][0]).toStrictEqual({
+ hash: '',
+ pathname: '/network',
+ search:
+ "?_g=()&kqlQuery=(filterQuery:(expression:'host.name:%22siem-es%22',kind:kuery),queryLocation:network.page,type:page)",
+ state: '',
+ });
});
});
});
@@ -110,21 +118,23 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () =>
test.each(testCases)('%o', (page, namespaceLower, namespaceUpper, examplePath, type) => {
mockProps = getMockPropsObj({ page, examplePath, namespaceLower, type }).noSearch
.undefinedQuery;
- shallow();
+ mount( useUrlStateHooks(mockProps)} />);
- expect(mockHistory.replace.mock.calls[0][0]).toEqual({
- hash: '',
- pathname: examplePath,
- search: `?_g=()&kqlQuery=(filterQuery:!n,queryLocation:${page},type:${type})`,
- state: '',
- });
+ wait(() => {
+ expect(mockHistory.replace.mock.calls[0][0]).toEqual({
+ hash: '',
+ pathname: examplePath,
+ search: `?_g=()&kqlQuery=(filterQuery:!n,queryLocation:${page},type:${type})`,
+ state: '',
+ });
- expect(mockHistory.replace.mock.calls[1][0]).toEqual({
- hash: '',
- pathname: examplePath,
- search:
- '?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))',
- state: '',
+ expect(mockHistory.replace.mock.calls[1][0]).toEqual({
+ hash: '',
+ pathname: examplePath,
+ search:
+ '?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))',
+ state: '',
+ });
});
});
});
@@ -142,24 +152,26 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () =>
namespaceLower: 'network',
type: networkModel.NetworkType.page,
}).noSearch.undefinedQuery;
- const wrapper = shallow();
+ const wrapper = mount( useUrlStateHooks(mockProps)} />);
- // @ts-ignore ignore staticContext warning
- wrapper.setProps(updatedProps);
- wrapper.update();
- // sets new kqlQuery
- expect(mockHistory.replace.mock.calls[2][0]).toEqual({
- hash: '',
- pathname: '/network',
- search: `?_g=()&kqlQuery=(filterQuery:!n,queryLocation:${CONSTANTS.networkPage},type:${
- networkModel.NetworkType.page
- })`,
- state: '',
+ wait(() => {
+ // @ts-ignore ignore staticContext warning
+ wrapper.setProps(updatedProps);
+ wrapper.update();
+ // sets new kqlQuery
+ expect(mockHistory.replace.mock.calls[2][0]).toEqual({
+ hash: '',
+ pathname: '/network',
+ search: `?_g=()&kqlQuery=(filterQuery:!n,queryLocation:${CONSTANTS.networkPage},type:${
+ networkModel.NetworkType.page
+ })`,
+ state: '',
+ });
+ // sets same timeline
+ expect(mockHistory.replace.mock.calls[3][0].search).toEqual(
+ mockHistory.replace.mock.calls[1][0].search
+ );
});
- // sets same timeline
- expect(mockHistory.replace.mock.calls[3][0].search).toEqual(
- mockHistory.replace.mock.calls[1][0].search
- );
});
});
});
diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/test_dependencies.ts b/x-pack/legacy/plugins/siem/public/components/url_state/test_dependencies.ts
index 39a69d7ada7f6..86c3f2c422d64 100644
--- a/x-pack/legacy/plugins/siem/public/components/url_state/test_dependencies.ts
+++ b/x-pack/legacy/plugins/siem/public/components/url_state/test_dependencies.ts
@@ -47,6 +47,7 @@ export const mockHistory = {
};
export const defaultProps: UrlStateContainerPropTypes = {
+ children: jest.fn(),
match: {
isExact: true,
params: '',
diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/types.ts b/x-pack/legacy/plugins/siem/public/components/url_state/types.ts
index 520d263a2cf2e..b3ee1758fb775 100644
--- a/x-pack/legacy/plugins/siem/public/components/url_state/types.ts
+++ b/x-pack/legacy/plugins/siem/public/components/url_state/types.ts
@@ -4,12 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { StaticIndexPattern } from 'ui/index_patterns';
-import { ActionCreator } from 'typescript-fsa';
+import { Location } from 'history';
import { RouteComponentProps } from 'react-router';
+import { ActionCreator } from 'typescript-fsa';
+import { StaticIndexPattern } from 'ui/index_patterns';
+
import { hostsModel, KueryFilterQuery, networkModel, SerializedFilterQuery } from '../../store';
import { UrlInputsModel } from '../../store/inputs/model';
import { InputsModelId } from '../../store/inputs/constants';
+
import { CONSTANTS } from './constants';
export const LOCATION_KEYS: LocationKeysType[] = [
@@ -76,6 +79,7 @@ export interface UrlState {
export type KeyUrlState = keyof UrlState;
export interface UrlStateProps {
+ children: (args: { isInitializing: boolean }) => React.ReactNode;
indexPattern: StaticIndexPattern;
mapToUrlState?: (value: string) => UrlState;
onChange?: (urlState: UrlState, previousUrlState: UrlState) => void;
@@ -118,3 +122,8 @@ export type UrlStateContainerPropTypes = RouteComponentProps &
UrlStateStateToPropsType &
UrlStateDispatchToPropsType &
UrlStateProps;
+
+export interface PreviousLocationUrlState {
+ location: Location;
+ urlState: UrlState;
+}
diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx
new file mode 100644
index 0000000000000..c70dd1408d74b
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/components/url_state/use_url_state.tsx
@@ -0,0 +1,246 @@
+/*
+ * 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 { Location } from 'history';
+import { throttle, get, isEqual } from 'lodash/fp';
+import { useState, useEffect, useRef } from 'react';
+
+import { convertKueryToElasticSearchQuery } from '../../lib/keury';
+import { InputsModelId, TimeRangeKinds } from '../../store/inputs/constants';
+import {
+ AbsoluteTimeRange,
+ LinkTo,
+ RelativeTimeRange,
+ UrlInputsModel,
+} from '../../store/inputs/model';
+
+import { CONSTANTS } from './constants';
+import {
+ replaceQueryStringInLocation,
+ getQueryStringFromLocation,
+ replaceStateKeyInQueryString,
+ getParamFromQueryString,
+ getCurrentLocation,
+ decodeRisonUrlState,
+ isKqlForRoute,
+} from './helpers';
+import { normalizeTimeRange } from './normalize_time_range';
+import {
+ UrlStateContainerPropTypes,
+ PreviousLocationUrlState,
+ URL_STATE_KEYS,
+ KeyUrlState,
+ LocationKeysType,
+ LOCATION_KEYS,
+ KqlQuery,
+ LocationTypes,
+ LOCATION_MAPPED_TO_MODEL,
+} from './types';
+
+function usePrevious(value: PreviousLocationUrlState) {
+ const ref = useRef(value);
+ useEffect(() => {
+ ref.current = value;
+ });
+ return ref.current;
+}
+
+export const useUrlStateHooks = ({
+ location,
+ indexPattern,
+ history,
+ setAbsoluteTimerange,
+ setHostsKql,
+ setNetworkKql,
+ setRelativeTimerange,
+ toggleTimelineLinkTo,
+ urlState,
+}: UrlStateContainerPropTypes) => {
+ const [isInitializing, setIsInitializing] = useState(true);
+ const prevProps = usePrevious({ location, urlState });
+
+ const replaceStateInLocation = throttle(
+ 1000,
+ (urlStateToReplace: UrlInputsModel | KqlQuery, urlStateKey: string) => {
+ const newLocation = replaceQueryStringInLocation(
+ location,
+ replaceStateKeyInQueryString(urlStateKey, urlStateToReplace)(
+ getQueryStringFromLocation(location)
+ )
+ );
+ if (newLocation !== location) {
+ history.replace(newLocation);
+ }
+ }
+ );
+
+ const handleInitialize = (initLocation: Location) => {
+ URL_STATE_KEYS.forEach((urlKey: KeyUrlState) => {
+ const newUrlStateString = getParamFromQueryString(
+ getQueryStringFromLocation(location),
+ urlKey
+ );
+ if (newUrlStateString) {
+ setInitialStateFromUrl(urlKey, newUrlStateString, location);
+ } else {
+ if (urlKey === CONSTANTS.timerange) {
+ replaceStateInLocation(urlState[urlKey], urlKey);
+ }
+ if (urlKey === CONSTANTS.kqlQuery) {
+ const currentLocation: LocationTypes = getCurrentLocation(location.pathname);
+ if (currentLocation !== null) {
+ replaceStateInLocation(urlState[CONSTANTS.kqlQuery][currentLocation], urlKey);
+ }
+ }
+ }
+ });
+ };
+
+ const setInitialStateFromUrl = (
+ urlKey: KeyUrlState,
+ newUrlStateString: string,
+ newLocation: Location
+ ) => {
+ if (urlKey === CONSTANTS.timerange) {
+ const timerangeStateData: UrlInputsModel = decodeRisonUrlState(newUrlStateString);
+ const globalId: InputsModelId = 'global';
+ const globalLinkTo: LinkTo = { linkTo: get('global.linkTo', timerangeStateData) };
+ const globalType: TimeRangeKinds = get('global.timerange.kind', timerangeStateData);
+ if (globalType) {
+ if (globalLinkTo.linkTo.length === 0) {
+ toggleTimelineLinkTo({ linkToId: 'global' });
+ }
+ if (globalType === 'absolute') {
+ const absoluteRange = normalizeTimeRange(
+ get('global.timerange', timerangeStateData)
+ );
+ setAbsoluteTimerange({
+ ...absoluteRange,
+ id: globalId,
+ });
+ }
+ if (globalType === 'relative') {
+ const relativeRange = normalizeTimeRange(
+ get('global.timerange', timerangeStateData)
+ );
+ setRelativeTimerange({
+ ...relativeRange,
+ id: globalId,
+ });
+ }
+ }
+ const timelineId: InputsModelId = 'timeline';
+ const timelineLinkTo: LinkTo = { linkTo: get('timeline.linkTo', timerangeStateData) };
+ const timelineType: TimeRangeKinds = get('timeline.timerange.kind', timerangeStateData);
+ if (timelineType) {
+ if (timelineLinkTo.linkTo.length === 0) {
+ toggleTimelineLinkTo({ linkToId: 'timeline' });
+ }
+ if (timelineType === 'absolute') {
+ const absoluteRange = normalizeTimeRange(
+ get('timeline.timerange', timerangeStateData)
+ );
+ setAbsoluteTimerange({
+ ...absoluteRange,
+ id: timelineId,
+ });
+ }
+ if (timelineType === 'relative') {
+ const relativeRange = normalizeTimeRange(
+ get('timeline.timerange', timerangeStateData)
+ );
+ setRelativeTimerange({
+ ...relativeRange,
+ id: timelineId,
+ });
+ }
+ }
+ }
+ if (urlKey === CONSTANTS.kqlQuery) {
+ const kqlQueryStateData: KqlQuery = decodeRisonUrlState(newUrlStateString);
+ if (isKqlForRoute(location.pathname, kqlQueryStateData)) {
+ const filterQuery = {
+ kuery: kqlQueryStateData.filterQuery,
+ serializedQuery: convertKueryToElasticSearchQuery(
+ kqlQueryStateData.filterQuery ? kqlQueryStateData.filterQuery.expression : '',
+ indexPattern
+ ),
+ };
+ if (
+ kqlQueryStateData.queryLocation === CONSTANTS.hostsPage ||
+ kqlQueryStateData.queryLocation === CONSTANTS.hostsDetails
+ ) {
+ const hostsType = LOCATION_MAPPED_TO_MODEL[kqlQueryStateData.queryLocation];
+ setHostsKql({
+ filterQuery,
+ hostsType,
+ });
+ }
+ if (
+ kqlQueryStateData.queryLocation === CONSTANTS.networkPage ||
+ kqlQueryStateData.queryLocation === CONSTANTS.networkDetails
+ ) {
+ const networkType = LOCATION_MAPPED_TO_MODEL[kqlQueryStateData.queryLocation];
+ setNetworkKql({
+ filterQuery,
+ networkType,
+ });
+ }
+ }
+ }
+ };
+
+ useEffect(() => {
+ if (isInitializing) {
+ setIsInitializing(false);
+ handleInitialize(initializeLocation(location));
+ } else if (!isEqual(urlState, prevProps.urlState)) {
+ URL_STATE_KEYS.forEach((urlKey: KeyUrlState) => {
+ if (urlState[urlKey] && !isEqual(urlState[urlKey], prevProps.urlState[urlKey])) {
+ if (urlKey === CONSTANTS.kqlQuery) {
+ LOCATION_KEYS.forEach((queryLocation: LocationKeysType) => {
+ if (
+ !!urlState[CONSTANTS.kqlQuery][queryLocation] &&
+ !isEqual(
+ urlState[CONSTANTS.kqlQuery][queryLocation],
+ prevProps.urlState[CONSTANTS.kqlQuery][queryLocation]
+ )
+ ) {
+ replaceStateInLocation(
+ urlState[CONSTANTS.kqlQuery][queryLocation],
+ CONSTANTS.kqlQuery
+ );
+ }
+ });
+ } else {
+ replaceStateInLocation(urlState[urlKey], urlKey);
+ }
+ }
+ });
+ } else if (location.pathname !== prevProps.location.pathname) {
+ handleInitialize(location);
+ }
+ });
+
+ return { isInitializing };
+};
+
+/*
+ * Why are we doing that, it is because angular-ui router is encoding the `+` back to `2%B` after
+ * that react router is getting the data with the `+` and convert to `2%B`
+ * so we need to get back the value from the window location at initialization to avoid
+ * to bring back the `+` in the kql
+ */
+export const initializeLocation = (location: Location): Location => {
+ const substringIndex =
+ window.location.href.indexOf(`#${location.pathname}`) >= 0
+ ? window.location.href.indexOf(`#${location.pathname}`) + location.pathname.length + 1
+ : -1;
+ if (substringIndex >= 0) {
+ location.search = window.location.href.substring(substringIndex);
+ }
+ return location;
+};
diff --git a/x-pack/legacy/plugins/siem/public/containers/authentications/index.tsx b/x-pack/legacy/plugins/siem/public/containers/authentications/index.tsx
index e5587569f9f17..9545913af966c 100644
--- a/x-pack/legacy/plugins/siem/public/containers/authentications/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/authentications/index.tsx
@@ -49,6 +49,7 @@ class AuthenticationsComponentQuery extends QueryTemplate<
id = 'authenticationQuery',
children,
filterQuery,
+ skip,
sourceId,
startDate,
endDate,
@@ -59,6 +60,7 @@ class AuthenticationsComponentQuery extends QueryTemplate<
query={authenticationsQuery}
fetchPolicy={getDefaultFetchPolicy()}
notifyOnNetworkStatusChange
+ skip={skip}
variables={{
sourceId,
timerange: {
diff --git a/x-pack/legacy/plugins/siem/public/containers/domains/index.tsx b/x-pack/legacy/plugins/siem/public/containers/domains/index.tsx
index 7d7e522df5f64..3acc7bd9f1354 100644
--- a/x-pack/legacy/plugins/siem/public/containers/domains/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/domains/index.tsx
@@ -62,6 +62,7 @@ class DomainsComponentQuery extends QueryTemplate<
domainsSortField,
filterQuery,
ip,
+ skip,
sourceId,
startDate,
endDate,
@@ -74,6 +75,7 @@ class DomainsComponentQuery extends QueryTemplate<
query={domainsQuery}
fetchPolicy="cache-and-network"
notifyOnNetworkStatusChange
+ skip={skip}
variables={{
sourceId,
timerange: {
diff --git a/x-pack/legacy/plugins/siem/public/containers/events/index.tsx b/x-pack/legacy/plugins/siem/public/containers/events/index.tsx
index 83d7498422873..9b2373fc6bcd7 100644
--- a/x-pack/legacy/plugins/siem/public/containers/events/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/events/index.tsx
@@ -50,6 +50,7 @@ class EventsComponentQuery extends QueryTemplate<
filterQuery,
id = 'eventsQuery',
limit,
+ skip,
sourceId,
startDate,
endDate,
@@ -59,6 +60,7 @@ class EventsComponentQuery extends QueryTemplate<
query={eventsQuery}
fetchPolicy={getDefaultFetchPolicy()}
notifyOnNetworkStatusChange
+ skip={skip}
variables={{
filterQuery: createFilter(filterQuery),
sourceId,
diff --git a/x-pack/legacy/plugins/siem/public/containers/hosts/index.tsx b/x-pack/legacy/plugins/siem/public/containers/hosts/index.tsx
index 48ae965e404f1..ce38eeb15a375 100644
--- a/x-pack/legacy/plugins/siem/public/containers/hosts/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/hosts/index.tsx
@@ -78,6 +78,7 @@ class HostsComponentQuery extends QueryTemplate<
endDate,
limit,
startDate,
+ skip,
sourceId,
sortField,
} = this.props;
@@ -105,6 +106,7 @@ class HostsComponentQuery extends QueryTemplate<
query={HostsTableQuery}
fetchPolicy="cache-first"
notifyOnNetworkStatusChange
+ skip={skip}
variables={variables}
>
{({ data, loading, fetchMore, refetch }) => {
diff --git a/x-pack/legacy/plugins/siem/public/containers/hosts/overview/index.tsx b/x-pack/legacy/plugins/siem/public/containers/hosts/overview/index.tsx
index b78ea70088002..04834075d81c8 100644
--- a/x-pack/legacy/plugins/siem/public/containers/hosts/overview/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/hosts/overview/index.tsx
@@ -42,6 +42,7 @@ export class HostOverviewByNameQuery extends QueryTemplate<
id = 'hostOverviewQuery',
children,
hostName,
+ skip,
sourceId,
startDate,
endDate,
@@ -51,6 +52,7 @@ export class HostOverviewByNameQuery extends QueryTemplate<
query={HostOverviewQuery}
fetchPolicy={getDefaultFetchPolicy()}
notifyOnNetworkStatusChange
+ skip={skip}
variables={{
sourceId,
hostName,
diff --git a/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.tsx b/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.tsx
index fe500482fac54..3f6d2df7d709e 100644
--- a/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/ip_overview/index.tsx
@@ -31,11 +31,12 @@ export interface IpOverviewProps extends QueryTemplateProps {
}
export const IpOverviewQuery = pure(
- ({ id = 'ipOverviewQuery', children, filterQuery, sourceId, ip }) => (
+ ({ id = 'ipOverviewQuery', children, filterQuery, skip, sourceId, ip }) => (
query={ipOverviewQuery}
fetchPolicy="cache-and-network"
notifyOnNetworkStatusChange
+ skip={skip}
variables={{
sourceId,
filterQuery: createFilter(filterQuery),
diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx
index afb5e90b93b76..a8d880ede7bcc 100644
--- a/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/kpi_hosts/index.tsx
@@ -29,11 +29,12 @@ export interface KpiHostsProps extends QueryTemplateProps {
}
export const KpiHostsQuery = React.memo(
- ({ id = 'kpiHostsQuery', children, filterQuery, sourceId, startDate, endDate }) => (
+ ({ id = 'kpiHostsQuery', children, filterQuery, skip, sourceId, startDate, endDate }) => (
query={kpiHostsQuery}
fetchPolicy="cache-and-network"
notifyOnNetworkStatusChange
+ skip={skip}
variables={{
sourceId,
timerange: {
diff --git a/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx
index 8e3175d1ddc66..277ce24dcc270 100644
--- a/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/kpi_network/index.tsx
@@ -29,11 +29,12 @@ export interface KpiNetworkProps extends QueryTemplateProps {
}
export const KpiNetworkQuery = React.memo(
- ({ id = 'kpiNetworkQuery', children, filterQuery, sourceId, startDate, endDate }) => (
+ ({ id = 'kpiNetworkQuery', children, filterQuery, skip, sourceId, startDate, endDate }) => (
query={kpiNetworkQuery}
fetchPolicy="cache-and-network"
notifyOnNetworkStatusChange
+ skip={skip}
variables={{
sourceId,
timerange: {
diff --git a/x-pack/legacy/plugins/siem/public/containers/network_dns/index.tsx b/x-pack/legacy/plugins/siem/public/containers/network_dns/index.tsx
index ce5e34dfcd871..f4e6c3550f1fd 100644
--- a/x-pack/legacy/plugins/siem/public/containers/network_dns/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/network_dns/index.tsx
@@ -58,6 +58,7 @@ class NetworkDnsComponentQuery extends QueryTemplate<
dnsSortField,
filterQuery,
isPtrIncluded,
+ skip,
sourceId,
startDate,
endDate,
@@ -68,6 +69,7 @@ class NetworkDnsComponentQuery extends QueryTemplate<
query={networkDnsQuery}
fetchPolicy="cache-and-network"
notifyOnNetworkStatusChange
+ skip={skip}
variables={{
sourceId,
timerange: {
diff --git a/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.tsx b/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.tsx
index 1975cc64b91f6..8c32d21c86c11 100644
--- a/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.tsx
@@ -59,6 +59,7 @@ class NetworkTopNFlowComponentQuery extends QueryTemplate<
id = 'networkTopNFlowQuery',
children,
filterQuery,
+ skip,
sourceId,
startDate,
endDate,
@@ -72,6 +73,7 @@ class NetworkTopNFlowComponentQuery extends QueryTemplate<
query={networkTopNFlowQuery}
fetchPolicy="cache-and-network"
notifyOnNetworkStatusChange
+ skip={skip}
variables={{
sourceId,
timerange: {
diff --git a/x-pack/legacy/plugins/siem/public/containers/query_template.tsx b/x-pack/legacy/plugins/siem/public/containers/query_template.tsx
index 3f55b26529fb3..57af9114b8ac7 100644
--- a/x-pack/legacy/plugins/siem/public/containers/query_template.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/query_template.tsx
@@ -12,10 +12,11 @@ import { ESQuery } from '../../common/typed_json';
export interface QueryTemplateProps {
id?: string;
- sourceId: string;
- startDate?: number;
endDate?: number;
filterQuery?: ESQuery | string;
+ skip?: boolean;
+ sourceId: string;
+ startDate?: number;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type FetchMoreOptionsArgs = FetchMoreQueryOptions &
diff --git a/x-pack/legacy/plugins/siem/public/containers/tls/index.tsx b/x-pack/legacy/plugins/siem/public/containers/tls/index.tsx
index a09d8d7b5809b..8aa710ed5b353 100644
--- a/x-pack/legacy/plugins/siem/public/containers/tls/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/tls/index.tsx
@@ -50,6 +50,7 @@ class TlsComponentQuery extends QueryTemplate {
const myHook = props.hook ? props.hook() : null;
- return {myHook}
;
+ return {JSON.stringify(myHook)}
;
};
diff --git a/x-pack/legacy/plugins/siem/public/mock/index.ts b/x-pack/legacy/plugins/siem/public/mock/index.ts
index fe5ded2a26fca..620e266618c5c 100644
--- a/x-pack/legacy/plugins/siem/public/mock/index.ts
+++ b/x-pack/legacy/plugins/siem/public/mock/index.ts
@@ -6,9 +6,11 @@
export * from './global_state';
export * from './header';
+export * from './hook_wrapper';
export * from './index_pattern';
export * from './kibana_config';
export * from './mock_timeline_data';
export * from './mock_detail_item';
export * from './netflow';
export * from './test_providers';
+export * from './utils';
diff --git a/x-pack/legacy/plugins/siem/public/mock/utils.ts b/x-pack/legacy/plugins/siem/public/mock/utils.ts
new file mode 100644
index 0000000000000..6a372f163a648
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/mock/utils.ts
@@ -0,0 +1,12 @@
+/*
+ * 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.
+ */
+
+interface Global extends NodeJS.Global {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ window?: any;
+}
+
+export const globalNode: Global = global;
diff --git a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx
index 8e55b2c2ed7c1..4be974622b36f 100644
--- a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx
@@ -26,7 +26,6 @@ import { NetworkContainer } from '../network';
import { Overview } from '../overview';
import { Timelines } from '../timelines';
import { WithSource } from '../../containers/source';
-import { UrlStateContainer } from '../../components/url_state';
const WrappedByAutoSizer = styled.div`
height: 100%;
@@ -99,7 +98,6 @@ export const HomePage = pure(() => (
-
diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/host_details.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/host_details.tsx
index cb8e6df95d07d..937aeda5d35b1 100644
--- a/x-pack/legacy/plugins/siem/public/pages/hosts/host_details.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/hosts/host_details.tsx
@@ -22,6 +22,7 @@ import { EventsTable, UncommonProcessTable } from '../../components/page/hosts';
import { AuthenticationTable } from '../../components/page/hosts/authentications_table';
import { HostOverview } from '../../components/page/hosts/host_overview';
import { manageQuery } from '../../components/page/manage_query';
+import { UseUrlState } from '../../components/url_state';
import { AuthenticationsQuery } from '../../containers/authentications';
import { EventsQuery } from '../../containers/events';
import { GlobalTime } from '../../containers/global_time';
@@ -73,116 +74,124 @@ const HostDetailsComponent = pure(
{({ to, from, setQuery }) => (
- <>
-
- {({ hostOverview, loading, id, refetch }) => (
-
- )}
-
-
-
-
-
- {({
- authentications,
- totalCount,
- loading,
- pageInfo,
- loadMore,
- id,
- refetch,
- }) => (
-
+ {({ isInitializing }) => (
+ <>
+
+ {({ hostOverview, loading, id, refetch }) => (
+
+ )}
+
+
+
+
+
- )}
-
-
-
-
-
- {({
- uncommonProcesses,
- totalCount,
- loading,
- pageInfo,
- loadMore,
- id,
- refetch,
- }) => (
-
+ {({
+ authentications,
+ totalCount,
+ loading,
+ pageInfo,
+ loadMore,
+ id,
+ refetch,
+ }) => (
+
+ )}
+
+
+
+
+
- )}
-
-
-
-
-
- {({ events, loading, id, refetch, totalCount, pageInfo, loadMore }) => (
-
+ {({
+ uncommonProcesses,
+ totalCount,
+ loading,
+ pageInfo,
+ loadMore,
+ id,
+ refetch,
+ }) => (
+
+ )}
+
+
+
+
+
- )}
-
- >
+ >
+ {({ events, loading, id, refetch, totalCount, pageInfo, loadMore }) => (
+
+ )}
+
+ >
+ )}
+
)}
diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx
index fdd68e5f65fd0..76b937983dd11 100644
--- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx
@@ -22,6 +22,7 @@ import {
} from '../../components/page/hosts';
import { AuthenticationTable } from '../../components/page/hosts/authentications_table';
import { manageQuery } from '../../components/page/manage_query';
+import { UseUrlState } from '../../components/url_state';
import { AuthenticationsQuery } from '../../containers/authentications';
import { EventsQuery } from '../../containers/events';
import { GlobalTime } from '../../containers/global_time';
@@ -63,141 +64,157 @@ const HostsComponent = pure(({ filterQuery }) => (
{({ to, from, setQuery }) => (
- <>
-
- {({ kpiHosts, loading, id, refetch }) => (
-
- )}
-
-
-
-
-
- {({ hosts, totalCount, loading, pageInfo, loadMore, id, refetch }) => (
-
+ {({ isInitializing }) => (
+ <>
+
+ {({ kpiHosts, loading, id, refetch }) => (
+
+ )}
+
+
+
+
+
- )}
-
-
-
-
-
- {({ authentications, totalCount, loading, pageInfo, loadMore, id, refetch }) => (
-
+ {({ hosts, totalCount, loading, pageInfo, loadMore, id, refetch }) => (
+
+ )}
+
+
+
+
+
- )}
-
-
-
-
-
- {({
- uncommonProcesses,
- totalCount,
- loading,
- pageInfo,
- loadMore,
- id,
- refetch,
- }) => (
-
+ {({
+ authentications,
+ totalCount,
+ loading,
+ pageInfo,
+ loadMore,
+ id,
+ refetch,
+ }) => (
+
+ )}
+
+
+
+
+
- )}
-
-
-
-
-
- {({ events, loading, id, refetch, totalCount, pageInfo, loadMore }) => (
-
+ {({
+ uncommonProcesses,
+ totalCount,
+ loading,
+ pageInfo,
+ loadMore,
+ id,
+ refetch,
+ }) => (
+
+ )}
+
+
+
+
+
- )}
-
- >
+ >
+ {({ events, loading, id, refetch, totalCount, pageInfo, loadMore }) => (
+
+ )}
+
+ >
+ )}
+
)}
) : (
<>
-
>
)
diff --git a/x-pack/legacy/plugins/siem/public/pages/network/ip_details.tsx b/x-pack/legacy/plugins/siem/public/pages/network/ip_details.tsx
index 398cf9fb99f75..aefbee980eabb 100644
--- a/x-pack/legacy/plugins/siem/public/pages/network/ip_details.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/network/ip_details.tsx
@@ -20,21 +20,22 @@ import { manageQuery } from '../../components/page/manage_query';
import { DomainsTable } from '../../components/page/network/domains_table';
import { FlowTargetSelectConnected } from '../../components/page/network/flow_target_select_connected';
import { IpOverview } from '../../components/page/network/ip_overview';
+import { UsersTable } from '../../components/page/network/users_table';
+import { TlsTable } from '../../components/page/network/tls_table';
+import { UseUrlState } from '../../components/url_state';
import { DomainsQuery } from '../../containers/domains';
import { GlobalTime } from '../../containers/global_time';
import { IpOverviewQuery } from '../../containers/ip_overview';
import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source';
+import { TlsQuery } from '../../containers/tls';
+import { UsersQuery } from '../../containers/users';
import { FlowTarget, LastEventIndexKey } from '../../graphql/types';
import { decodeIpv6 } from '../../lib/helpers';
import { networkModel, networkSelectors, State } from '../../store';
-import { TlsTable } from '../../components/page/network/tls_table';
import { NetworkKql } from './kql';
import { NetworkEmptyPage } from './network_empty_page';
import * as i18n from './translations';
-import { TlsQuery } from '../../containers/tls';
-import { UsersTable } from '../../components/page/network/users_table';
-import { UsersQuery } from '../../containers/users';
const DomainsTableManage = manageQuery(DomainsTable);
const TlsTableManage = manageQuery(TlsTable);
@@ -75,109 +76,117 @@ export const IPDetailsComponent = pure(
{({ to, from, setQuery }) => (
- <>
-
- {({ ipOverviewData, loading }) => (
-
+ {({ isInitializing }) => (
+ <>
+
+ {({ ipOverviewData, loading }) => (
+
+ )}
+
+
+
+
+
- )}
-
-
-
-
-
- {({ id, domains, totalCount, pageInfo, loading, loadMore, refetch }) => (
-
- )}
-
-
-
-
-
- {({ id, users, totalCount, pageInfo, loading, loadMore, refetch }) => (
-
+ {({ id, domains, totalCount, pageInfo, loading, loadMore, refetch }) => (
+
+ )}
+
+
+
+
+
- )}
-
-
-
-
-
- {({ id, tls, totalCount, pageInfo, loading, loadMore, refetch }) => (
-
+ {({ id, users, totalCount, pageInfo, loading, loadMore, refetch }) => (
+
+ )}
+
+
+
+
+
- )}
-
- >
+ >
+ {({ id, tls, totalCount, pageInfo, loading, loadMore, refetch }) => (
+
+ )}
+
+ >
+ )}
+
)}
diff --git a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx
index 6f6e889215045..71bf3548e8759 100644
--- a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx
@@ -17,6 +17,7 @@ import { LastEventTime } from '../../components/last_event_time';
import { manageQuery } from '../../components/page/manage_query';
import { KpiNetworkComponent, NetworkTopNFlowTable } from '../../components/page/network';
import { NetworkDnsTable } from '../../components/page/network/network_dns_table';
+import { UseUrlState } from '../../components/url_state';
import { GlobalTime } from '../../containers/global_time';
import { KpiNetworkQuery } from '../../containers/kpi_network';
import { NetworkDnsQuery } from '../../containers/network_dns';
@@ -53,75 +54,90 @@ const NetworkComponent = pure(({ filterQuery }) => (
{({ to, from, setQuery }) => (
- <>
-
- {({ kpiNetwork, loading, id, refetch }) => (
-
- )}
-
+
+ {({ isInitializing }) => (
+ <>
+
+ {({ kpiNetwork, loading, id, refetch }) => (
+
+ )}
+
-
+
-
- {({ totalCount, loading, networkTopNFlow, pageInfo, loadMore, id, refetch }) => (
-
- )}
-
+ >
+ {({
+ totalCount,
+ loading,
+ networkTopNFlow,
+ pageInfo,
+ loadMore,
+ id,
+ refetch,
+ }) => (
+
+ )}
+
-
+
-
- {({ totalCount, loading, networkDns, pageInfo, loadMore, id, refetch }) => (
-
- )}
-
- >
+ >
+ {({ totalCount, loading, networkDns, pageInfo, loadMore, id, refetch }) => (
+
+ )}
+
+ >
+ )}
+
)}