From 385884d98b21e5613eadb613ef984aa87da282ae Mon Sep 17 00:00:00 2001 From: Michael Olorunnisola Date: Mon, 15 Jul 2024 12:23:45 -0400 Subject: [PATCH] [Bug][Investigations] - Fix timeline column reset (#188240) ## Summary **Bug:** Within the new timeline, we have default columns that show whenever an empty array for columns are provided. This was causing columns to re-appear in the `Selected fields` section even though the columns were not actually selected anymore leading to mismatched state between the browser ui and the table preventing the default columns from being removed again without page refresh. _The old timeline table is not affected_. https://github.com/user-attachments/assets/7d16b8c3-be1a-4bc7-87b0-62fcac563f15 **Fix:** The logic used to default an empty array of columns to the default timeline columns has been updated to allow the empty array to be passed. With the old timeline experience this just means all columns _can_ be removed and you'd see an empty table, but with the new unified table (which will be the default in 8.15 after https://github.com/user-attachments/assets/e5fbaf48-77e3-4363-8232-35d256729b7e --- .../public/common/mock/timeline_results.ts | 2 +- .../components/alerts_table/actions.test.tsx | 2 +- .../body/unified_timeline_body.test.tsx | 2 +- .../timeline/body/unified_timeline_body.tsx | 5 +- .../use_timeline_columns.test.ts.snap | 216 +----------------- .../tabs/shared/use_timeline_columns.test.ts | 4 +- .../tabs/shared/use_timeline_columns.tsx | 6 +- .../public/timelines/store/defaults.ts | 2 +- 8 files changed, 10 insertions(+), 229 deletions(-) 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 1cbddd4725bc7..8c823e2e83606 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 @@ -2117,7 +2117,7 @@ export const defaultTimelineProps: CreateTimelineProps = { savedSearch: null, isDataProviderVisible: false, sampleSize: 500, - rowHeight: 1, + rowHeight: 3, }, to: '2018-11-05T19:03:25.937Z', notes: null, 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 c72b3be8dc51a..bc260da6c4046 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 @@ -449,7 +449,7 @@ describe('alert actions', () => { savedSearchId: null, savedSearch: null, isDataProviderVisible: false, - rowHeight: 1, + rowHeight: 3, sampleSize: 500, }, to: '2018-11-05T19:03:25.937Z', diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.test.tsx index 401fe8763ada5..5538f739a8e9e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.test.tsx @@ -100,7 +100,7 @@ describe('UnifiedTimelineBody', () => { expect(MockUnifiedTimelineComponent).toHaveBeenLastCalledWith( expect.objectContaining({ - columns: defaultUdtHeaders, + columns: [], }), {} ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.tsx index d832eee22bb64..9f1a4eb57da48 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.tsx @@ -8,7 +8,6 @@ import type { ComponentProps, ReactElement } from 'react'; import React, { useEffect, useState, useMemo } from 'react'; import { RootDragDropProvider } from '@kbn/dom-drag-drop'; -import { isEmpty } from 'lodash'; import { StyledTableFlexGroup, StyledUnifiedTableFlexItem } from '../unified_components/styles'; import { UnifiedTimeline } from '../unified_components'; import { defaultUdtHeaders } from '../unified_components/default_headers'; @@ -59,9 +58,7 @@ export const UnifiedTimelineBody = (props: UnifiedTimelineBodyProps) => { }); }, [events, pageInfo.activePage]); - const columnsHeader = useMemo(() => { - return isEmpty(columns) ? defaultUdtHeaders : columns; - }, [columns]); + const columnsHeader = useMemo(() => columns ?? defaultUdtHeaders, [columns]); return ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/__snapshots__/use_timeline_columns.test.ts.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/__snapshots__/use_timeline_columns.test.ts.snap index 5d68c438f6020..676051194a1ed 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/__snapshots__/use_timeline_columns.test.ts.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/__snapshots__/use_timeline_columns.test.ts.snap @@ -1,212 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`useTimelineColumns augmentedColumnHeaders should return the default columns 1`] = ` -Array [ - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "date", - ], - "format": "", - "id": "@timestamp", - "initialWidth": 215, - "name": "@timestamp", - "readFromDocValues": true, - "searchable": true, - "type": "date", - }, - Object { - "aggregatable": false, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "text", - ], - "format": "string", - "id": "message", - "initialWidth": 360, - "name": "message", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "keyword", - ], - "format": "string", - "id": "event.category", - "name": "event.category", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "keyword", - ], - "format": "string", - "id": "event.action", - "name": "event.action", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "keyword", - ], - "format": "string", - "id": "host.name", - "name": "host.name", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "ip", - ], - "format": "", - "id": "source.ip", - "name": "source.ip", - "searchable": true, - "type": "ip", - }, - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "ip", - ], - "format": "", - "id": "destination.ip", - "name": "destination.ip", - "searchable": true, - "type": "ip", - }, - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "keyword", - ], - "format": "string", - "id": "user.name", - "name": "user.name", - "searchable": true, - "type": "string", - }, -] -`; +exports[`useTimelineColumns augmentedColumnHeaders should return the default columns 1`] = `Array []`; -exports[`useTimelineColumns augmentedColumnHeaders should return the default unified data table (udt) columns 1`] = ` -Array [ - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "date", - ], - "format": "", - "id": "@timestamp", - "initialWidth": 215, - "name": "@timestamp", - "readFromDocValues": true, - "searchable": true, - "type": "date", - }, - Object { - "aggregatable": false, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "text", - ], - "format": "string", - "id": "message", - "initialWidth": 360, - "name": "message", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "keyword", - ], - "format": "string", - "id": "event.category", - "name": "event.category", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "keyword", - ], - "format": "string", - "id": "event.action", - "name": "event.action", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "keyword", - ], - "format": "string", - "id": "host.name", - "name": "host.name", - "searchable": true, - "type": "string", - }, - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "ip", - ], - "format": "", - "id": "source.ip", - "name": "source.ip", - "searchable": true, - "type": "ip", - }, - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "ip", - ], - "format": "", - "id": "destination.ip", - "name": "destination.ip", - "searchable": true, - "type": "ip", - }, - Object { - "aggregatable": true, - "columnHeaderType": "not-filtered", - "esTypes": Array [ - "keyword", - ], - "format": "string", - "id": "user.name", - "name": "user.name", - "searchable": true, - "type": "string", - }, -] -`; +exports[`useTimelineColumns augmentedColumnHeaders should return the default unified data table (udt) columns 1`] = `Array []`; exports[`useTimelineColumns augmentedColumnHeaders should return the provided columns 1`] = ` Array [ @@ -263,14 +59,6 @@ Array [ exports[`useTimelineColumns getTimelineQueryFieldsFromColumns should return the list of all the fields 1`] = ` Array [ - "@timestamp", - "message", - "event.category", - "event.action", - "host.name", - "source.ip", - "destination.ip", - "user.name", "@timestamp", "kibana.alert.workflow_status", "kibana.alert.workflow_tags", diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.test.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.test.ts index 2ba6d719699d4..53e6401747ca5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.test.ts @@ -55,7 +55,7 @@ describe('useTimelineColumns', () => { const { result } = renderHook(() => useTimelineColumns([]), { wrapper: TestProviders, }); - expect(result.current.localColumns).toEqual(defaultHeaders); + expect(result.current.localColumns).toEqual([]); }); it('should return the default unified data table (udt) columns', () => { @@ -63,7 +63,7 @@ describe('useTimelineColumns', () => { const { result } = renderHook(() => useTimelineColumns([]), { wrapper: TestProviders, }); - expect(result.current.localColumns).toEqual(defaultUdtHeaders); + expect(result.current.localColumns).toEqual([]); }); it('should return the provided columns', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.tsx index 54d965d55d0ba..966039181561a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import { isEmpty } from 'lodash/fp'; import { useMemo } from 'react'; import { SourcererScopeName } from '../../../../../sourcerer/store/model'; import { useSourcererDataView } from '../../../../../sourcerer/containers'; @@ -28,10 +27,7 @@ export const useTimelineColumns = (columns: ColumnHeaderOptions[]) => { [unifiedComponentsInTimelineDisabled] ); - const localColumns = useMemo( - () => (isEmpty(columns) ? defaultColumns : columns), - [columns, defaultColumns] - ); + const localColumns = useMemo(() => columns ?? defaultColumns, [columns, defaultColumns]); const augmentedColumnHeaders = memoizedGetTimelineColumnHeaders( localColumns, diff --git a/x-pack/plugins/security_solution/public/timelines/store/defaults.ts b/x-pack/plugins/security_solution/public/timelines/store/defaults.ts index ed177107a96f0..7f9e7edae432d 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/defaults.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/defaults.ts @@ -102,7 +102,7 @@ export const timelineDefaults: SubsetTimelineModel & savedSearch: null, isDataProviderVisible: false, sampleSize: 500, - rowHeight: 1, + rowHeight: 3, }; export const getTimelineManageDefaults = (id: string) => ({