diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/domains_table/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/page/network/domains_table/__snapshots__/index.test.tsx.snap
deleted file mode 100644
index 2d8836c63e2be36..000000000000000
--- a/x-pack/legacy/plugins/siem/public/components/page/network/domains_table/__snapshots__/index.test.tsx.snap
+++ /dev/null
@@ -1,168 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Domains Table Component Rendering it renders the default Domains table 1`] = `
-
-`;
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
deleted file mode 100644
index b63895f333db42d..000000000000000
--- a/x-pack/legacy/plugins/siem/public/components/page/network/domains_table/columns.tsx
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { EuiIcon, EuiToolTip } from '@elastic/eui';
-import numeral from '@elastic/numeral';
-import { getOr, isEmpty } from 'lodash/fp';
-import moment from 'moment';
-import React from 'react';
-import { StaticIndexPattern } from 'ui/index_patterns';
-
-import {
- DomainsEdges,
- DomainsItem,
- DomainsNetworkField,
- FlowDirection,
- FlowTarget,
-} from '../../../../graphql/types';
-import { assertUnreachable } from '../../../../lib/helpers';
-import { escapeQueryValue } from '../../../../lib/keury';
-import { networkModel } from '../../../../store';
-import { DragEffects, DraggableWrapper } from '../../../drag_and_drop/draggable_wrapper';
-import { escapeDataProviderId } from '../../../drag_and_drop/helpers';
-import { defaultToEmptyTag, getEmptyTagValue } from '../../../empty_value';
-import { PreferenceFormattedDate } from '../../../formatted_date';
-import { Columns } from '../../../paginated_table';
-import { LocalizedDateTooltip } from '../../../localized_date_tooltip';
-import { IS_OPERATOR } from '../../../timeline/data_providers/data_provider';
-import { PreferenceFormattedBytes } from '../../../formatted_bytes';
-import { Provider } from '../../../timeline/data_providers/provider';
-import { AddToKql } from '../../add_to_kql';
-
-import * as i18n from './translations';
-
-export type DomainsColumns = [
- Columns,
- Columns,
- Columns,
- Columns,
- Columns,
- Columns
-];
-
-export const getDomainsColumns = (
- indexPattern: StaticIndexPattern,
- ip: string,
- flowDirection: FlowDirection,
- flowTarget: FlowTarget,
- type: networkModel.NetworkType,
- tableId: string
-): DomainsColumns => [
- {
- field: `node.${flowTarget}.domainName`,
- name: i18n.DOMAIN_NAME,
- truncateText: false,
- hideForMobile: false,
- sortable: true,
- render: domainName => {
- const domainNameAttr = `${flowTarget}.domain`;
- if (domainName != null) {
- const id = escapeDataProviderId(
- `${tableId}-table-${flowTarget}-${flowDirection}-domain-${domainName}`
- );
- return (
-
- snapshot.isDragging ? (
-
-
-
- ) : (
- <>{domainName}>
- )
- }
- />
- );
- } else {
- return getEmptyTagValue();
- }
- },
- },
- {
- field: 'node.network.direction',
- name: i18n.DIRECTION,
- truncateText: false,
- hideForMobile: false,
- render: directions =>
- isEmpty(directions)
- ? getEmptyTagValue()
- : directions &&
- directions.map((direction, index) => (
-
- <>
- {defaultToEmptyTag(direction)}
- {index < directions.length - 1 ? '\u00A0' : null}
- >
-
- )),
- },
- {
- field: 'node.network.bytes',
- name: i18n.BYTES,
- truncateText: false,
- hideForMobile: false,
- sortable: true,
- render: bytes => {
- if (bytes != null) {
- return ;
- } else {
- return getEmptyTagValue();
- }
- },
- },
- {
- field: 'node.network.packets',
- name: i18n.PACKETS,
- truncateText: false,
- hideForMobile: false,
- sortable: true,
- render: packets => {
- if (packets != null) {
- return numeral(packets).format('0,000');
- } else {
- return getEmptyTagValue();
- }
- },
- },
- {
- field: `node.${flowTarget}.uniqueIpCount`,
- name: getFlowTargetTitle(flowTarget),
- truncateText: false,
- hideForMobile: false,
- sortable: true,
- render: uniqueIpCount => {
- if (uniqueIpCount != null) {
- return numeral(uniqueIpCount).format('0,000');
- } else {
- return getEmptyTagValue();
- }
- },
- },
- {
- name: (
-
- <>
- {i18n.LAST_SEEN}{' '}
-
- >
-
- ),
- truncateText: false,
- hideForMobile: false,
- render: ({ node }) => {
- const lastSeenAttr = `${flowTarget}.lastSeen`;
- const lastSeen = getOr(null, lastSeenAttr, node);
- if (lastSeen != null) {
- return (
-
-
-
- );
- }
- return getEmptyTagValue();
- },
- },
-];
-
-const getFlowTargetTitle = (flowTarget: FlowTarget): string => {
- switch (flowTarget) {
- case FlowTarget.client:
- return i18n.UNIQUE_CLIENTS;
- case FlowTarget.server:
- return i18n.UNIQUE_SERVERS;
- case FlowTarget.source:
- return i18n.UNIQUE_DESTINATIONS;
- case FlowTarget.destination:
- return i18n.UNIQUE_SOURCES;
- }
- assertUnreachable(flowTarget);
-};
diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/__snapshots__/index.test.tsx.snap
index a8fde09ff5f4f5f..f80a61836b86ed7 100644
--- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/__snapshots__/index.test.tsx.snap
+++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/__snapshots__/index.test.tsx.snap
@@ -181,6 +181,12 @@ exports[`NetworkTopNFlow Table Component rendering it renders the default Networ
"searchable": true,
"type": "string",
},
+ Object {
+ "aggregatable": true,
+ "name": "host.name",
+ "searchable": true,
+ "type": "string",
+ },
],
"title": "filebeat-*,auditbeat-*,packetbeat-*",
}
diff --git a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx
index eda7d73ccb40dca..f8c29b79bdc170c 100644
--- a/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/search_bar/index.tsx
@@ -5,7 +5,7 @@
*/
import { Filter } from '@kbn/es-query';
-import { getOr, isEqual } from 'lodash/fp';
+import { getOr, isEqual, set } from 'lodash/fp';
import React, { memo, useEffect } from 'react';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
@@ -16,13 +16,14 @@ import { StaticIndexPattern, IndexPattern } from 'ui/index_patterns';
import { TimeRange, Query } from 'src/plugins/data/common/types';
import { SavedQuery } from 'src/legacy/core_plugins/data/public';
+import { OnTimeChangeProps } from '@elastic/eui';
import { start as data } from '../../../../../../../src/legacy/core_plugins/data/public/legacy';
import { inputsActions } from '../../store/inputs';
import { InputsRange } from '../../store/inputs/model';
import { InputsModelId } from '../../store/inputs/constants';
import { State, inputsModel } from '../../store';
-import { dispatchUpdateReduxTime, DispatchUpdateReduxTime, formatDate } from '../super_date_picker';
+import { formatDate } from '../super_date_picker';
import {
endSelector,
filterQuerySelector,
@@ -34,6 +35,7 @@ import {
startSelector,
toStrSelector,
} from './selectors';
+import { timelineActions, hostsActions, networkActions } from '../../store/actions';
const {
ui: { SearchBar },
@@ -57,16 +59,7 @@ interface SiemSearchBarRedux {
}
interface SiemSearchBarDispatch {
- updateReduxTime: DispatchUpdateReduxTime;
- setFilterQuery: ({
- id,
- query,
- language,
- }: {
- id: InputsModelId;
- query: string | { [key: string]: unknown };
- language: string;
- }) => void;
+ updateSearch: DispatchUpdateSearch;
setSavedQuery: ({
id,
savedQuery,
@@ -99,13 +92,12 @@ const SearchBarComponent = memo {
if (fromStr != null && toStr != null) {
timefilter.timefilter.setTime({ from: fromStr, to: toStr });
@@ -117,9 +109,18 @@ const SearchBarComponent = memo {
- let isStateUpdated = false;
const isQuickSelection =
payload.dateRange.from.includes('now') || payload.dateRange.to.includes('now');
+ let updateSearchBar: UpdateReduxSearchBar = {
+ id,
+ end: toStr != null ? toStr : new Date(end).toISOString(),
+ start: fromStr != null ? fromStr : new Date(start).toISOString(),
+ isInvalid: false,
+ isQuickSelection,
+ updateTime: false,
+ };
+ let isStateUpdated = false;
+
if (
(isQuickSelection &&
(fromStr !== payload.dateRange.from || toStr !== payload.dateRange.to)) ||
@@ -128,53 +129,39 @@ const SearchBarComponent = memo q.refetch && (q.refetch as inputsModel.Refetch)());
}
}
+
+ updateSearch(updateSearchBar);
};
const onRefresh = (payload: { dateRange: TimeRange }) => {
if (payload.dateRange.from.includes('now') || payload.dateRange.to.includes('now')) {
- updateReduxTime({
- end: payload.dateRange.to,
+ updateSearch({
id,
+ end: payload.dateRange.to,
+ start: payload.dateRange.from,
isInvalid: false,
isQuickSelection: true,
- kql: undefined,
- start: payload.dateRange.from,
- timelineId,
+ updateTime: true,
});
} else {
queries.forEach(q => q.refetch && (q.refetch as inputsModel.Refetch)());
@@ -186,45 +173,54 @@ const SearchBarComponent = memo {
- siemFilterManager.setFilters(savedQueryUpdated.attributes.filters || []);
-
const isQuickSelection = savedQueryUpdated.attributes.timefilter
? savedQueryUpdated.attributes.timefilter.from.includes('now') ||
savedQueryUpdated.attributes.timefilter.to.includes('now')
: false;
+ let updateSearchBar: UpdateReduxSearchBar = {
+ id,
+ filters: savedQueryUpdated.attributes.filters || [],
+ end: toStr != null ? toStr : new Date(end).toISOString(),
+ start: fromStr != null ? fromStr : new Date(start).toISOString(),
+ isInvalid: false,
+ isQuickSelection,
+ updateTime: false,
+ };
+
if (savedQueryUpdated.attributes.timefilter) {
- updateReduxTime({
- end: savedQueryUpdated.attributes.timefilter
- ? savedQueryUpdated.attributes.timefilter.to
- : toStr,
- id,
- isInvalid: false,
- isQuickSelection,
- kql: undefined,
- start: savedQueryUpdated.attributes.timefilter
- ? savedQueryUpdated.attributes.timefilter.from
- : fromStr,
- timelineId,
- });
+ updateSearchBar.end = savedQueryUpdated.attributes.timefilter
+ ? savedQueryUpdated.attributes.timefilter.to
+ : updateSearchBar.end;
+ updateSearchBar.start = savedQueryUpdated.attributes.timefilter
+ ? savedQueryUpdated.attributes.timefilter.from
+ : updateSearchBar.start;
+ updateSearchBar.updateTime = true;
}
- setFilterQuery({
- id,
- ...savedQueryUpdated.attributes.query,
- });
- setSavedQuery({ id, savedQuery: savedQueryUpdated });
+ updateSearchBar = set('query', savedQueryUpdated.attributes.query, updateSearchBar);
+ updateSearchBar = set('savedQuery', savedQueryUpdated, updateSearchBar);
+
+ updateSearch(updateSearchBar);
};
const onClearSavedQuery = () => {
if (savedQuery != null) {
- setFilterQuery({
+ updateSearch({
id,
- query: '',
- language: savedQuery.attributes.query.language,
+ filters: [],
+ end: toStr != null ? toStr : new Date(end).toISOString(),
+ start: fromStr != null ? fromStr : new Date(start).toISOString(),
+ isInvalid: false,
+ isQuickSelection: false,
+ updateTime: false,
+ query: {
+ query: '',
+ language: savedQuery.attributes.query.language,
+ },
+ resetSavedQuery: true,
+ savedQuery: undefined,
});
- setSavedQuery({ id, savedQuery: undefined });
- siemFilterManager.setFilters([]);
}
};
@@ -303,17 +299,90 @@ const makeMapStateToProps = () => {
SearchBarComponent.displayName = 'SiemSearchBarComponent';
+interface UpdateReduxSearchBar extends OnTimeChangeProps {
+ id: InputsModelId;
+ filters?: Filter[];
+ query?: Query;
+ savedQuery?: SavedQuery;
+ resetSavedQuery?: boolean;
+ timelineId?: string;
+ updateTime: boolean;
+}
+
+type DispatchUpdateSearch = ({
+ end,
+ id,
+ isQuickSelection,
+ start,
+ timelineId,
+}: UpdateReduxSearchBar) => void;
+
+export const dispatchUpdateSearch = (dispatch: Dispatch) => ({
+ end,
+ filters,
+ id,
+ isQuickSelection,
+ query,
+ resetSavedQuery,
+ savedQuery,
+ start,
+ timelineId,
+ updateTime = false,
+}: UpdateReduxSearchBar): void => {
+ if (updateTime) {
+ const fromDate = formatDate(start);
+ let toDate = formatDate(end, { roundUp: true });
+ if (isQuickSelection) {
+ dispatch(
+ inputsActions.setRelativeRangeDatePicker({
+ id,
+ fromStr: start,
+ toStr: end,
+ from: fromDate,
+ to: toDate,
+ })
+ );
+ } else {
+ toDate = formatDate(end);
+ dispatch(
+ inputsActions.setAbsoluteRangeDatePicker({
+ id,
+ from: formatDate(start),
+ to: formatDate(end),
+ })
+ );
+ }
+ if (timelineId != null) {
+ dispatch(
+ timelineActions.updateRange({
+ id: timelineId,
+ start: fromDate,
+ end: toDate,
+ })
+ );
+ }
+ }
+ if (query != null) {
+ dispatch(
+ inputsActions.setFilterQuery({
+ id,
+ ...query,
+ })
+ );
+ }
+ if (filters != null) {
+ siemFilterManager.setFilters(filters);
+ }
+ if (savedQuery != null || resetSavedQuery) {
+ dispatch(inputsActions.setSavedQuery({ id, savedQuery }));
+ }
+
+ dispatch(hostsActions.setHostTablesActivePageToZero());
+ dispatch(networkActions.setNetworkTablesActivePageToZero());
+};
+
const mapDispatchToProps = (dispatch: Dispatch) => ({
- updateReduxTime: dispatchUpdateReduxTime(dispatch),
- setFilterQuery: ({
- id,
- query,
- language,
- }: {
- id: InputsModelId;
- query: string | { [key: string]: unknown };
- language: string;
- }) => dispatch(inputsActions.setFilterQuery({ id, query, language })),
+ updateSearch: dispatchUpdateSearch(dispatch),
setSavedQuery: ({ id, savedQuery }: { id: InputsModelId; savedQuery: SavedQuery | undefined }) =>
dispatch(inputsActions.setSavedQuery({ id, savedQuery })),
setSearchBarFilter: ({ id, filters }: { id: InputsModelId; filters: Filter[] }) =>
diff --git a/x-pack/legacy/plugins/siem/public/components/super_date_picker/index.tsx b/x-pack/legacy/plugins/siem/public/components/super_date_picker/index.tsx
index 7dd66e21dad03b7..2d93fde336d3acc 100644
--- a/x-pack/legacy/plugins/siem/public/components/super_date_picker/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/super_date_picker/index.tsx
@@ -18,7 +18,7 @@ import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import { inputsModel, State } from '../../store';
-import { inputsActions, timelineActions, hostsActions, networkActions } from '../../store/actions';
+import { inputsActions, timelineActions } from '../../store/actions';
import { InputsModelId } from '../../store/inputs/constants';
import {
policySelector,
@@ -55,18 +55,13 @@ interface UpdateReduxTime extends OnTimeChangeProps {
timelineId?: string;
}
-interface ReturnUpdateReduxTime {
- kqlHasBeenUpdated: boolean;
-}
-
export type DispatchUpdateReduxTime = ({
end,
id,
isQuickSelection,
- kql,
start,
timelineId,
-}: UpdateReduxTime) => ReturnUpdateReduxTime;
+}: UpdateReduxTime) => void;
interface SuperDatePickerDispatchProps {
setDuration: ({ id, duration }: { id: InputsModelId; duration: number }) => void;
@@ -109,7 +104,7 @@ export const SuperDatePickerComponent = React.memo(
[]
);
const onRefresh = ({ start: newStart, end: newEnd }: OnRefreshProps): void => {
- const { kqlHasBeenUpdated } = updateReduxTime({
+ updateReduxTime({
end: newEnd,
id,
isInvalid: false,
@@ -122,10 +117,7 @@ export const SuperDatePickerComponent = React.memo(
const currentEnd = isQuickSelection
? formatDate(newEnd, { roundUp: true })
: formatDate(newEnd);
- if (
- !kqlHasBeenUpdated &&
- (!isQuickSelection || (start === currentStart && end === currentEnd))
- ) {
+ if (!isQuickSelection || (start === currentStart && end === currentEnd)) {
refetchQuery(queries);
}
};
@@ -215,10 +207,9 @@ export const dispatchUpdateReduxTime = (dispatch: Dispatch) => ({
end,
id,
isQuickSelection,
- kql,
start,
timelineId,
-}: UpdateReduxTime): ReturnUpdateReduxTime => {
+}: UpdateReduxTime): void => {
const fromDate = formatDate(start);
let toDate = formatDate(end, { roundUp: true });
if (isQuickSelection) {
@@ -250,21 +241,6 @@ export const dispatchUpdateReduxTime = (dispatch: Dispatch) => ({
})
);
}
-
- let kqlHasBeenUpdated = false;
- if (kql) {
- // if refetch is successful, it will have a side effect
- // to set all the tables on its activePage to zero (meaning pagination)
- kqlHasBeenUpdated = kql.refetch(dispatch);
- }
- if (!kqlHasBeenUpdated) {
- // Date picker is global to all the page in the app
- // (Hosts/Network are the only one having tables)
- dispatch(hostsActions.setHostTablesActivePageToZero());
- dispatch(networkActions.setNetworkTablesActivePageToZero());
- }
-
- return { kqlHasBeenUpdated };
};
export const makeMapStateToProps = () => {
diff --git a/x-pack/legacy/plugins/siem/public/store/network/reducer.ts b/x-pack/legacy/plugins/siem/public/store/network/reducer.ts
index 9e4ed569cdf687b..74281bc2a4a5aab 100644
--- a/x-pack/legacy/plugins/siem/public/store/network/reducer.ts
+++ b/x-pack/legacy/plugins/siem/public/store/network/reducer.ts
@@ -17,6 +17,7 @@ import {
import { DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from '../constants';
import {
+ setNetworkTablesActivePageToZero,
updateDnsLimit,
updateDnsSort,
updateIpDetailsFlowTarget,
@@ -30,6 +31,10 @@ import {
updateUsersLimit,
updateUsersSort,
} from './actions';
+import {
+ setNetworkDetailsQueriesActivePageToZero,
+ setNetworkPageQueriesActivePageToZero,
+} from './helpers';
import { IpDetailsTableType, NetworkModel, NetworkTableType, NetworkType } from './model';
export type NetworkState = NetworkModel;
@@ -104,6 +109,17 @@ export const initialNetworkState: NetworkState = {
};
export const networkReducer = reducerWithInitialState(initialNetworkState)
+ .case(setNetworkTablesActivePageToZero, state => ({
+ ...state,
+ page: {
+ ...state.page,
+ queries: setNetworkPageQueriesActivePageToZero(state),
+ },
+ details: {
+ ...state.details,
+ queries: setNetworkDetailsQueriesActivePageToZero(state),
+ },
+ }))
.case(updateIpDetailsTableActivePage, (state, { activePage, tableType }) => ({
...state,
[NetworkType.details]: {