diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx index 571e04a106cf0..d14f88252b836 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx @@ -63,7 +63,7 @@ describe('StatefulEventsViewer', () => { wrapper.update(); expect(wrapper.text()).toMatchInlineSnapshot( - `"Showing: 12 events1 fields sorted@timestamp1event.severityevent.categoryevent.actionhost.namesource.ipdestination.ipdestination.bytesuser.name_idmessage0 of 12 events123"` + `"Showing: 12 events1 fields sorted@timestamp1event.severityevent.categoryevent.actionhost.namesource.ipdestination.ipdestination.bytesuser.name_idmessage0 of 12 123"` ); }); }); 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 ffbfd1a5123ad..9daa27bd4dc89 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 @@ -212,6 +212,9 @@ export const mockGlobalState: State = { activeTab: TimelineTabs.query, prevActiveTab: TimelineTabs.notes, deletedEventIds: [], + documentType: '', + queryFields: [], + selectAll: false, id: 'test', savedObjectId: null, columns: defaultHeaders, 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 806031b07e0c9..d848469187302 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 @@ -1977,6 +1977,7 @@ export const mockTimelineModel: TimelineModel = { }, deletedEventIds: [], description: 'This is a sample rule description', + documentType: '', eqlOptions: { eventCategoryField: 'event.category', tiebreakerField: 'event.sequence', @@ -2015,6 +2016,7 @@ export const mockTimelineModel: TimelineModel = { kqlQuery: { filterQuery: null, }, + queryFields: [], itemsPerPage: 25, itemsPerPageOptions: [10, 25, 50, 100], loadingEventIds: [], @@ -2022,6 +2024,7 @@ export const mockTimelineModel: TimelineModel = { pinnedEventIds: {}, pinnedEventsSaveObject: {}, savedObjectId: 'ef579e40-jibber-jabber', + selectAll: false, selectedEventIds: {}, show: false, showCheckboxes: false, @@ -2106,6 +2109,7 @@ export const defaultTimelineProps: CreateTimelineProps = { dateRange: { end: '2018-11-05T19:03:25.937Z', start: '2018-11-05T18:58:25.937Z' }, deletedEventIds: [], description: '', + documentType: '', eqlOptions: { eventCategoryField: 'event.category', query: '', @@ -2137,7 +2141,9 @@ export const defaultTimelineProps: CreateTimelineProps = { noteIds: [], pinnedEventIds: {}, pinnedEventsSaveObject: {}, + queryFields: [], savedObjectId: null, + selectAll: false, selectedEventIds: {}, show: false, showCheckboxes: false, 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 08e88567b0fd0..2aa2a2600dbe8 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 @@ -146,6 +146,7 @@ describe('alert actions', () => { }, deletedEventIds: [], description: 'This is a sample rule description', + documentType: '', eqlOptions: { eventCategoryField: 'event.category', query: '', @@ -202,7 +203,9 @@ describe('alert actions', () => { noteIds: [], pinnedEventIds: {}, pinnedEventsSaveObject: {}, + queryFields: [], savedObjectId: null, + selectAll: false, selectedEventIds: {}, show: true, showCheckboxes: false, 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 c0fea1f210a8a..b57b831c5592e 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 @@ -293,6 +293,7 @@ describe('helpers', () => { dataProviders: [], dateRange: { start: '2020-07-07T08:20:18.966Z', end: '2020-07-08T08:20:18.966Z' }, description: '', + documentType: '', deletedEventIds: [], eqlOptions: { eventCategoryField: 'event.category', @@ -325,7 +326,9 @@ describe('helpers', () => { noteIds: [], pinnedEventIds: {}, pinnedEventsSaveObject: {}, + queryFields: [], savedObjectId: 'savedObject-1', + selectAll: false, selectedEventIds: {}, show: false, showCheckboxes: false, @@ -404,6 +407,7 @@ describe('helpers', () => { dataProviders: [], dateRange: { start: '2020-07-07T08:20:18.966Z', end: '2020-07-08T08:20:18.966Z' }, description: '', + documentType: '', deletedEventIds: [], eqlOptions: { eventCategoryField: 'event.category', @@ -436,7 +440,9 @@ describe('helpers', () => { noteIds: [], pinnedEventIds: {}, pinnedEventsSaveObject: {}, + queryFields: [], savedObjectId: 'savedObject-1', + selectAll: false, selectedEventIds: {}, show: false, showCheckboxes: false, @@ -515,6 +521,7 @@ describe('helpers', () => { dataProviders: [], dateRange: { start: '2020-07-07T08:20:18.966Z', end: '2020-07-08T08:20:18.966Z' }, description: '', + documentType: '', deletedEventIds: [], eqlOptions: { eventCategoryField: 'event.category', @@ -547,7 +554,9 @@ describe('helpers', () => { noteIds: [], pinnedEventIds: {}, pinnedEventsSaveObject: {}, + queryFields: [], savedObjectId: 'savedObject-1', + selectAll: false, selectedEventIds: {}, show: false, showCheckboxes: false, @@ -624,6 +633,7 @@ describe('helpers', () => { dataProviders: [], dateRange: { start: '2020-07-07T08:20:18.966Z', end: '2020-07-08T08:20:18.966Z' }, description: '', + documentType: '', deletedEventIds: [], eqlOptions: { eventCategoryField: 'event.category', @@ -656,7 +666,9 @@ describe('helpers', () => { noteIds: [], pinnedEventIds: {}, pinnedEventsSaveObject: {}, + queryFields: [], savedObjectId: 'savedObject-1', + selectAll: false, selectedEventIds: {}, show: false, showCheckboxes: false, @@ -771,6 +783,7 @@ describe('helpers', () => { dataProviders: [], dateRange: { start: '2020-07-07T08:20:18.966Z', end: '2020-07-08T08:20:18.966Z' }, description: '', + documentType: '', deletedEventIds: [], eqlOptions: { eventCategoryField: 'event.category', @@ -806,6 +819,8 @@ describe('helpers', () => { noteIds: [], pinnedEventIds: {}, pinnedEventsSaveObject: {}, + queryFields: [], + selectAll: false, selectedEventIds: {}, show: false, showCheckboxes: false, @@ -907,6 +922,7 @@ describe('helpers', () => { dateRange: { start: '2020-07-07T08:20:18.966Z', end: '2020-07-08T08:20:18.966Z' }, dataProviders: [], description: '', + documentType: '', deletedEventIds: [], eqlOptions: { eventCategoryField: 'event.category', @@ -985,6 +1001,8 @@ describe('helpers', () => { noteIds: [], pinnedEventIds: {}, pinnedEventsSaveObject: {}, + queryFields: [], + selectAll: false, selectedEventIds: {}, show: false, showCheckboxes: false, @@ -1059,6 +1077,7 @@ describe('helpers', () => { dataProviders: [], dateRange: { end: '2020-10-28T11:37:31.655Z', start: '2020-10-27T11:37:31.655Z' }, description: '', + documentType: '', deletedEventIds: [], eqlOptions: { eventCategoryField: 'event.category', @@ -1091,7 +1110,9 @@ describe('helpers', () => { noteIds: [], pinnedEventIds: {}, pinnedEventsSaveObject: {}, + queryFields: [], savedObjectId: 'savedObject-1', + selectAll: false, selectedEventIds: {}, show: false, showCheckboxes: false, @@ -1170,6 +1191,7 @@ describe('helpers', () => { dataProviders: [], dateRange: { end: '2020-07-08T08:20:18.966Z', start: '2020-07-07T08:20:18.966Z' }, description: '', + documentType: '', deletedEventIds: [], eqlOptions: { eventCategoryField: 'event.category', @@ -1202,7 +1224,9 @@ describe('helpers', () => { noteIds: [], pinnedEventIds: {}, pinnedEventsSaveObject: {}, + queryFields: [], savedObjectId: 'savedObject-1', + selectAll: false, selectedEventIds: {}, show: false, showCheckboxes: false, diff --git a/x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.test.ts b/x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.test.ts index f1b5f6a944678..5fa98c11045d5 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.test.ts @@ -28,6 +28,15 @@ const useKibanaMock = useKibana as jest.Mocked; const getExpectedColumns = (model: TimelineModel) => model.columns.map(migrateColumnWidthToInitialWidth).map(migrateColumnLabelToDisplayAsText); +const { + documentType, + filterManager, + isLoading, + queryFields, + selectAll, + ...timelineToStore +} = mockTimelineModel; + describe('SiemLocalStorage', () => { const { localStorage, storage } = createSecuritySolutionStorageMock(); @@ -41,7 +50,7 @@ describe('SiemLocalStorage', () => { const timelineStorage = useTimelinesStorage(); timelineStorage.addTimeline(TimelineId.hostsPageEvents, mockTimelineModel); expect(JSON.parse(localStorage.getItem(LOCAL_STORAGE_TIMELINE_KEY))).toEqual({ - [TimelineId.hostsPageEvents]: mockTimelineModel, + [TimelineId.hostsPageEvents]: timelineToStore, }); }); @@ -50,8 +59,8 @@ describe('SiemLocalStorage', () => { timelineStorage.addTimeline(TimelineId.hostsPageEvents, mockTimelineModel); timelineStorage.addTimeline(TimelineId.hostsPageExternalAlerts, mockTimelineModel); expect(JSON.parse(localStorage.getItem(LOCAL_STORAGE_TIMELINE_KEY))).toEqual({ - [TimelineId.hostsPageEvents]: mockTimelineModel, - [TimelineId.hostsPageExternalAlerts]: mockTimelineModel, + [TimelineId.hostsPageEvents]: timelineToStore, + [TimelineId.hostsPageExternalAlerts]: timelineToStore, }); }); }); @@ -63,8 +72,8 @@ describe('SiemLocalStorage', () => { timelineStorage.addTimeline(TimelineId.hostsPageExternalAlerts, mockTimelineModel); const timelines = timelineStorage.getAllTimelines(); expect(timelines).toEqual({ - [TimelineId.hostsPageEvents]: mockTimelineModel, - [TimelineId.hostsPageExternalAlerts]: mockTimelineModel, + [TimelineId.hostsPageEvents]: timelineToStore, + [TimelineId.hostsPageExternalAlerts]: timelineToStore, }); }); @@ -80,7 +89,7 @@ describe('SiemLocalStorage', () => { const timelineStorage = useTimelinesStorage(); timelineStorage.addTimeline(TimelineId.hostsPageEvents, mockTimelineModel); const timeline = timelineStorage.getTimelineById(TimelineId.hostsPageEvents); - expect(timeline).toEqual(mockTimelineModel); + expect(timeline).toEqual(timelineToStore); }); }); @@ -94,8 +103,8 @@ describe('SiemLocalStorage', () => { TimelineId.hostsPageExternalAlerts, ]); expect(timelines).toEqual({ - [TimelineId.hostsPageEvents]: mockTimelineModel, - [TimelineId.hostsPageExternalAlerts]: mockTimelineModel, + [TimelineId.hostsPageEvents]: timelineToStore, + [TimelineId.hostsPageExternalAlerts]: timelineToStore, }); }); @@ -126,7 +135,7 @@ describe('SiemLocalStorage', () => { TimelineId.hostsPageExternalAlerts, ]); expect(timelines).toEqual({ - [TimelineId.hostsPageEvents]: mockTimelineModel, + [TimelineId.hostsPageEvents]: timelineToStore, }); }); @@ -152,8 +161,8 @@ describe('SiemLocalStorage', () => { // all legacy `width` values are migrated to `initialWidth`: expect(timelines).toStrictEqual({ [TimelineId.hostsPageEvents]: { - ...mockTimelineModel, - columns: mockTimelineModel.columns.map((c) => ({ + ...timelineToStore, + columns: timelineToStore.columns.map((c) => ({ ...c, displayAsText: undefined, initialWidth: 98765, @@ -161,7 +170,7 @@ describe('SiemLocalStorage', () => { })), }, [TimelineId.hostsPageExternalAlerts]: { - ...mockTimelineModel, + ...timelineToStore, columns: getExpectedColumns(mockTimelineModel), }, }); @@ -187,8 +196,8 @@ describe('SiemLocalStorage', () => { expect(timelines).toStrictEqual({ [TimelineId.hostsPageEvents]: { - ...mockTimelineModel, - columns: mockTimelineModel.columns.map((c) => ({ + ...timelineToStore, + columns: timelineToStore.columns.map((c) => ({ ...c, displayAsText: undefined, initialWidth: c.initialWidth, // initialWidth is unchanged @@ -196,7 +205,7 @@ describe('SiemLocalStorage', () => { })), }, [TimelineId.hostsPageExternalAlerts]: { - ...mockTimelineModel, + ...timelineToStore, columns: getExpectedColumns(mockTimelineModel), }, }); @@ -223,15 +232,15 @@ describe('SiemLocalStorage', () => { // all legacy `label` values are migrated to `displayAsText`: expect(timelines).toStrictEqual({ [TimelineId.hostsPageEvents]: { - ...mockTimelineModel, - columns: mockTimelineModel.columns.map((c, i) => ({ + ...timelineToStore, + columns: timelineToStore.columns.map((c, i) => ({ ...c, displayAsText: `A legacy label ${i}`, label: `A legacy label ${i}`, })), }, [TimelineId.hostsPageExternalAlerts]: { - ...mockTimelineModel, + ...timelineToStore, columns: getExpectedColumns(mockTimelineModel), }, }); @@ -259,8 +268,8 @@ describe('SiemLocalStorage', () => { expect(timelines).toStrictEqual({ [TimelineId.hostsPageEvents]: { - ...mockTimelineModel, - columns: mockTimelineModel.columns.map((c, i) => ({ + ...timelineToStore, + columns: timelineToStore.columns.map((c, i) => ({ ...c, displayAsText: 'Label will NOT be migrated to displayAsText, because displayAsText already has a value', @@ -268,7 +277,7 @@ describe('SiemLocalStorage', () => { })), }, [TimelineId.hostsPageExternalAlerts]: { - ...mockTimelineModel, + ...timelineToStore, columns: getExpectedColumns(mockTimelineModel), }, }); @@ -293,11 +302,11 @@ describe('SiemLocalStorage', () => { expect(timelines).toStrictEqual({ [TimelineId.hostsPageEvents]: { - ...mockTimelineModel, + ...timelineToStore, columns: 'this is NOT an array', }, [TimelineId.hostsPageExternalAlerts]: { - ...mockTimelineModel, + ...timelineToStore, columns: getExpectedColumns(mockTimelineModel), }, }); @@ -311,8 +320,8 @@ describe('SiemLocalStorage', () => { timelineStorage.addTimeline(TimelineId.hostsPageExternalAlerts, mockTimelineModel); const timelines = getAllTimelinesInStorage(storage); expect(timelines).toEqual({ - [TimelineId.hostsPageEvents]: mockTimelineModel, - [TimelineId.hostsPageExternalAlerts]: mockTimelineModel, + [TimelineId.hostsPageEvents]: timelineToStore, + [TimelineId.hostsPageExternalAlerts]: timelineToStore, }); }); @@ -326,7 +335,7 @@ describe('SiemLocalStorage', () => { it('adds a timeline when storage is empty', () => { addTimelineInStorage(storage, TimelineId.hostsPageEvents, mockTimelineModel); expect(JSON.parse(localStorage.getItem(LOCAL_STORAGE_TIMELINE_KEY))).toEqual({ - [TimelineId.hostsPageEvents]: mockTimelineModel, + [TimelineId.hostsPageEvents]: timelineToStore, }); }); @@ -334,8 +343,8 @@ describe('SiemLocalStorage', () => { addTimelineInStorage(storage, TimelineId.hostsPageEvents, mockTimelineModel); addTimelineInStorage(storage, TimelineId.hostsPageExternalAlerts, mockTimelineModel); expect(JSON.parse(localStorage.getItem(LOCAL_STORAGE_TIMELINE_KEY))).toEqual({ - [TimelineId.hostsPageEvents]: mockTimelineModel, - [TimelineId.hostsPageExternalAlerts]: mockTimelineModel, + [TimelineId.hostsPageEvents]: timelineToStore, + [TimelineId.hostsPageExternalAlerts]: timelineToStore, }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.tsx b/x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.tsx index 99f45c7d9a4b4..0062553b5d785 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.tsx @@ -85,13 +85,27 @@ export const addTimelineInStorage = ( id: TimelineIdLiteral, timeline: TimelineModel ) => { + const timelineToStore = cleanStorageTimeline(timeline); const timelines = getAllTimelinesInStorage(storage); storage.set(LOCAL_STORAGE_TIMELINE_KEY, { ...timelines, - [id]: timeline, + [id]: timelineToStore, }); }; +const cleanStorageTimeline = (timeline: TimelineModel) => { + // discard unneeded fields to make sure the object serialization works + const { + documentType, + filterManager, + isLoading, + queryFields, + selectAll, + ...timelineToStore + } = timeline; + return timelineToStore; +}; + export const useTimelinesStorage = (): TimelinesStorage => { const { storage } = useKibana().services; 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 d8fd82005dfbe..f4bf1acde34d4 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 @@ -19,6 +19,7 @@ export const timelineDefaults: SubsetTimelineModel & activeTab: TimelineTabs.query, prevActiveTab: TimelineTabs.query, columns: defaultHeaders, + documentType: '', dataProviders: [], dateRange: { start, end }, deletedEventIds: [], @@ -50,6 +51,7 @@ export const timelineDefaults: SubsetTimelineModel & filterQuery: null, }, loadingEventIds: [], + queryFields: [], title: '', timelineType: TimelineType.default, templateTimelineId: null, @@ -58,6 +60,7 @@ export const timelineDefaults: SubsetTimelineModel & pinnedEventIds: {}, pinnedEventsSaveObject: {}, savedObjectId: null, + selectAll: false, selectedEventIds: {}, show: false, showCheckboxes: false, diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.test.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.test.ts index eabcdd53fb994..2f355c3972264 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.test.ts @@ -90,6 +90,7 @@ describe('Epic Timeline', () => { ], deletedEventIds: [], description: '', + documentType: '', eqlOptions: { eventCategoryField: 'event.category', tiebreakerField: '', @@ -144,6 +145,8 @@ describe('Epic Timeline', () => { }, }, loadingEventIds: [], + queryFields: [], + selectAll: false, title: 'saved', timelineType: TimelineType.default, templateTimelineId: null, diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts index 335946ece11eb..b16cc75461112 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts @@ -81,6 +81,7 @@ export type SubsetTimelineModel = Readonly< | 'dataProviders' | 'deletedEventIds' | 'description' + | 'documentType' | 'eventType' | 'eventIdToNoteIds' | 'excludedRowRendererIds' @@ -96,6 +97,7 @@ export type SubsetTimelineModel = Readonly< | 'itemsPerPageOptions' | 'kqlMode' | 'kqlQuery' + | 'queryFields' | 'title' | 'timelineType' | 'templateTimelineId' @@ -105,6 +107,7 @@ export type SubsetTimelineModel = Readonly< | 'pinnedEventIds' | 'pinnedEventsSaveObject' | 'dateRange' + | 'selectAll' | 'selectedEventIds' | 'show' | 'showCheckboxes' 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 c221961f9a21b..b3ac003a72f3b 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 @@ -90,6 +90,7 @@ const basicTimeline: TimelineModel = { }, deletedEventIds: [], description: '', + documentType: '', eqlOptions: { eventCategoryField: 'event.category', tiebreakerField: '', @@ -116,7 +117,9 @@ const basicTimeline: TimelineModel = { noteIds: [], pinnedEventIds: {}, pinnedEventsSaveObject: {}, + queryFields: [], savedObjectId: null, + selectAll: false, selectedEventIds: {}, show: true, showCheckboxes: false, diff --git a/x-pack/plugins/timelines/public/store/t_grid/model.ts b/x-pack/plugins/timelines/public/store/t_grid/model.ts index a29be15f7456c..ce880c9a44c72 100644 --- a/x-pack/plugins/timelines/public/store/t_grid/model.ts +++ b/x-pack/plugins/timelines/public/store/t_grid/model.ts @@ -84,12 +84,14 @@ export type TGridModelForTimeline = Pick< | 'columns' | 'dateRange' | 'deletedEventIds' + | 'documentType' | 'excludedRowRendererIds' | 'expandedDetail' | 'filters' | 'filterManager' | 'graphEventId' | 'kqlQuery' + | 'queryFields' | 'id' | 'indexNames' | 'isLoading' @@ -97,6 +99,7 @@ export type TGridModelForTimeline = Pick< | 'itemsPerPage' | 'itemsPerPageOptions' | 'loadingEventIds' + | 'selectAll' | 'showCheckboxes' | 'sort' | 'selectedEventIds'