From 1e7c3f88ec2e580d4b31465aa2ccfec1da5254ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopyci=C5=84ski?= Date: Tue, 12 Jan 2021 00:09:38 +0100 Subject: [PATCH] =?UTF-8?q?[Security=20Solution]=20Fix=20sorting=20on=20un?= =?UTF-8?q?mapped=20fields=20in=20Timeline=20Events=E2=80=A6=20(#87241)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Security Solution] Fix sorting on unmapped fields in Timeline Events table * set unmapped_type to the column type * add missing types * Update saved_object_mappings.ts Co-authored-by: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> --- .../common/search_strategy/timeline/index.ts | 6 +++++- .../common/types/timeline/index.ts | 1 + .../events_viewer/events_viewer.test.tsx | 1 + .../components/events_viewer/events_viewer.tsx | 3 ++- .../public/common/components/page/index.tsx | 5 +++++ .../public/common/mock/global_state.ts | 2 +- .../public/common/mock/timeline_results.ts | 7 ++++--- .../components/alerts_table/actions.test.tsx | 2 ++ .../components/open_timeline/__mocks__/index.ts | 2 ++ .../components/open_timeline/helpers.test.ts | 17 ++++++++++++++++- .../__snapshots__/index.test.tsx.snap | 2 ++ .../body/column_headers/default_headers.ts | 1 + .../header/__snapshots__/index.test.tsx.snap | 5 +++++ .../body/column_headers/header/index.test.tsx | 13 ++++++++++++- .../body/column_headers/header/index.tsx | 3 +++ .../timeline/body/column_headers/index.test.tsx | 15 ++++++++++++--- .../timeline/body/column_headers/index.tsx | 3 ++- .../components/timeline/body/index.test.tsx | 1 + .../components/timeline/body/sort/index.ts | 1 + .../__snapshots__/index.test.tsx.snap | 1 + .../timeline/pinned_tab_content/index.test.tsx | 1 + .../timeline/pinned_tab_content/index.tsx | 3 ++- .../__snapshots__/index.test.tsx.snap | 1 + .../timeline/query_tab_content/index.test.tsx | 1 + .../timeline/query_tab_content/index.tsx | 3 ++- .../public/timelines/containers/index.tsx | 5 +++-- .../public/timelines/store/timeline/defaults.ts | 1 + .../timelines/store/timeline/epic.test.ts | 3 ++- .../store/timeline/epic_local_storage.test.tsx | 2 ++ .../timelines/store/timeline/reducer.test.ts | 6 +++++- .../lib/timeline/pick_saved_timeline.test.ts | 2 +- .../routes/__mocks__/create_timelines.ts | 2 +- .../routes/__mocks__/import_timelines.ts | 6 +++++- .../routes/__mocks__/request_responses.ts | 6 +++--- .../lib/timeline/saved_object_mappings.ts | 4 ++++ .../factory/events/all/query.events_all.dsl.ts | 11 ++++++++--- 36 files changed, 121 insertions(+), 27 deletions(-) diff --git a/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts b/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts index 6f71ed5c2751..d3ec2763f939 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts @@ -28,10 +28,14 @@ export interface TimelineRequestBasicOptions extends IEsSearchRequest { factoryQueryType?: TimelineFactoryQueryTypes; } +export interface TimelineRequestSortField extends SortField { + type: string; +} + export interface TimelineRequestOptionsPaginated extends TimelineRequestBasicOptions { pagination: Pick; - sort: Array>; + sort: Array>; } export type TimelineStrategyResponseType< diff --git a/x-pack/plugins/security_solution/common/types/timeline/index.ts b/x-pack/plugins/security_solution/common/types/timeline/index.ts index 26d13b13f40c..77d22f712061 100644 --- a/x-pack/plugins/security_solution/common/types/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/types/timeline/index.ts @@ -146,6 +146,7 @@ const SavedFavoriteRuntimeType = runtimeTypes.partial({ const SavedSortObject = runtimeTypes.partial({ columnId: unionWithNullType(runtimeTypes.string), + columnType: unionWithNullType(runtimeTypes.string), sortDirection: unionWithNullType(runtimeTypes.string), }); const SavedSortRuntimeType = runtimeTypes.union([ diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx index 6250345579cf..5e9195a686c8 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx @@ -104,6 +104,7 @@ const eventsViewerDefaultProps = { sort: [ { columnId: 'foo', + columnType: 'number', sortDirection: 'asc' as SortDirection, }, ], diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx index 1d06f07bc774..261db75b03b3 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx @@ -216,8 +216,9 @@ const EventsViewerComponent: React.FC = ({ const sortField = useMemo( () => - sort.map(({ columnId, sortDirection }) => ({ + sort.map(({ columnId, columnType, sortDirection }) => ({ field: columnId, + type: columnType, direction: sortDirection as Direction, })), [sort] diff --git a/x-pack/plugins/security_solution/public/common/components/page/index.tsx b/x-pack/plugins/security_solution/public/common/components/page/index.tsx index 30a7685a193b..0f1968fb3fc2 100644 --- a/x-pack/plugins/security_solution/public/common/components/page/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/page/index.tsx @@ -26,6 +26,11 @@ SecuritySolutionAppWrapper.displayName = 'SecuritySolutionAppWrapper'; and `EuiPopover`, `EuiToolTip` global styles */ export const AppGlobalStyle = createGlobalStyle<{ theme: { eui: { euiColorPrimary: string } } }>` + // fixes double scrollbar on views with EventsTable + #kibana-body { + overflow: hidden; + } + div.app-wrapper { background-color: rgba(0,0,0,0); } diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index 320c3a073654..9570d49fdc66 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -238,7 +238,7 @@ export const mockGlobalState: State = { pinnedEventIds: {}, pinnedEventsSaveObject: {}, itemsPerPageOptions: [5, 10, 20], - sort: [{ columnId: '@timestamp', sortDirection: Direction.desc }], + sort: [{ columnId: '@timestamp', columnType: 'number', sortDirection: Direction.desc }], isSaving: false, version: null, status: TimelineStatus.active, diff --git a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts index 03109803eb9d..3137ef4c2456 100644 --- a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts +++ b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts @@ -2150,6 +2150,7 @@ export const mockTimelineModel: TimelineModel = { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: Direction.desc, }, ], @@ -2184,7 +2185,7 @@ export const mockTimelineResult: TimelineResult = { templateTimelineId: null, templateTimelineVersion: null, savedQueryId: null, - sort: [{ columnId: '@timestamp', sortDirection: 'desc' }], + sort: [{ columnId: '@timestamp', columnType: 'number', sortDirection: 'desc' }], version: '1', }; @@ -2202,7 +2203,7 @@ export const defaultTimelineProps: CreateTimelineProps = { timeline: { activeTab: TimelineTabs.query, columns: [ - { columnHeaderType: 'not-filtered', id: '@timestamp', width: 190 }, + { columnHeaderType: 'not-filtered', id: '@timestamp', type: 'number', width: 190 }, { columnHeaderType: 'not-filtered', id: 'message', width: 180 }, { columnHeaderType: 'not-filtered', id: 'event.category', width: 180 }, { columnHeaderType: 'not-filtered', id: 'event.action', width: 180 }, @@ -2254,7 +2255,7 @@ export const defaultTimelineProps: CreateTimelineProps = { selectedEventIds: {}, show: false, showCheckboxes: false, - sort: [{ columnId: '@timestamp', sortDirection: Direction.desc }], + sort: [{ columnId: '@timestamp', columnType: 'number', sortDirection: Direction.desc }], status: TimelineStatus.draft, title: '', timelineType: TimelineType.default, diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx index 64e916f87b09..bdf358dc8737 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx @@ -111,6 +111,7 @@ describe('alert actions', () => { { columnHeaderType: 'not-filtered', id: '@timestamp', + type: 'number', width: 190, }, { @@ -207,6 +208,7 @@ describe('alert actions', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, ], diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/__mocks__/index.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/__mocks__/index.ts index ce4b0f09e5c9..1f6ba3315705 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/__mocks__/index.ts @@ -151,6 +151,7 @@ export const mockTimeline = { savedQueryId: null, sort: { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', __typename: 'SortTimelineResult', }, @@ -403,6 +404,7 @@ export const mockTemplate = { savedQueryId: null, sort: { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', __typename: 'SortTimelineResult', }, diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts index da6eec968d11..0e90a5ab5287 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts @@ -246,6 +246,7 @@ describe('helpers', () => { { columnHeaderType: 'not-filtered', id: '@timestamp', + type: 'number', width: 190, }, { @@ -319,6 +320,7 @@ describe('helpers', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, ], @@ -347,6 +349,7 @@ describe('helpers', () => { { columnHeaderType: 'not-filtered', id: '@timestamp', + type: 'number', width: 190, }, { @@ -420,6 +423,7 @@ describe('helpers', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, ], @@ -448,6 +452,7 @@ describe('helpers', () => { { columnHeaderType: 'not-filtered', id: '@timestamp', + type: 'number', width: 190, }, { @@ -521,6 +526,7 @@ describe('helpers', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, ], @@ -547,6 +553,7 @@ describe('helpers', () => { { columnHeaderType: 'not-filtered', id: '@timestamp', + type: 'number', width: 190, }, { @@ -620,6 +627,7 @@ describe('helpers', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, ], @@ -652,7 +660,7 @@ describe('helpers', () => { example: undefined, id: '@timestamp', placeholder: undefined, - type: undefined, + type: 'number', width: 190, }, { @@ -760,6 +768,7 @@ describe('helpers', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, ], @@ -815,6 +824,7 @@ describe('helpers', () => { { columnHeaderType: 'not-filtered', id: '@timestamp', + type: 'number', width: 190, }, { @@ -929,6 +939,7 @@ describe('helpers', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, ], @@ -953,6 +964,7 @@ describe('helpers', () => { { columnHeaderType: 'not-filtered', id: '@timestamp', + type: 'number', width: 190, }, { @@ -1026,6 +1038,7 @@ describe('helpers', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, ], @@ -1054,6 +1067,7 @@ describe('helpers', () => { { columnHeaderType: 'not-filtered', id: '@timestamp', + type: 'number', width: 190, }, { @@ -1127,6 +1141,7 @@ describe('helpers', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, ], diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/__snapshots__/index.test.tsx.snap index 36e0652c3032..695032d80f8a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/__snapshots__/index.test.tsx.snap @@ -421,6 +421,7 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = ` Object { "columnHeaderType": "not-filtered", "id": "@timestamp", + "type": "number", "width": 190, }, Object { @@ -468,6 +469,7 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = ` Array [ Object { "columnId": "@timestamp", + "columnType": "number", "sortDirection": "desc", }, ] diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/default_headers.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/default_headers.ts index 082b5103a7d8..82cb3f258710 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/default_headers.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/default_headers.ts @@ -13,6 +13,7 @@ export const defaultHeaders: ColumnHeaderOptions[] = [ { columnHeaderType: defaultColumnHeaderType, id: '@timestamp', + type: 'number', width: DEFAULT_DATE_COLUMN_MIN_WIDTH, }, { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/__snapshots__/index.test.tsx.snap index fa9a4e78d88f..bd0ae9024df5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/__snapshots__/index.test.tsx.snap @@ -7,6 +7,7 @@ exports[`Header renders correctly against snapshot 1`] = ` Object { "columnHeaderType": "not-filtered", "id": "@timestamp", + "type": "number", "width": 190, } } @@ -17,6 +18,7 @@ exports[`Header renders correctly against snapshot 1`] = ` Array [ Object { "columnId": "@timestamp", + "columnType": "number", "sortDirection": "desc", }, ] @@ -27,6 +29,7 @@ exports[`Header renders correctly against snapshot 1`] = ` Object { "columnHeaderType": "not-filtered", "id": "@timestamp", + "type": "number", "width": 190, } } @@ -36,6 +39,7 @@ exports[`Header renders correctly against snapshot 1`] = ` Array [ Object { "columnId": "@timestamp", + "columnType": "number", "sortDirection": "desc", }, ] @@ -47,6 +51,7 @@ exports[`Header renders correctly against snapshot 1`] = ` Object { "columnHeaderType": "not-filtered", "id": "@timestamp", + "type": "number", "width": 190, } } diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx index 58d40c94ac33..20df1bb7a3c6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx @@ -35,6 +35,7 @@ describe('Header', () => { const sort: Sort[] = [ { columnId: columnHeader.id, + columnType: columnHeader.type ?? 'number', sortDirection: Direction.desc, }, ]; @@ -124,6 +125,7 @@ describe('Header', () => { sort: [ { columnId: columnHeader.id, + columnType: columnHeader.type ?? 'number', sortDirection: Direction.asc, // (because the previous state was Direction.desc) }, ], @@ -191,6 +193,7 @@ describe('Header', () => { const nonMatching: Sort[] = [ { columnId: 'differentSocks', + columnType: columnHeader.type ?? 'number', sortDirection: Direction.desc, }, ]; @@ -201,7 +204,11 @@ describe('Header', () => { describe('getNextSortDirection', () => { test('it returns "asc" when the current direction is "desc"', () => { - const sortDescending: Sort = { columnId: columnHeader.id, sortDirection: Direction.desc }; + const sortDescending: Sort = { + columnId: columnHeader.id, + columnType: columnHeader.type ?? 'number', + sortDirection: Direction.desc, + }; expect(getNextSortDirection(sortDescending)).toEqual('asc'); }); @@ -209,6 +216,7 @@ describe('Header', () => { test('it returns "desc" when the current direction is "asc"', () => { const sortAscending: Sort = { columnId: columnHeader.id, + columnType: columnHeader.type ?? 'number', sortDirection: Direction.asc, }; @@ -218,6 +226,7 @@ describe('Header', () => { test('it returns "desc" by default', () => { const sortNone: Sort = { columnId: columnHeader.id, + columnType: columnHeader.type ?? 'number', sortDirection: 'none', }; @@ -230,6 +239,7 @@ describe('Header', () => { const sortMatches: Sort[] = [ { columnId: columnHeader.id, + columnType: columnHeader.type ?? 'number', sortDirection: Direction.desc, }, ]; @@ -246,6 +256,7 @@ describe('Header', () => { const sortDoesNotMatch: Sort[] = [ { columnId: 'someOtherColumn', + columnType: columnHeader.type ?? 'number', sortDirection: 'none', }, ]; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx index 192a9c6b0973..633e7474ffa8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx @@ -35,6 +35,7 @@ export const HeaderComponent: React.FC = ({ const onColumnSort = useCallback(() => { const columnId = header.id; + const columnType = header.type ?? 'text'; const sortDirection = getNewSortDirectionOnClick({ clickedHeader: header, currentSort: sort, @@ -46,6 +47,7 @@ export const HeaderComponent: React.FC = ({ ...sort, { columnId, + columnType, sortDirection, }, ]; @@ -54,6 +56,7 @@ export const HeaderComponent: React.FC = ({ ...sort.slice(0, headerIndex), { columnId, + columnType, sortDirection, }, ...sort.slice(headerIndex + 1), diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.test.tsx index 6eb279644ef3..307166388b49 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.test.tsx @@ -38,6 +38,7 @@ describe('ColumnHeaders', () => { const sort: Sort[] = [ { columnId: '@timestamp', + columnType: 'number', sortDirection: Direction.desc, }, ]; @@ -108,10 +109,12 @@ describe('ColumnHeaders', () => { let mockSort: Sort[] = [ { columnId: '@timestamp', + columnType: 'number', sortDirection: Direction.desc, }, { columnId: 'host.name', + columnType: 'text', sortDirection: Direction.asc, }, ]; @@ -126,10 +129,12 @@ describe('ColumnHeaders', () => { mockSort = [ { columnId: '@timestamp', + columnType: 'number', sortDirection: Direction.desc, }, { columnId: 'host.name', + columnType: 'text', sortDirection: Direction.asc, }, ]; @@ -162,13 +167,15 @@ describe('ColumnHeaders', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: Direction.desc, }, { columnId: 'host.name', + columnType: 'text', sortDirection: Direction.asc, }, - { columnId: 'event.category', sortDirection: Direction.desc }, + { columnId: 'event.category', columnType: 'text', sortDirection: Direction.desc }, ], }) ); @@ -201,9 +208,10 @@ describe('ColumnHeaders', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: Direction.asc, }, - { columnId: 'host.name', sortDirection: Direction.asc }, + { columnId: 'host.name', columnType: 'text', sortDirection: Direction.asc }, ], }) ); @@ -236,9 +244,10 @@ describe('ColumnHeaders', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: Direction.desc, }, - { columnId: 'host.name', sortDirection: Direction.desc }, + { columnId: 'host.name', columnType: 'text', sortDirection: Direction.desc }, ], }) ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx index dd535094e7dc..21f32a211f42 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx @@ -230,11 +230,12 @@ export const ColumnHeadersComponent = ({ id: timelineId, sort: cols.map(({ id, direction }) => ({ columnId: id, + columnType: columnHeaders.find((ch) => ch.id === id)?.type ?? 'text', sortDirection: direction as SortDirection, })), }) ), - [dispatch, timelineId] + [columnHeaders, dispatch, timelineId] ); const sortedColumns = useMemo( () => ({ diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx index cc04b8338299..87b475ef4597 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx @@ -22,6 +22,7 @@ import { TimelineTabs } from '../../../../../common/types/timeline'; const mockSort: Sort[] = [ { columnId: '@timestamp', + columnType: 'number', sortDirection: Direction.desc, }, ]; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/index.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/index.ts index 93fbe314e1da..985c19deaa09 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/index.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/index.ts @@ -13,5 +13,6 @@ export type SortDirection = 'none' | Direction; /** Specifies which column the timeline is sorted on */ export interface Sort { columnId: ColumnId; + columnType: string; sortDirection: SortDirection; } diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/__snapshots__/index.test.tsx.snap index ca75dd669caf..f5064ba66cf2 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/__snapshots__/index.test.tsx.snap @@ -140,6 +140,7 @@ In other use cases the message field can be used to concatenate different values Array [ Object { "columnId": "@timestamp", + "columnType": "number", "sortDirection": "desc", }, ] diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.test.tsx index bf26dc65afcb..89fef405bec7 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.test.tsx @@ -66,6 +66,7 @@ describe('PinnedTabContent', () => { const sort: Sort[] = [ { columnId: '@timestamp', + columnType: 'number', sortDirection: Direction.desc, }, ]; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx index e204578db610..e2eed83ec937 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx @@ -143,8 +143,9 @@ export const PinnedTabContentComponent: React.FC = ({ const timelineQuerySortField = useMemo( () => - sort.map(({ columnId, sortDirection }) => ({ + sort.map(({ columnId, columnType, sortDirection }) => ({ field: columnId, + type: columnType, direction: sortDirection as Direction, })), [sort] diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/__snapshots__/index.test.tsx.snap index e09a66dde6d9..4fbf7788d912 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/__snapshots__/index.test.tsx.snap @@ -283,6 +283,7 @@ In other use cases the message field can be used to concatenate different values Array [ Object { "columnId": "@timestamp", + "columnType": "number", "sortDirection": "desc", }, ] diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx index 4f4b699f046b..3b163a98a6a8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx @@ -67,6 +67,7 @@ describe('Timeline', () => { const sort: Sort[] = [ { columnId: '@timestamp', + columnType: 'number', sortDirection: Direction.desc, }, ]; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx index 94a67643f002..fd9406a64404 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx @@ -211,9 +211,10 @@ export const QueryTabContentComponent: React.FC = ({ const timelineQuerySortField = useMemo( () => - sort.map(({ columnId, sortDirection }) => ({ + sort.map(({ columnId, columnType, sortDirection }) => ({ field: columnId, direction: sortDirection as Direction, + type: columnType, })), [sort] ); diff --git a/x-pack/plugins/security_solution/public/timelines/containers/index.tsx b/x-pack/plugins/security_solution/public/timelines/containers/index.tsx index f9ed46171d09..e76fe4f37680 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/index.tsx @@ -26,7 +26,7 @@ import { TimelineEventsAllRequestOptions, TimelineEdges, TimelineItem, - SortField, + TimelineRequestSortField, } from '../../../common/search_strategy'; import { InspectResponse } from '../../types'; import * as i18n from './translations'; @@ -56,7 +56,7 @@ export interface UseTimelineEventsProps { fields: string[]; indexNames: string[]; limit: number; - sort: SortField[]; + sort: TimelineRequestSortField[]; startDate: string; timerangeKind?: 'absolute' | 'relative'; } @@ -69,6 +69,7 @@ export const initSortDefault = [ { field: '@timestamp', direction: Direction.asc, + type: 'number', }, ]; diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/defaults.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/defaults.ts index fd0d6bd3a9aa..c3f5821b1eaf 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/defaults.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/defaults.ts @@ -55,6 +55,7 @@ export const timelineDefaults: SubsetTimelineModel & Pick { selectedEventIds: {}, show: true, showCheckboxes: false, - sort: [{ columnId: '@timestamp', sortDirection: Direction.desc }], + sort: [{ columnId: '@timestamp', columnType: 'number', sortDirection: Direction.desc }], status: TimelineStatus.active, version: 'WzM4LDFd', id: '11169110-fc22-11e9-8ca9-072f15ce2685', @@ -289,6 +289,7 @@ describe('Epic Timeline', () => { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, ], diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx index 513d61ea862f..e9f39a4fcdd1 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx @@ -61,6 +61,7 @@ describe('epicLocalStorage', () => { const sort: Sort[] = [ { columnId: '@timestamp', + columnType: 'number', sortDirection: Direction.desc, }, ]; @@ -168,6 +169,7 @@ describe('epicLocalStorage', () => { sort: [ { columnId: 'event.severity', + columnType: 'number', sortDirection: Direction.desc, }, ], diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.test.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.test.ts index 0733bf471a12..0d7024754c8b 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.test.ts @@ -103,6 +103,7 @@ const basicTimeline: TimelineModel = { sort: [ { columnId: '@timestamp', + columnType: 'number', sortDirection: Direction.desc, }, ], @@ -932,6 +933,7 @@ describe('Timeline', () => { sort: [ { columnId: 'some column', + columnType: 'text', sortDirection: Direction.desc, }, ], @@ -943,7 +945,9 @@ describe('Timeline', () => { }); test('should update the sort attribute', () => { - expect(update.foo.sort).toEqual([{ columnId: 'some column', sortDirection: Direction.desc }]); + expect(update.foo.sort).toEqual([ + { columnId: 'some column', columnType: 'text', sortDirection: Direction.desc }, + ]); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/pick_saved_timeline.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/pick_saved_timeline.test.ts index 92d2a9c5a307..d9ed99972dbe 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/pick_saved_timeline.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/pick_saved_timeline.test.ts @@ -42,7 +42,7 @@ describe('pickSavedTimeline', () => { templateTimelineVersion: null, eventType: 'all', filters: [], - sort: { sortDirection: 'desc', columnId: '@timestamp' }, + sort: { sortDirection: 'desc', columnType: 'number', columnId: '@timestamp' }, title: 'title', kqlMode: 'filter', timelineType: TimelineType.default, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/__mocks__/create_timelines.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/__mocks__/create_timelines.ts index e8242d969103..18f080925c50 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/__mocks__/create_timelines.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/__mocks__/create_timelines.ts @@ -212,6 +212,6 @@ export const mockTimeline = { templateTimelineId: null, dateRange: { start: '2020-11-03T13:34:40.339Z', end: '2020-11-04T13:34:40.339Z' }, savedQueryId: null, - sort: { columnId: '@timestamp', sortDirection: 'desc' }, + sort: { columnId: '@timestamp', columnType: 'number', sortDirection: 'desc' }, status: 'draft', }; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/__mocks__/import_timelines.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/__mocks__/import_timelines.ts index 90d5b538a520..1ff7385112ca 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/__mocks__/import_timelines.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/__mocks__/import_timelines.ts @@ -23,7 +23,7 @@ export const mockParsedObjects = [ title: 'My duplicate timeline', dateRange: { start: '2020-03-18T09:31:47.294Z', end: '2020-03-19T09:31:47.294Z' }, savedQueryId: null, - sort: { columnId: '@timestamp', sortDirection: 'desc' }, + sort: { columnId: '@timestamp', columnType: 'number', sortDirection: 'desc' }, created: 1584828930463, createdBy: 'angela', updated: 1584868346013, @@ -698,6 +698,7 @@ export const mockCheckTimelinesStatusBeforeInstallResult = { savedQueryId: null, sort: { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, created: 1588162404153, @@ -870,6 +871,7 @@ export const mockCheckTimelinesStatusAfterInstallResult = { savedQueryId: null, sort: { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, timelineType: 'template', @@ -1052,6 +1054,7 @@ export const mockCheckTimelinesStatusAfterInstallResult = { savedQueryId: null, sort: { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, timelineType: 'template', @@ -1172,6 +1175,7 @@ export const mockCheckTimelinesStatusAfterInstallResult = { savedQueryId: null, sort: { columnId: '@timestamp', + columnType: 'number', sortDirection: 'desc', }, timelineType: 'template', diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/__mocks__/request_responses.ts index 026ec1fa847f..5cc2c6034109 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/__mocks__/request_responses.ts @@ -73,7 +73,7 @@ export const inputTimeline: SavedTimeline = { templateTimelineVersion: 1, dateRange: { start: '2020-03-26T12:50:05.527Z', end: '2020-03-27T12:50:05.527Z' }, savedQueryId: null, - sort: { columnId: '@timestamp', sortDirection: 'desc' }, + sort: { columnId: '@timestamp', columnType: 'number', sortDirection: 'desc' }, }; export const inputTemplateTimeline = { @@ -289,7 +289,7 @@ export const mockTimelines = () => ({ title: 'test no.2', dateRange: { start: '2020-02-24T10:09:11.145Z', end: '2020-02-25T10:09:11.145Z' }, savedQueryId: null, - sort: { columnId: '@timestamp', sortDirection: 'desc' }, + sort: { columnId: '@timestamp', columnType: 'number', sortDirection: 'desc' }, created: 1582625382448, createdBy: 'elastic', updated: 1583741197521, @@ -371,7 +371,7 @@ export const mockTimelines = () => ({ title: 'test no.3', dateRange: { start: '2020-02-24T10:09:11.145Z', end: '2020-02-25T10:09:11.145Z' }, savedQueryId: null, - sort: { columnId: '@timestamp', sortDirection: 'desc' }, + sort: { columnId: '@timestamp', columnType: 'number', sortDirection: 'desc' }, created: 1582642817439, createdBy: 'elastic', updated: 1583741175216, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings.ts index 11082cd7295c..dc7565daf0b0 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings.ts @@ -266,10 +266,14 @@ export const timelineSavedObjectMappings: SavedObjectsType['mappings'] = { type: 'keyword', }, sort: { + dynamic: false, properties: { columnId: { type: 'keyword', }, + columnType: { + type: 'keyword', + }, sortDirection: { type: 'keyword', }, diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/query.events_all.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/query.events_all.dsl.ts index 3ff542ebde5f..a5cfc86c7d5c 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/query.events_all.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/query.events_all.dsl.ts @@ -6,10 +6,10 @@ import { isEmpty } from 'lodash/fp'; import { - SortField, TimerangeFilter, TimerangeInput, TimelineEventsAllRequestOptions, + TimelineRequestSortField, } from '../../../../../../common/search_strategy'; import { createQueryFilterClauses } from '../../../../../utils/build_query'; @@ -46,10 +46,15 @@ export const buildTimelineEventsAllQuery = ({ const filter = [...filterClause, ...getTimerangeFilter(timerange), { match_all: {} }]; - const getSortField = (sortFields: SortField[]) => + const getSortField = (sortFields: TimelineRequestSortField[]) => sortFields.map((item) => { const field: string = item.field === 'timestamp' ? '@timestamp' : item.field; - return { [field]: item.direction }; + return { + [field]: { + order: item.direction, + unmapped_type: item.type, + }, + }; }); const dslQuery = {