diff --git a/x-pack/plugins/siem/public/components/open_timeline/index.tsx b/x-pack/plugins/siem/public/components/open_timeline/index.tsx index d7b1fe7ae5df11..24d63324c11f57 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/index.tsx +++ b/x-pack/plugins/siem/public/components/open_timeline/index.tsx @@ -106,7 +106,20 @@ export const StatefulOpenTimelineComponent = React.memo( const [sortField, setSortField] = useState(DEFAULT_SORT_FIELD); const { timelineTypes, timelineTabs, timelineFilters } = useTimelineTypes(); - const { fetchAllTimeline, timelines, loading, totalCount, refetch } = useGetAllTimeline(); + const { fetchAllTimeline, timelines, loading, totalCount } = useGetAllTimeline(); + + const refetch = useCallback(() => { + fetchAllTimeline({ + pageInfo: { + pageIndex: pageIndex + 1, + pageSize, + }, + search, + sort: { sortField: sortField as SortFieldTimeline, sortOrder: sortDirection as Direction }, + onlyUserFavorite: onlyFavorites, + timelineTypes, + }); + }, [pageIndex, pageSize, search, sortField, sortDirection, timelineTypes, onlyFavorites]); /** Invoked when the user presses enters to submit the text in the search input */ const onQueryChange: OnQueryChange = useCallback((query: EuiSearchBarQuery) => { @@ -139,8 +152,6 @@ export const StatefulOpenTimelineComponent = React.memo( const deleteTimelines: DeleteTimelines = useCallback( async (timelineIds: string[]) => { - const existingTimelines = [...timelines]; - const existingTimelinesCount = totalCount; if (timelineIds.includes(timeline.savedObjectId || '')) { createNewTimeline({ id: 'timeline-1', columns: defaultHeaders, show: false }); } @@ -153,9 +164,9 @@ export const StatefulOpenTimelineComponent = React.memo( fetchPolicy: 'no-cache', variables: { id: timelineIds }, }); - refetch(existingTimelines, existingTimelinesCount); + refetch(); }, - [apolloClient, createNewTimeline, refetch, timeline, timelines, totalCount] + [apolloClient, createNewTimeline, refetch, timeline] ); const onDeleteOneTimeline: OnDeleteOneTimeline = useCallback( @@ -235,17 +246,8 @@ export const StatefulOpenTimelineComponent = React.memo( }, []); useEffect(() => { - fetchAllTimeline({ - pageInfo: { - pageIndex: pageIndex + 1, - pageSize, - }, - search, - sort: { sortField: sortField as SortFieldTimeline, sortOrder: sortDirection as Direction }, - onlyUserFavorite: onlyFavorites, - timelineTypes, - }); - }, [pageIndex, pageSize, search, sortField, sortDirection, timelineTypes, onlyFavorites]); + refetch(); + }, [refetch]); return !isModal ? ( TimelineTab[] = ( + const getFilterOrTabs: (timelineTabsStyle: TimelineTabsStyle) => TimelineTab[] = ( timelineTabsStyle: TimelineTabsStyle ) => [ { @@ -65,7 +65,7 @@ export const useTimelineTypes = (): { return ( <> - {getTabs(TimelineTabsStyle.tab).map((tab: TimelineTab) => ( + {getFilterOrTabs(TimelineTabsStyle.tab).map((tab: TimelineTab) => ( ); - }, [getTabs, tabName]); + }, [tabName]); const timelineFilters = useMemo(() => { return ( <> - {getTabs(TimelineTabsStyle.tab).map((tab: TimelineTab) => ( + {getFilterOrTabs(TimelineTabsStyle.tab).map((tab: TimelineTab) => ( ); - }, [getTabs, timelineTypes]); + }, [timelineTypes]); return { timelineTypes, diff --git a/x-pack/plugins/siem/public/containers/timeline/all/index.tsx b/x-pack/plugins/siem/public/containers/timeline/all/index.tsx index 85f891438426af..273b267405ae10 100644 --- a/x-pack/plugins/siem/public/containers/timeline/all/index.tsx +++ b/x-pack/plugins/siem/public/containers/timeline/all/index.tsx @@ -35,7 +35,6 @@ export interface AllTimelinesArgs { timelines: OpenTimelineResult[]; loading: boolean; totalCount: number; - refetch: (existingTimelines?: OpenTimelineResult[], existingTotalCount?: number) => void; } export interface AllTimelinesVariables { @@ -86,12 +85,10 @@ export const getAllTimeline = memoizeOne( export const useGetAllTimeline = (): AllTimelinesArgs => { const dispatch = useDispatch(); const apolloClient = useApolloClient(); - const refetch = useRef(); const [, dispatchToaster] = useStateToaster(); const [allTimelines, setAllTimelines] = useState({ fetchAllTimeline: noop, loading: false, - refetch: refetch.current ?? noop, totalCount: 0, timelines: [], }); @@ -101,16 +98,11 @@ export const useGetAllTimeline = (): AllTimelinesArgs => { let didCancel = false; const abortCtrl = new AbortController(); - const fetchData = async ( - existingTimelines?: OpenTimelineResult[], - existingTotalCount?: number - ) => { + const fetchData = async () => { try { if (apolloClient != null) { setAllTimelines({ ...allTimelines, - timelines: existingTimelines ?? allTimelines.timelines, - totalCount: existingTotalCount ?? allTimelines.totalCount, loading: true, }); @@ -142,15 +134,13 @@ export const useGetAllTimeline = (): AllTimelinesArgs => { inputId: 'global', id: ALL_TIMELINE_QUERY_ID, loading: false, - refetch: refetch?.current?.bind(null, timelines, totalCount) ?? noop, + refetch: fetchData, inspect: null, }) ); - setAllTimelines({ fetchAllTimeline, loading: false, - refetch: refetch?.current?.bind(null, timelines, totalCount) ?? noop, totalCount, timelines: getAllTimeline(JSON.stringify(variables), timelines as TimelineResult[]), }); @@ -166,21 +156,19 @@ export const useGetAllTimeline = (): AllTimelinesArgs => { setAllTimelines({ fetchAllTimeline, loading: false, - refetch: noop, totalCount: 0, timelines: [], }); } } }; - refetch.current = fetchData; fetchData(); return () => { didCancel = true; abortCtrl.abort(); }; }, - [apolloClient, allTimelines, refetch] + [apolloClient, allTimelines] ); useEffect(() => { @@ -192,6 +180,5 @@ export const useGetAllTimeline = (): AllTimelinesArgs => { return { ...allTimelines, fetchAllTimeline, - refetch: refetch.current ?? noop, }; }; diff --git a/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts b/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts index 6de10bffb1325c..07bb3257e2ab8a 100644 --- a/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts +++ b/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts @@ -44,5 +44,7 @@ export const pickSavedTimeline = ( savedTimeline.templateTimelineVersion = null; } + console.log('pickSavedTimeline', JSON.stringify(savedTimeline)); + return savedTimeline; }; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts index 99621f1391acb9..6fe6d396ed0b06 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts @@ -119,35 +119,36 @@ export const importTimelinesRoute = ( return null; } const { - savedObjectId, + savedObjectId = null, pinnedEventIds, globalNotes, eventNotes, templateTimelineId, templateTimelineVersion, timelineType, + version = null, } = parsedTimeline; const parsedTimelineObject = omit( timelineSavedObjectOmittedFields, parsedTimeline ); + console.log('parsedTimeline', JSON.stringify(parsedTimeline)); + console.log('parsedTimelineObject', JSON.stringify(parsedTimelineObject)); let newTimeline = null; try { const templateTimeline = templateTimelineId != null ? await getTemplateTimeline(frameworkRequest, templateTimelineId) : null; + const timeline = - templateTimeline?.savedObjectId != null || savedObjectId != null - ? await getTimeline( - frameworkRequest, - templateTimeline?.savedObjectId ?? savedObjectId - ) - : null; + savedObjectId != null && + (await getTimeline(frameworkRequest, savedObjectId)); const isHandlingTemplateTimeline = timelineType === TimelineType.template; + if ( (timeline == null && !isHandlingTemplateTimeline) || - (templateTimeline == null && isHandlingTemplateTimeline) + (timeline == null && templateTimeline == null && isHandlingTemplateTimeline) ) { // create timeline / template timeline newTimeline = await createTimelines( @@ -165,6 +166,7 @@ export const importTimelinesRoute = ( status_code: 200, }); } else if ( + timeline && timeline != null && templateTimeline != null && isHandlingTemplateTimeline @@ -172,8 +174,8 @@ export const importTimelinesRoute = ( // update template timeline const errorObj = checkIsFailureCases( isHandlingTemplateTimeline, - timeline.version, - templateTimeline.templateTimelineVersion ?? null, + version, + templateTimelineVersion ?? null, timeline, templateTimeline ); @@ -198,16 +200,16 @@ export const importTimelinesRoute = ( } else { resolve( createBulkErrorObject({ - id: savedObjectId, + id: savedObjectId ?? 'unknown', statusCode: 409, - message: `timeline_id: "${timeline?.savedObjectId}" already exists`, + message: `timeline_id: "${savedObjectId}" already exists`, }) ); } } catch (err) { resolve( createBulkErrorObject({ - id: savedObjectId, + id: savedObjectId ?? 'unknown', statusCode: 400, message: err.message, }) diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/utils/import_timelines.ts b/x-pack/plugins/siem/server/lib/timeline/routes/utils/import_timelines.ts index a49627d40c8f57..b829b550334b5a 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/utils/import_timelines.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/utils/import_timelines.ts @@ -18,7 +18,8 @@ export interface ImportTimelinesSchema { } export type ImportedTimeline = SavedTimeline & { - savedObjectId: string; + savedObjectId: string | null; + version: string | null; pinnedEventIds: string[]; globalNotes: NoteResult[]; eventNotes: NoteResult[]; @@ -90,12 +91,9 @@ export const timelineSavedObjectOmittedFields = [ 'globalNotes', 'eventNotes', 'pinnedEventIds', - 'version', 'savedObjectId', 'created', 'createdBy', 'updated', 'updatedBy', - 'templateTimelineId', - 'templateTimelineVersion', ];