diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index a16b88f649618..ffb9e9748d9c1 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -183,10 +183,6 @@ export const allowedExperimentalValues = Object.freeze({ * */ timelineEsqlTabDisabled: false, - /* - * Disables experimental Discover components, UnifiedFieldList and UnifiedDataTable in Timeline. - */ - unifiedComponentsInTimelineDisabled: false, /* * Disables date pickers and sourcerer in analyzer if needed. diff --git a/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.test.tsx b/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.test.tsx index 5b48b4286fe63..22320b2a9a3db 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.test.tsx @@ -14,7 +14,6 @@ import { TimelineTabs } from '../../../../common/types'; import { HeaderActions } from './header_actions'; import { timelineActions } from '../../../timelines/store'; import { getColumnHeader } from '../../../timelines/components/timeline/body/column_headers/helpers'; -import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; jest.mock('../../hooks/use_experimental_features', () => ({ useIsExperimentalFeatureEnabled: jest.fn(), @@ -141,51 +140,23 @@ describe('HeaderActions', () => { }); }); - describe('conditional components based on unifiedComponentsInTimelineDisabled', () => { - describe('when unifiedComponentsInTimelineDisabled is false', () => { - beforeEach(() => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false); - }); - it('should not show the event renderer settings', () => { - const result = render( - - - - ); - expect(result.queryByTestId('show-row-renderers-gear')).toBeNull(); - }); - - it('should not show the sorting settings', () => { - const result = render( - - - - ); - expect(result.queryByTestId('timeline-sorting-fields')).toBeNull(); - }); + describe('Controls', () => { + it('should not show the event renderer settings', () => { + const result = render( + + + + ); + expect(result.queryByTestId('show-row-renderers-gear')).toBeNull(); }); - describe('when unifiedComponentsInTimelineDisabled is true', () => { - beforeEach(() => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); - }); - it('should show the event renderer settings', () => { - const result = render( - - - - ); - result.getByTestId('show-row-renderers-gear'); - }); - - it('should show the sorting settings', () => { - const result = render( - - - - ); - result.getByTestId('timeline-sorting-fields'); - }); + it('should not show the sorting settings', () => { + const result = render( + + + + ); + expect(result.queryByTestId('timeline-sorting-fields')).toBeNull(); }); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.tsx b/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.tsx index 7dabf3014da95..1341cb72104d8 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.tsx +++ b/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.tsx @@ -6,13 +6,12 @@ */ import React, { useMemo, useCallback, memo } from 'react'; -import type { EuiDataGridSorting, EuiDataGridSchemaDetector } from '@elastic/eui'; -import { EuiButtonIcon, EuiToolTip, useDataGridColumnSorting, EuiCheckbox } from '@elastic/eui'; +import { EuiButtonIcon, EuiToolTip, EuiCheckbox } from '@elastic/eui'; import { useDispatch } from 'react-redux'; import styled from 'styled-components'; -import type { HeaderActionProps, SortDirection } from '../../../../common/types'; -import { TimelineTabs, TimelineId } from '../../../../common/types'; +import type { HeaderActionProps } from '../../../../common/types'; +import { TimelineId } from '../../../../common/types'; import { isFullScreen } from '../../../timelines/components/timeline/body/column_headers'; import { isActiveTimeline } from '../../../helpers'; import { getColumnHeader } from '../../../timelines/components/timeline/body/column_headers/helpers'; @@ -21,28 +20,12 @@ import { useGlobalFullScreen, useTimelineFullScreen } from '../../containers/use import { useKibana } from '../../lib/kibana'; import { DEFAULT_ACTION_BUTTON_WIDTH } from '.'; import { EventsTh, EventsThContent } from '../../../timelines/components/timeline/styles'; -import { StatefulRowRenderersBrowser } from '../../../timelines/components/row_renderers_browser'; import { EXIT_FULL_SCREEN } from '../exit_full_screen/translations'; import { EventsSelect } from '../../../timelines/components/timeline/body/column_headers/events_select'; import * as i18n from './translations'; -import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; import { useDeepEqualSelector } from '../../hooks/use_selector'; import { selectTimelineById } from '../../../timelines/store/selectors'; -const SortingColumnsContainer = styled.div` - button { - color: ${({ theme }) => theme.eui.euiColorPrimary}; - } - - .euiPopover .euiButtonEmpty { - padding: 0; - - .euiButtonEmpty__text { - display: none; - } - } -`; - const FieldBrowserContainer = styled.div` .euiToolTipAnchor { .euiButtonContent { @@ -66,23 +49,15 @@ const ActionsContainer = styled.div` display: flex; `; -// Defined statically to reduce rerenders -const emptySchema = {}; -const emptySchemaDetectors: EuiDataGridSchemaDetector[] = []; - const HeaderActionsComponent: React.FC = memo( ({ - width, browserFields, columnHeaders, - isEventViewer = false, isSelectAllChecked, onSelectAll, showEventsSelect, showSelectAllCheckbox, showFullScreenToggle = true, - sort, - tabType, timelineId, fieldBrowserOptions, }) => { @@ -91,10 +66,6 @@ const HeaderActionsComponent: React.FC = memo( const { timelineFullScreen, setTimelineFullScreen } = useTimelineFullScreen(); const dispatch = useDispatch(); - const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled( - 'unifiedComponentsInTimelineDisabled' - ); - const { defaultColumns } = useDeepEqualSelector((state) => selectTimelineById(state, timelineId) ); @@ -129,57 +100,6 @@ const HeaderActionsComponent: React.FC = memo( [onSelectAll] ); - const onSortColumns = useCallback( - (cols: EuiDataGridSorting['columns']) => - dispatch( - timelineActions.updateSort({ - id: timelineId, - sort: cols.map(({ id, direction }) => { - const columnHeader = columnHeaders.find((ch) => ch.id === id); - const columnType = columnHeader?.type ?? ''; - const esTypes = columnHeader?.esTypes ?? []; - - return { - columnId: id, - columnType, - esTypes, - sortDirection: direction as SortDirection, - }; - }), - }) - ), - [columnHeaders, dispatch, timelineId] - ); - - const sortedColumns = useMemo( - () => ({ - onSort: onSortColumns, - columns: - sort?.map<{ id: string; direction: 'asc' | 'desc' }>(({ columnId, sortDirection }) => ({ - id: columnId, - direction: sortDirection as 'asc' | 'desc', - })) ?? [], - }), - [onSortColumns, sort] - ); - const displayValues = useMemo( - () => - columnHeaders?.reduce((acc, ch) => ({ ...acc, [ch.id]: ch.displayAsText ?? ch.id }), {}) ?? - {}, - [columnHeaders] - ); - - const myColumns = useMemo( - () => - columnHeaders?.map(({ aggregatable, displayAsText, id, type }) => ({ - id, - isSortable: aggregatable, - displayAsText, - schema: type, - })) ?? [], - [columnHeaders] - ); - const onResetColumns = useCallback(() => { dispatch(timelineActions.updateColumns({ id: timelineId, columns: defaultColumns })); }, [defaultColumns, dispatch, timelineId]); @@ -206,14 +126,6 @@ const HeaderActionsComponent: React.FC = memo( [columnHeaders, dispatch, timelineId, defaultColumns] ); - const ColumnSorting = useDataGridColumnSorting({ - columns: myColumns, - sorting: sortedColumns, - schema: emptySchema, - schemaDetectors: emptySchemaDetectors, - displayValues, - }); - return ( {showSelectAllCheckbox && ( @@ -242,11 +154,6 @@ const HeaderActionsComponent: React.FC = memo( )} - {unifiedComponentsInTimelineDisabled && ( - - - - )} {showFullScreenToggle && ( @@ -275,15 +182,6 @@ const HeaderActionsComponent: React.FC = memo( )} - {tabType !== TimelineTabs.eql && unifiedComponentsInTimelineDisabled && ( - - - - {ColumnSorting} - - - - )} {showEventsSelect && ( diff --git a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts index d885787c14b12..5e032a9a97d07 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts @@ -19,10 +19,6 @@ import { URL_PARAM_KEY } from '../use_url_state'; import { useIsExperimentalFeatureEnabled } from '../use_experimental_features'; export const useInitTimelineFromUrlParam = () => { - const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled( - 'unifiedComponentsInTimelineDisabled' - ); - const isEsqlTabDisabled = useIsExperimentalFeatureEnabled('timelineEsqlTabDisabled'); const queryTimelineById = useQueryTimelineById(); @@ -43,11 +39,10 @@ export const useInitTimelineFromUrlParam = () => { timelineId: initialState.id, openTimeline: initialState.isOpen, savedSearchId: initialState.savedSearchId, - unifiedComponentsInTimelineDisabled, }); } }, - [isEsqlTabDisabled, queryTimelineById, unifiedComponentsInTimelineDisabled] + [isEsqlTabDisabled, queryTimelineById] ); useEffect(() => { diff --git a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_query_timeline_by_id_on_url_change.ts b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_query_timeline_by_id_on_url_change.ts index d4df6d67504d6..60d4ff10b8de1 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_query_timeline_by_id_on_url_change.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_query_timeline_by_id_on_url_change.ts @@ -21,7 +21,6 @@ import { getQueryStringFromLocation, } from '../../utils/global_query_string/helpers'; import { URL_PARAM_KEY } from '../use_url_state'; -import { useIsExperimentalFeatureEnabled } from '../use_experimental_features'; /** * After the initial load of the security solution, timeline is not updated when the timeline URL search value is changed @@ -42,10 +41,6 @@ export const useQueryTimelineByIdOnUrlChange = () => { const oldSearch = usePrevious(search); const timelineIdFromReduxStore = flyoutTimeline?.savedObjectId ?? ''; - const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled( - 'unifiedComponentsInTimelineDisabled' - ); - const [previousTimeline, currentTimeline] = useMemo(() => { const oldUrlStateString = getQueryStringKeyValue({ urlKey: URL_PARAM_KEY.timeline, @@ -74,18 +69,9 @@ export const useQueryTimelineByIdOnUrlChange = () => { graphEventId, timelineId: newId, openTimeline: true, - unifiedComponentsInTimelineDisabled, }); } - }, [ - timelineIdFromReduxStore, - oldId, - newId, - activeTab, - graphEventId, - queryTimelineById, - unifiedComponentsInTimelineDisabled, - ]); + }, [timelineIdFromReduxStore, oldId, newId, activeTab, graphEventId, queryTimelineById]); }; export const getQueryStringKeyValue = ({ search, urlKey }: { search: string; urlKey: string }) => diff --git a/x-pack/plugins/security_solution/public/common/utils/timeline/use_timeline_click.tsx b/x-pack/plugins/security_solution/public/common/utils/timeline/use_timeline_click.tsx index db42ca9b774bd..f5e866f240e16 100644 --- a/x-pack/plugins/security_solution/public/common/utils/timeline/use_timeline_click.tsx +++ b/x-pack/plugins/security_solution/public/common/utils/timeline/use_timeline_click.tsx @@ -8,25 +8,19 @@ import { useCallback } from 'react'; import { useQueryTimelineById } from '../../../timelines/components/open_timeline/helpers'; import type { TimelineErrorCallback } from '../../../timelines/components/open_timeline/types'; -import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; export const useTimelineClick = () => { const queryTimelineById = useQueryTimelineById(); - const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled( - 'unifiedComponentsInTimelineDisabled' - ); - const handleTimelineClick = useCallback( (timelineId: string, onError: TimelineErrorCallback, graphEventId?: string) => { queryTimelineById({ graphEventId, timelineId, onError, - unifiedComponentsInTimelineDisabled, }); }, - [queryTimelineById, unifiedComponentsInTimelineDisabled] + [queryTimelineById] ); return handleTimelineClick; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx index a68d773468e75..a67eb08496dd0 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx @@ -19,7 +19,6 @@ import { useApi } from '@kbn/securitysolution-list-hooks'; import type { Filter } from '@kbn/es-query'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { isEmpty } from 'lodash'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { createHistoryEntry } from '../../../../common/utils/global_query_string/helpers'; import { useKibana } from '../../../../common/lib/kibana'; import { TimelineId } from '../../../../../common/types/timeline'; @@ -35,7 +34,6 @@ import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; import { ALERTS_ACTIONS } from '../../../../common/lib/apm/user_actions'; import { defaultUdtHeaders } from '../../../../timelines/components/timeline/unified_components/default_headers'; -import { defaultHeaders } from '../../../../timelines/components/timeline/body/column_headers/default_headers'; interface UseInvestigateInTimelineActionProps { ecsRowData?: Ecs | Ecs[] | null; @@ -146,21 +144,13 @@ export const useInvestigateInTimeline = ({ timelineType: TimelineTypeEnum.default, }); - const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled( - 'unifiedComponentsInTimelineDisabled' - ); - const updateTimeline = useUpdateTimeline(); const createTimeline = useCallback( async ({ from: fromTimeline, timeline, to: toTimeline, ruleNote }: CreateTimelineProps) => { const newColumns = timeline.columns; const newColumnsOverride = - !newColumns || isEmpty(newColumns) - ? !unifiedComponentsInTimelineDisabled - ? defaultUdtHeaders - : defaultHeaders - : newColumns; + !newColumns || isEmpty(newColumns) ? defaultUdtHeaders : newColumns; await clearActiveTimeline(); updateTimelineIsLoading({ id: TimelineId.active, isLoading: false }); @@ -175,7 +165,6 @@ export const useInvestigateInTimeline = ({ indexNames: timeline.indexNames ?? [], show: true, excludedRowRendererIds: - !unifiedComponentsInTimelineDisabled && timeline.timelineType !== TimelineTypeEnum.template ? timeline.excludedRowRendererIds : [], @@ -184,12 +173,7 @@ export const useInvestigateInTimeline = ({ ruleNote, }); }, - [ - updateTimeline, - updateTimelineIsLoading, - clearActiveTimeline, - unifiedComponentsInTimelineDisabled, - ] + [updateTimeline, updateTimelineIsLoading, clearActiveTimeline] ); const investigateInTimelineAlertClick = useCallback(async () => { diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx index a8eec62f2d58a..27c2699cdf195 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx @@ -10,7 +10,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; import { i18n } from '@kbn/i18n'; import type { EqlOptionsSelected } from '@kbn/timelines-plugin/common'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { convertKueryToElasticSearchQuery } from '../../../../common/lib/kuery'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { useSourcererDataView } from '../../../../sourcerer/containers'; @@ -48,10 +47,6 @@ export const useRuleFromTimeline = (setRuleQuery: SetRuleQuery): RuleFromTimelin SourcererScopeName.timeline ); - const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled( - 'unifiedComponentsInTimelineDisabled' - ); - const isEql = useRef(false); // selectedTimeline = timeline to set rule from @@ -200,11 +195,10 @@ export const useRuleFromTimeline = (setRuleQuery: SetRuleQuery): RuleFromTimelin queryTimelineById({ timelineId, onOpenTimeline, - unifiedComponentsInTimelineDisabled, }); } }, - [onOpenTimeline, queryTimelineById, selectedTimeline, unifiedComponentsInTimelineDisabled] + [onOpenTimeline, queryTimelineById, selectedTimeline] ); const [urlStateInitialized, setUrlStateInitialized] = useState(false); diff --git a/x-pack/plugins/security_solution/public/notes/components/open_timeline_button.test.tsx b/x-pack/plugins/security_solution/public/notes/components/open_timeline_button.test.tsx index 85ecfce68e5d9..c6a2629494758 100644 --- a/x-pack/plugins/security_solution/public/notes/components/open_timeline_button.test.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/open_timeline_button.test.tsx @@ -10,7 +10,6 @@ import React from 'react'; import { OpenTimelineButtonIcon } from './open_timeline_button'; import type { Note } from '../../../common/api/timeline'; import { OPEN_TIMELINE_BUTTON_TEST_ID } from './test_ids'; -import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { useQueryTimelineById } from '../../timelines/components/open_timeline/helpers'; jest.mock('../../common/hooks/use_experimental_features'); @@ -40,11 +39,6 @@ describe('OpenTimelineButtonIcon', () => { const openTimeline = jest.fn(); (useQueryTimelineById as jest.Mock).mockReturnValue(openTimeline); - const unifiedComponentsInTimelineDisabled = false; - (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue( - unifiedComponentsInTimelineDisabled - ); - const { getByTestId } = render(); const button = getByTestId(`${OPEN_TIMELINE_BUTTON_TEST_ID}-${index}`); @@ -55,7 +49,6 @@ describe('OpenTimelineButtonIcon', () => { onOpenTimeline: undefined, timelineId: note.timelineId, timelineType: undefined, - unifiedComponentsInTimelineDisabled, }); }); }); diff --git a/x-pack/plugins/security_solution/public/notes/components/open_timeline_button.tsx b/x-pack/plugins/security_solution/public/notes/components/open_timeline_button.tsx index b44ffd55a767a..91f3a722ebeeb 100644 --- a/x-pack/plugins/security_solution/public/notes/components/open_timeline_button.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/open_timeline_button.tsx @@ -8,7 +8,6 @@ import React, { memo, useCallback } from 'react'; import { EuiButtonIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { useQueryTimelineById } from '../../timelines/components/open_timeline/helpers'; import { OPEN_TIMELINE_BUTTON_TEST_ID } from './test_ids'; import type { Note } from '../../../common/api/timeline'; @@ -32,10 +31,6 @@ export interface OpenTimelineButtonIconProps { * Renders a button to open the timeline associated with a note */ export const OpenTimelineButtonIcon = memo(({ note, index }: OpenTimelineButtonIconProps) => { - const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled( - 'unifiedComponentsInTimelineDisabled' - ); - const queryTimelineById = useQueryTimelineById(); const openTimeline = useCallback( ({ timelineId }: { timelineId: string }) => @@ -44,9 +39,8 @@ export const OpenTimelineButtonIcon = memo(({ note, index }: OpenTimelineButtonI onOpenTimeline: undefined, timelineId, timelineType: undefined, - unifiedComponentsInTimelineDisabled, }), - [queryTimelineById, unifiedComponentsInTimelineDisabled] + [queryTimelineById] ); return ( diff --git a/x-pack/plugins/security_solution/public/overview/components/recent_timelines/index.tsx b/x-pack/plugins/security_solution/public/overview/components/recent_timelines/index.tsx index a167791a7b06c..97310f8a90f23 100644 --- a/x-pack/plugins/security_solution/public/overview/components/recent_timelines/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/recent_timelines/index.tsx @@ -8,7 +8,6 @@ import { EuiHorizontalRule, EuiText } from '@elastic/eui'; import React, { useCallback, useMemo, useEffect } from 'react'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { SortFieldTimelineEnum, TimelineTypeEnum } from '../../../../common/api/timeline'; import { useGetAllTimeline } from '../../../timelines/containers/all'; import { useQueryTimelineById } from '../../../timelines/components/open_timeline/helpers'; @@ -33,10 +32,6 @@ interface Props { const PAGE_SIZE = 3; const StatefulRecentTimelinesComponent: React.FC = ({ filterBy }) => { - const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled( - 'unifiedComponentsInTimelineDisabled' - ); - const { formatUrl } = useFormatUrl(SecurityPageName.timelines); const { navigateToApp } = useKibana().services.application; @@ -47,10 +42,9 @@ const StatefulRecentTimelinesComponent: React.FC = ({ filterBy }) => { queryTimelineById({ duplicate, timelineId, - unifiedComponentsInTimelineDisabled, }); }, - [queryTimelineById, unifiedComponentsInTimelineDisabled] + [queryTimelineById] ); const goToTimelines = useCallback( diff --git a/x-pack/plugins/security_solution/public/timelines/components/modal/actions/new_timeline_button.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/modal/actions/new_timeline_button.test.tsx index e1fdbe8817041..c26b34dffcaf4 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/modal/actions/new_timeline_button.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/modal/actions/new_timeline_button.test.tsx @@ -10,9 +10,7 @@ import React from 'react'; import { NewTimelineButton } from './new_timeline_button'; import { TimelineId } from '../../../../../common/types'; import { timelineActions } from '../../../store'; -import { defaultHeaders } from '../../timeline/body/column_headers/default_headers'; import { TestProviders } from '../../../../common/mock'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { RowRendererValues } from '../../../../../common/api/timeline'; import { defaultUdtHeaders } from '../../timeline/unified_components/default_headers'; @@ -76,26 +74,5 @@ describe('NewTimelineButton', () => { excludedRowRendererIds: RowRendererValues, }); }); - - // disable unified components in timeline - (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); - - getByTestId('timeline-modal-new-timeline-dropdown-button').click(); - getByTestId('timeline-modal-new-timeline').click(); - - spy.mockClear(); - - await waitFor(() => { - expect(spy).toHaveBeenCalledWith({ - columns: defaultHeaders, - dataViewId, - id: TimelineId.test, - indexNames: selectedPatterns, - show: true, - timelineType: 'default', - updated: undefined, - excludedRowRendererIds: [], - }); - }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/netflow/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/netflow/__snapshots__/index.test.tsx.snap index e881d9d5d1ce1..1267a66e0f6d7 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/netflow/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/netflow/__snapshots__/index.test.tsx.snap @@ -119,12 +119,13 @@ tr:hover .c3:focus::before { margin-right: 5px; } -.c7 { - margin-right: 3px; +.c15 { + position: relative; + top: 1px; } -.c8 { - margin: 0 5px; +.c14 { + margin-right: 5px; } .c17 { @@ -155,13 +156,12 @@ tr:hover .c3:focus::before { margin: 0 5px; } -.c15 { - position: relative; - top: 1px; +.c7 { + margin-right: 3px; } -.c14 { - margin-right: 5px; +.c8 { + margin: 0 5px; } .c12 { 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 a3428ae6f2e1d..5da977c30a410 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 @@ -36,12 +36,8 @@ import { } from './__mocks__'; import { resolveTimeline } from '../../containers/api'; import { defaultUdtHeaders } from '../timeline/unified_components/default_headers'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; -import type { ExperimentalFeatures } from '../../../../common'; -import { allowedExperimentalValues } from '../../../../common'; jest.mock('../../../common/hooks/use_experimental_features'); -const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock; jest.mock('react-redux', () => { const actual = jest.requireActual('react-redux'); @@ -146,14 +142,6 @@ describe('helpers', () => { beforeEach(() => { mockResults = cloneDeep(mockTimelineResults); - - (useIsExperimentalFeatureEnabledMock as jest.Mock).mockImplementation( - (featureFlag: keyof ExperimentalFeatures) => { - return featureFlag === 'unifiedComponentsInTimelineDisabled' - ? false - : allowedExperimentalValues[featureFlag]; - } - ); }); describe('#getPinnedEventCount', () => { @@ -500,8 +488,7 @@ describe('helpers', () => { const newTimeline = defaultTimelineToTimelineModel( timeline, false, - TimelineTypeEnum.template, - false + TimelineTypeEnum.template ); expect(newTimeline).toEqual({ ...defaultTimeline, @@ -523,12 +510,7 @@ describe('helpers', () => { timelineType: TimelineTypeEnum.default, }; - const newTimeline = defaultTimelineToTimelineModel( - timeline, - false, - TimelineTypeEnum.default, - false - ); + const newTimeline = defaultTimelineToTimelineModel(timeline, false, TimelineTypeEnum.default); expect(newTimeline).toEqual({ ...defaultTimeline, dateRange: { end: '2020-07-08T08:20:18.966Z', start: '2020-07-07T08:20:18.966Z' }, @@ -538,7 +520,7 @@ describe('helpers', () => { }); }); - test('should produce correct model if unifiedComponentsInTimelineDisabled is false', () => { + test('should produce correct model', () => { const timeline = { savedObjectId: 'savedObject-1', title: 'Awesome Timeline', @@ -547,12 +529,7 @@ describe('helpers', () => { timelineType: TimelineTypeEnum.default, }; - const newTimeline = defaultTimelineToTimelineModel( - timeline, - false, - TimelineTypeEnum.default, - false - ); + const newTimeline = defaultTimelineToTimelineModel(timeline, false, TimelineTypeEnum.default); expect(newTimeline).toEqual({ ...defaultTimeline, dateRange: { end: '2020-07-08T08:20:18.966Z', start: '2020-07-07T08:20:18.966Z' }, @@ -564,7 +541,7 @@ describe('helpers', () => { }); }); - test('should produce correct model if unifiedComponentsInTimelineDisabled == false and custom set of columns is passed', () => { + test('should produce correct model if custom set of columns is passed', () => { const customColumns = defaultUdtHeaders.slice(0, 2); const timeline = { savedObjectId: 'savedObject-1', @@ -575,12 +552,7 @@ describe('helpers', () => { columns: customColumns as ColumnHeaderResult[], }; - const newTimeline = defaultTimelineToTimelineModel( - timeline, - false, - TimelineTypeEnum.default, - false - ); + const newTimeline = defaultTimelineToTimelineModel(timeline, false, TimelineTypeEnum.default); expect(newTimeline).toEqual({ ...defaultTimeline, dateRange: { end: '2020-07-08T08:20:18.966Z', start: '2020-07-07T08:20:18.966Z' }, @@ -592,7 +564,7 @@ describe('helpers', () => { }); }); - test('should produce correct model if unifiedComponentsInTimelineDisabled == false and custom set of excludedRowRendererIds is passed', () => { + test('should produce correct model if custom set of excludedRowRendererIds is passed', () => { const excludedRowRendererIds: RowRendererId[] = ['zeek']; const timeline = { savedObjectId: 'savedObject-1', @@ -603,12 +575,7 @@ describe('helpers', () => { excludedRowRendererIds, }; - const newTimeline = defaultTimelineToTimelineModel( - timeline, - false, - TimelineTypeEnum.default, - false - ); + const newTimeline = defaultTimelineToTimelineModel(timeline, false, TimelineTypeEnum.default); expect(newTimeline).toEqual({ ...defaultTimeline, dateRange: { end: '2020-07-08T08:20:18.966Z', start: '2020-07-07T08:20:18.966Z' }, @@ -649,7 +616,7 @@ describe('helpers', () => { }); }); - describe('open a timeline', () => { + describe('open a timeline 1', () => { const selectedTimeline = { ...mockSelectedTimeline, }; @@ -715,7 +682,8 @@ describe('helpers', () => { describe('update a timeline', () => { const selectedTimeline = { ...mockSelectedTimeline }; - + const untitledTimeline = { ...mockSelectedTimeline, title: '' }; + const onOpenTimeline = jest.fn(); const args: QueryTimelineById = { duplicate: false, graphEventId: '', @@ -724,146 +692,76 @@ describe('helpers', () => { openTimeline: true, }; - beforeAll(async () => { + beforeEach(async () => { (resolveTimeline as jest.Mock).mockResolvedValue(selectedTimeline); - renderHook(async () => { - const queryTimelineById = useQueryTimelineById(); - await queryTimelineById(args); - }); }); - afterAll(() => { + afterEach(() => { jest.clearAllMocks(); }); - test('dispatch updateIsLoading to true', () => { - expect(dispatchUpdateIsLoading).toBeCalledWith({ - id: TimelineId.active, - isLoading: true, - }); - }); - - test('get timeline by Id', () => { - expect(resolveTimeline).toHaveBeenCalled(); - }); - - test('should not override daterange if TimelineStatus is active', () => { - const { timeline } = formatTimelineResponseToModel( - omitTypenameInTimeline(getOr({}, 'data.timeline', selectedTimeline)), - args.duplicate, - args.timelineType - ); - - expect(mockUpdateTimeline).toBeCalledWith({ - timeline: { - ...timeline, - graphEventId: '', - show: true, - dateRange: { - start: '2020-07-07T08:20:18.966Z', - end: '2020-07-08T08:20:18.966Z', - }, - }, - preventSettingQuery: true, - duplicate: false, - from: '2020-07-07T08:20:18.966Z', - to: '2020-07-08T08:20:18.966Z', - notes: [], - id: TimelineId.active, - resolveTimelineConfig: { - outcome: 'exactMatch', - alias_target_id: undefined, - }, - }); - }); - - test('dispatch updateIsLoading to false', () => { - expect(dispatchUpdateIsLoading).toBeCalledWith({ - id: TimelineId.active, - isLoading: false, - }); - }); - }); - - describe('open an immutable template', () => { - const template = { ...mockSelectedTemplate }; - const onOpenTimeline = jest.fn(); - const args = { - duplicate: false, - graphEventId: '', - timelineId: '', - timelineType: TimelineTypeEnum.template, - onOpenTimeline, - openTimeline: true, - }; - - beforeAll(async () => { - (resolveTimeline as jest.Mock).mockResolvedValue(template); + test('should get timeline by Id with correct statuses', async () => { renderHook(async () => { const queryTimelineById = useQueryTimelineById(); - queryTimelineById(args); + await queryTimelineById(args); }); - }); - afterAll(() => { - (resolveTimeline as jest.Mock).mockReset(); - jest.clearAllMocks(); - }); - - test('dispatch updateIsLoading to true', () => { expect(dispatchUpdateIsLoading).toBeCalledWith({ id: TimelineId.active, isLoading: true, }); - }); - test('get timeline by Id', () => { - expect(resolveTimeline).toHaveBeenCalled(); - }); - - test('override daterange if TimelineStatus is immutable', () => { + // expect(resolveTimeline).toHaveBeenCalled(); const { timeline } = formatTimelineResponseToModel( - omitTypenameInTimeline(getOr({}, 'data.timeline', template)), + omitTypenameInTimeline(getOr({}, 'data.timeline', selectedTimeline)), args.duplicate, args.timelineType ); - expect(onOpenTimeline).toBeCalledWith({ - ...timeline, - dateRange: { - end: '2020-10-28T11:37:31.655Z', - start: '2020-10-27T11:37:31.655Z', - }, + + await waitFor(() => { + expect(mockUpdateTimeline).toHaveBeenCalledWith({ + timeline: { + ...timeline, + graphEventId: '', + show: true, + dateRange: { + start: '2020-07-07T08:20:18.966Z', + end: '2020-07-08T08:20:18.966Z', + }, + }, + preventSettingQuery: true, + duplicate: false, + from: '2020-07-07T08:20:18.966Z', + to: '2020-07-08T08:20:18.966Z', + notes: [], + id: TimelineId.active, + resolveTimelineConfig: { + outcome: 'exactMatch', + alias_target_id: undefined, + }, + }); }); - }); - test('dispatch updateIsLoading to false', () => { expect(dispatchUpdateIsLoading).toBeCalledWith({ id: TimelineId.active, isLoading: false, }); }); - }); - describe('open a timeline when unifiedComponentsInTimelineDisabled is false', () => { - const untitledTimeline = { ...mockSelectedTimeline, title: '' }; - const onOpenTimeline = jest.fn(); - afterEach(() => { - jest.clearAllMocks(); - }); - it('should update timeline correctly when timeline is untitled', async () => { - const args: QueryTimelineById = { + test('should update timeline correctly when timeline is untitled', async () => { + (resolveTimeline as jest.Mock).mockResolvedValue(selectedTimeline); + const newArgs: QueryTimelineById = { duplicate: false, graphEventId: '', timelineId: undefined, timelineType: TimelineTypeEnum.default, onOpenTimeline, openTimeline: true, - unifiedComponentsInTimelineDisabled: false, }; (resolveTimeline as jest.Mock).mockResolvedValue(untitledTimeline); renderHook(async () => { const queryTimelineById = useQueryTimelineById(); - queryTimelineById(args); + queryTimelineById(newArgs); }); expect(dispatchUpdateIsLoading).toHaveBeenCalledWith({ @@ -886,17 +784,7 @@ describe('helpers', () => { }); }); - it('should update timeline correctly when timeline is already saved and onOpenTimeline is not provided', async () => { - const args: QueryTimelineById = { - duplicate: false, - graphEventId: '', - timelineId: TimelineId.active, - timelineType: TimelineTypeEnum.default, - onOpenTimeline: undefined, - openTimeline: true, - unifiedComponentsInTimelineDisabled: false, - }; - + test('should update timeline correctly when timeline is already saved and onOpenTimeline is not provided', async () => { (resolveTimeline as jest.Mock).mockResolvedValue(mockSelectedTimeline); renderHook(async () => { const queryTimelineById = useQueryTimelineById(); @@ -925,17 +813,7 @@ describe('helpers', () => { }); }); - it('should update timeline correctly when timeline is already saved and onOpenTimeline IS provided', async () => { - const args: QueryTimelineById = { - duplicate: false, - graphEventId: '', - timelineId: TimelineId.active, - timelineType: TimelineTypeEnum.default, - onOpenTimeline, - openTimeline: true, - unifiedComponentsInTimelineDisabled: false, - }; - + test('should update timeline correctly when timeline is already saved and onOpenTimeline IS provided', async () => { (resolveTimeline as jest.Mock).mockResolvedValue(mockSelectedTimeline); renderHook(async () => { const queryTimelineById = useQueryTimelineById(); @@ -956,16 +834,75 @@ describe('helpers', () => { }); }); }); + + describe('open an immutable template', () => { + const template = { ...mockSelectedTemplate }; + const onOpenTimeline = jest.fn(); + const args = { + duplicate: false, + graphEventId: '', + timelineId: '', + timelineType: TimelineTypeEnum.template, + onOpenTimeline, + openTimeline: true, + }; + + beforeAll(async () => { + (resolveTimeline as jest.Mock).mockResolvedValue(template); + renderHook(async () => { + const queryTimelineById = useQueryTimelineById(); + queryTimelineById(args); + }); + }); + + afterAll(() => { + (resolveTimeline as jest.Mock).mockReset(); + jest.clearAllMocks(); + }); + + test('dispatch updateIsLoading to true', () => { + expect(dispatchUpdateIsLoading).toBeCalledWith({ + id: TimelineId.active, + isLoading: true, + }); + }); + + test('get timeline by Id', () => { + expect(resolveTimeline).toHaveBeenCalled(); + }); + + test('override daterange if TimelineStatus is immutable', () => { + const { timeline } = formatTimelineResponseToModel( + omitTypenameInTimeline(getOr({}, 'data.timeline', template)), + args.duplicate, + args.timelineType + ); + expect(onOpenTimeline).toBeCalledWith({ + ...timeline, + dateRange: { + end: '2020-10-28T11:37:31.655Z', + start: '2020-10-27T11:37:31.655Z', + }, + }); + }); + + test('dispatch updateIsLoading to false', () => { + expect(dispatchUpdateIsLoading).toBeCalledWith({ + id: TimelineId.active, + isLoading: false, + }); + }); + }); }); describe('omitTypenameInTimeline', () => { - test('it does not modify the passed in timeline if no __typename exists', () => { + test('should not modify the passed in timeline if no __typename exists', () => { const result = omitTypenameInTimeline(mockGetOneTimelineResult); expect(result).toEqual(mockGetOneTimelineResult); }); - test('it returns timeline with __typename removed when it exists', () => { + test('should return timeline with __typename removed when it exists', () => { const mockTimeline = { ...mockGetOneTimelineResult, __typename: 'something, something', diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts index 000a7b226561e..b3f84a82d4ed0 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts @@ -35,10 +35,7 @@ import { useUpdateTimeline } from './use_update_timeline'; import type { TimelineModel } from '../../store/model'; import { timelineDefaults } from '../../store/defaults'; -import { - defaultColumnHeaderType, - defaultHeaders, -} from '../timeline/body/column_headers/default_headers'; +import { defaultColumnHeaderType } from '../timeline/body/column_headers/default_headers'; import type { OpenTimelineResult, TimelineErrorCallback } from './types'; import { IS_OPERATOR } from '../timeline/data_providers/data_provider'; @@ -238,13 +235,10 @@ export const getTimelineStatus = ( export const defaultTimelineToTimelineModel = ( timeline: TimelineResponse, duplicate: boolean, - timelineType?: TimelineType, - unifiedComponentsInTimelineDisabled?: boolean + timelineType?: TimelineType ): TimelineModel => { const isTemplate = timeline.timelineType === TimelineTypeEnum.template; - const defaultHeadersValue = !unifiedComponentsInTimelineDisabled - ? defaultUdtHeaders - : defaultHeaders; + const defaultHeadersValue = defaultUdtHeaders; const timelineEntries = { ...timeline, @@ -294,18 +288,12 @@ export const defaultTimelineToTimelineModel = ( export const formatTimelineResponseToModel = ( timelineToOpen: TimelineResponse, duplicate: boolean = false, - timelineType?: TimelineType, - unifiedComponentsInTimelineDisabled?: boolean + timelineType?: TimelineType ): { notes: Note[] | null | undefined; timeline: TimelineModel } => { const { notes, ...timelineModel } = timelineToOpen; return { notes, - timeline: defaultTimelineToTimelineModel( - timelineModel, - duplicate, - timelineType, - unifiedComponentsInTimelineDisabled - ), + timeline: defaultTimelineToTimelineModel(timelineModel, duplicate, timelineType), }; }; @@ -319,11 +307,6 @@ export interface QueryTimelineById { onOpenTimeline?: (timeline: TimelineModel) => void; openTimeline?: boolean; savedSearchId?: string; - /* - * Below feature flag will be removed once - * unified components have been fully migrated - * */ - unifiedComponentsInTimelineDisabled?: boolean; } export const useQueryTimelineById = () => { @@ -347,7 +330,6 @@ export const useQueryTimelineById = () => { onOpenTimeline, openTimeline = true, savedSearchId, - unifiedComponentsInTimelineDisabled = false, }: QueryTimelineById) => { updateIsLoading({ id: TimelineId.active, isLoading: true }); if (timelineId == null) { @@ -359,14 +341,14 @@ export const useQueryTimelineById = () => { to: DEFAULT_TO_MOMENT.toISOString(), timeline: { ...timelineDefaults, - columns: !unifiedComponentsInTimelineDisabled ? defaultUdtHeaders : defaultHeaders, + columns: defaultUdtHeaders, id: TimelineId.active, activeTab: activeTimelineTab, show: openTimeline, initialized: true, savedSearchId: savedSearchId ?? null, excludedRowRendererIds: - !unifiedComponentsInTimelineDisabled && timelineType !== TimelineTypeEnum.template + timelineType !== TimelineTypeEnum.template ? timelineDefaults.excludedRowRendererIds : [], }, @@ -384,8 +366,7 @@ export const useQueryTimelineById = () => { const { timeline, notes } = formatTimelineResponseToModel( timelineToOpen, duplicate, - timelineType, - unifiedComponentsInTimelineDisabled + timelineType ); if (onOpenTimeline != null) { diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.tsx index cdb61ecf61f6e..6afd900185af7 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.tsx @@ -9,7 +9,6 @@ import React, { useEffect, useState, useCallback, useMemo } from 'react'; import { useDispatch } from 'react-redux'; import { encode } from '@kbn/rison'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { RULE_FROM_EQL_URL_PARAM, RULE_FROM_TIMELINE_URL_PARAM, @@ -25,8 +24,6 @@ import { createTimeline as dispatchCreateNewTimeline } from '../../store/actions import { useGetAllTimeline } from '../../containers/all'; -import { defaultHeaders } from '../timeline/body/column_headers/default_headers'; - import { OpenTimeline } from './open_timeline'; import { OPEN_TIMELINE_CLASS_NAME, useQueryTimelineById } from './helpers'; import { OpenTimelineModalBody } from './open_timeline_modal/open_timeline_modal_body'; @@ -160,9 +157,6 @@ export const StatefulOpenTimelineComponent = React.memo( ); const { dataViewId, selectedPatterns } = useSourcererDataView(SourcererScopeName.timeline); - const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled( - 'unifiedComponentsInTimelineDisabled' - ); const { customTemplateTimelineCount, @@ -251,13 +245,11 @@ export const StatefulOpenTimelineComponent = React.memo( dispatch( dispatchCreateNewTimeline({ id: TimelineId.active, - columns: !unifiedComponentsInTimelineDisabled ? defaultUdtHeaders : defaultHeaders, + columns: defaultUdtHeaders, dataViewId, indexNames: selectedPatterns, show: false, - excludedRowRendererIds: !unifiedComponentsInTimelineDisabled - ? timelineDefaults.excludedRowRendererIds - : [], + excludedRowRendererIds: timelineDefaults.excludedRowRendererIds, }) ); } @@ -265,15 +257,7 @@ export const StatefulOpenTimelineComponent = React.memo( await deleteTimelinesByIds(timelineIds, searchIds); refetch(); }, - [ - startTransaction, - timelineSavedObjectId, - refetch, - dispatch, - dataViewId, - selectedPatterns, - unifiedComponentsInTimelineDisabled, - ] + [startTransaction, timelineSavedObjectId, refetch, dispatch, dataViewId, selectedPatterns] ); const onDeleteOneTimeline: OnDeleteOneTimeline = useCallback( @@ -374,7 +358,6 @@ export const StatefulOpenTimelineComponent = React.memo( onOpenTimeline, timelineId, timelineType: timelineTypeToOpen, - unifiedComponentsInTimelineDisabled, }); }, // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx index f502c1b8884aa..991355b1177bb 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx @@ -12,11 +12,9 @@ import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; import { isTab } from '@kbn/timelines-plugin/public'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { useUserPrivileges } from '../../../common/components/user_privileges'; import { timelineActions, timelineSelectors } from '../../store'; import { timelineDefaults } from '../../store/defaults'; -import { defaultHeaders } from './body/column_headers/default_headers'; import type { CellValueElementProps } from './cell_rendering'; import { SourcererScopeName } from '../../../sourcerer/store/model'; import { TimelineModalHeader } from '../modal/header'; @@ -75,10 +73,6 @@ const StatefulTimelineComponent: React.FC = ({ }) => { const dispatch = useDispatch(); - const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled( - 'unifiedComponentsInTimelineDisabled' - ); - const containerElement = useRef(null); const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); const selectedPatternsSourcerer = useSelector((state: State) => { @@ -129,13 +123,11 @@ const StatefulTimelineComponent: React.FC = ({ dispatch( timelineActions.createTimeline({ id: timelineId, - columns: !unifiedComponentsInTimelineDisabled ? defaultUdtHeaders : defaultHeaders, + columns: defaultUdtHeaders, dataViewId: selectedDataViewIdSourcerer, indexNames: selectedPatternsSourcerer, show: false, - excludedRowRendererIds: !unifiedComponentsInTimelineDisabled - ? timelineDefaults.excludedRowRendererIds - : [], + excludedRowRendererIds: timelineDefaults.excludedRowRendererIds, }) ); } diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/__snapshots__/index.test.tsx.snap deleted file mode 100644 index e238e24ebce7a..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,1165 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Timeline rendering renders correctly against snapshot 1`] = ` - -`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.test.tsx index 034f812373ec2..7c8949c1b6121 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.test.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; import useResizeObserver from 'use-resize-observer/polyfilled'; import type { Dispatch } from 'redux'; @@ -17,7 +16,6 @@ import { TestProviders } from '../../../../../common/mock/test_providers'; import type { Props as EqlTabContentComponentProps } from '.'; import { EqlTabContentComponent } from '.'; -import { useMountAppended } from '../../../../../common/utils/use_mount_appended'; import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; import { useTimelineEvents } from '../../../../containers'; import { useTimelineEventsDetails } from '../../../../containers/details'; @@ -26,6 +24,7 @@ import { mockSourcererScope } from '../../../../../sourcerer/containers/mocks'; import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import type { ExperimentalFeatures } from '../../../../../../common'; import { allowedExperimentalValues } from '../../../../../../common'; +import { render, screen } from '@testing-library/react'; jest.mock('../../../../containers', () => ({ useTimelineEvents: jest.fn(), @@ -54,18 +53,25 @@ mockUseResizeObserver.mockImplementation(() => ({})); jest.mock('../../../../../common/lib/kibana'); -describe('Timeline', () => { +describe('EQL Tab', () => { let props = {} as EqlTabContentComponentProps; const startDate = '2018-03-23T18:49:23.132Z'; const endDate = '2018-03-24T03:33:52.253Z'; - const mount = useMountAppended(); + beforeAll(() => { + // https://github.com/atlassian/react-beautiful-dnd/blob/4721a518356f72f1dac45b5fd4ee9d466aa2996b/docs/guides/setup-problem-detection-and-error-recovery.md#disable-logging + Object.defineProperty(window, '__@hello-pangea/dnd-disable-dev-warnings', { + get() { + return true; + }, + }); + }); beforeEach(() => { (useTimelineEvents as jest.Mock).mockReturnValue([ false, { - events: mockTimelineData, + events: mockTimelineData.slice(0, 1), pageInfo: { activePage: 0, totalPages: 10, @@ -78,9 +84,6 @@ describe('Timeline', () => { (useIsExperimentalFeatureEnabledMock as jest.Mock).mockImplementation( (feature: keyof ExperimentalFeatures) => { - if (feature === 'unifiedComponentsInTimelineDisabled') { - return true; - } return allowedExperimentalValues[feature]; } ); @@ -105,133 +108,45 @@ describe('Timeline', () => { }); describe('rendering', () => { - test('renders correctly against snapshot', () => { - const wrapper = shallow( - - - - ); - - expect(wrapper.find('EqlTabContentComponent')).toMatchSnapshot(); - }); - - test('it renders the timeline header', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="timelineHeader"]').exists()).toEqual(true); - }); - - test('it renders the timeline table', () => { - const wrapper = mount( + test('should render the timeline table', async () => { + render( ); - expect(wrapper.find(`[data-test-subj="${TimelineTabs.eql}-events-table"]`).exists()).toEqual( - true - ); - }); - - test('it renders the timeline column headers', () => { - const wrapper = mount( - - - - ); - - expect( - wrapper - .find( - `[data-test-subj="${TimelineTabs.eql}-events-table"] [data-test-subj="column-headers"]` - ) - .exists() - ).toEqual(true); - }); - - test('it does NOT renders the timeline global sorting icon in headers', () => { - const wrapper = mount( - - - - ); - expect( - wrapper - .find( - `[data-test-subj="${TimelineTabs.eql}-events-table"] [data-test-subj="column-headers"] [data-test-subj="timeline-sorting-fields"]` - ) - .exists() - ).toEqual(false); + expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); }); - test('it does render the timeline table when the source is loading with no events', () => { - (useSourcererDataView as jest.Mock).mockReturnValue({ - browserFields: {}, - loading: true, - indexPattern: {}, - selectedPatterns: [], - missingPatterns: [], - }); - const wrapper = mount( + test('it renders the timeline column headers', async () => { + render( ); - expect(wrapper.find(`[data-test-subj="${TimelineTabs.eql}-events-table"]`).exists()).toEqual( - true - ); - expect(wrapper.find('[data-test-subj="events"]').exists()).toEqual(false); - }); - - test('it does NOT render the timeline table when start is empty', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find(`[data-test-subj="${TimelineTabs.eql}-events-table"]`).exists()).toEqual( - true - ); - expect(wrapper.find('[data-test-subj="events"]').exists()).toEqual(false); + expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); }); - test('it does NOT render the timeline table when end is empty', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find(`[data-test-subj="${TimelineTabs.eql}-events-table"]`).exists()).toEqual( - true - ); - expect(wrapper.find('[data-test-subj="events"]').exists()).toEqual(false); - }); + test('should render correct placeholder when there are not results', async () => { + (useTimelineEvents as jest.Mock).mockReturnValue([ + false, + { + events: [], + pageInfo: { + activePage: 0, + totalPages: 10, + }, + }, + ]); - it('it does NOT render the timeline footer when query is empty', () => { - const wrapper = mount( + render( ); - expect(wrapper.find('[data-test-subj="timeline-footer"]').exists()).toEqual(false); - }); - - it('it shows the timeline footer when query is non-empty', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="timeline-footer"]').exists()).toEqual(true); + expect(await screen.findByText('No results found')).toBeVisible(); }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx index e2881c8c24458..e41d9017d49be 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx @@ -17,23 +17,17 @@ import type { EuiDataGridControlColumn } from '@elastic/eui'; import { DataLoadingState } from '@kbn/unified-data-table'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; +import { InputsModelId } from '../../../../../common/store/inputs/constants'; import { useKibana } from '../../../../../common/lib/kibana'; import { DocumentDetailsLeftPanelKey, DocumentDetailsRightPanelKey, } from '../../../../../flyout/document_details/shared/constants/panel_keys'; -import { InputsModelId } from '../../../../../common/store/inputs/constants'; -import type { ControlColumnProps } from '../../../../../../common/types'; import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector'; import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { timelineActions, timelineSelectors } from '../../../../store'; import { useTimelineEvents } from '../../../../containers'; -import { StatefulBody } from '../../body'; -import { Footer, footerHeight } from '../../footer'; -import { calculateTotalPages } from '../../helpers'; -import { TimelineRefetch } from '../../refetch_timeline'; import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; -import { EventDetailsWidthProvider } from '../../../../../common/components/events_viewer/event_details_width_context'; import type { inputsModel, State } from '../../../../../common/store'; import { inputsSelectors } from '../../../../../common/store'; import { SourcererScopeName } from '../../../../../sourcerer/store/model'; @@ -42,19 +36,8 @@ import { useSourcererDataView } from '../../../../../sourcerer/containers'; import { useEqlEventsCountPortal } from '../../../../../common/hooks/use_timeline_events_count'; import type { TimelineModel } from '../../../../store/model'; import { useTimelineFullScreen } from '../../../../../common/containers/use_full_screen'; -import { - EventsCountBadge, - FullWidthFlexGroup, - ScrollableFlexItem, - StyledEuiFlyoutBody, - StyledEuiFlyoutFooter, -} from '../shared/layout'; -import { - TIMELINE_EMPTY_EVENTS, - isTimerangeSame, - timelineEmptyTrailingControlColumns, - TIMELINE_NO_SORTING, -} from '../shared/utils'; +import { EventsCountBadge, FullWidthFlexGroup } from '../shared/layout'; +import { isTimerangeSame, TIMELINE_NO_SORTING } from '../shared/utils'; import type { TimelineTabCommonProps } from '../shared/types'; import { UnifiedTimelineBody } from '../../body/unified_timeline_body'; import { EqlTabHeader } from './header'; @@ -63,6 +46,7 @@ import { useTimelineControlColumn } from '../shared/use_timeline_control_columns import { LeftPanelNotesTab } from '../../../../../flyout/document_details/left'; import { useNotesInFlyout } from '../../properties/use_notes_in_flyout'; import { NotesFlyout } from '../../properties/notes_flyout'; +import { TimelineRefetch } from '../../refetch_timeline'; export type Props = TimelineTabCommonProps & PropsFromRedux; @@ -72,10 +56,8 @@ export const EqlTabContentComponent: React.FC = ({ end, eqlOptions, timelineId, - isLive, itemsPerPage, itemsPerPageOptions, - renderCellValue, rowRenderers, start, timerangeKind, @@ -88,7 +70,6 @@ export const EqlTabContentComponent: React.FC = ({ const { portalNode: eqlEventsCountPortalNode } = useEqlEventsCountPortal(); const { setTimelineFullScreen, timelineFullScreen } = useTimelineFullScreen(); const { - browserFields, dataViewId, loading: loadingSourcerer, selectedPatterns, @@ -96,10 +77,6 @@ export const EqlTabContentComponent: React.FC = ({ } = useSourcererDataView(SourcererScopeName.timeline); const { augmentedColumnHeaders, timelineQueryFieldsFromColumns } = useTimelineColumns(columns); - const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled( - 'unifiedComponentsInTimelineDisabled' - ); - const getManageTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); const currentTimeline = useDeepEqualSelector((state) => @@ -132,7 +109,7 @@ export const EqlTabContentComponent: React.FC = ({ id: timelineId, indexNames: selectedPatterns, language: 'eql', - limit: !unifiedComponentsInTimelineDisabled ? sampleSize : itemsPerPage, + limit: sampleSize, runtimeMappings: sourcererDataView?.runtimeFieldMap as RunTimeMappings, skip: !canQueryTimeline(), startDate: start, @@ -267,103 +244,42 @@ export const EqlTabContentComponent: React.FC = ({ return ( <> - {!unifiedComponentsInTimelineDisabled ? ( - <> - - {totalCount >= 0 ? ( - {totalCount} - ) : null} - - {NotesFlyoutMemo} - - - - - ) : ( - <> - - {totalCount >= 0 ? {totalCount} : null} - - {NotesFlyoutMemo} - - - {unifiedHeader} - - - - - - - - {!isBlankTimeline && ( -