From e2d1e7490b228574520ec31429ae817d400e0f35 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Thu, 16 Jul 2020 22:06:03 +0200 Subject: [PATCH 1/8] [Security Solution][Timeline] Fix timeline styling and createFrom behavior --- .../components/open_timeline/helpers.test.ts | 197 ++++++++++++++++++ .../components/open_timeline/helpers.ts | 27 ++- .../open_timeline/open_timeline.tsx | 1 - .../open_timeline_modal/index.tsx | 2 +- .../open_timeline_modal_body.tsx | 66 +++--- .../open_timeline/use_timeline_status.tsx | 4 +- .../timelines/components/timeline/styles.tsx | 3 +- 7 files changed, 258 insertions(+), 42 deletions(-) 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 5759d96b95f9e..f4bd17005fed7 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 @@ -306,6 +306,203 @@ describe('helpers', () => { width: 1100, }); }); + + test('if duplicates and timeline.timelineType is not matching with outcome timelineType it should return draft with empty title', () => { + const timeline = { + savedObjectId: 'savedObject-1', + title: 'Awesome Timeline', + version: '1', + status: TimelineStatus.active, + timelineType: TimelineType.default, + }; + + const newTimeline = defaultTimelineToTimelineModel(timeline, false, TimelineType.template); + expect(newTimeline).toEqual({ + columns: [ + { + columnHeaderType: 'not-filtered', + id: '@timestamp', + width: 190, + }, + { + columnHeaderType: 'not-filtered', + id: 'message', + width: 180, + }, + { + columnHeaderType: 'not-filtered', + id: 'event.category', + width: 180, + }, + { + columnHeaderType: 'not-filtered', + id: 'event.action', + width: 180, + }, + { + columnHeaderType: 'not-filtered', + id: 'host.name', + width: 180, + }, + { + columnHeaderType: 'not-filtered', + id: 'source.ip', + width: 180, + }, + { + columnHeaderType: 'not-filtered', + id: 'destination.ip', + width: 180, + }, + { + columnHeaderType: 'not-filtered', + id: 'user.name', + width: 180, + }, + ], + dataProviders: [], + dateRange: { start: '2020-07-07T08:20:18.966Z', end: '2020-07-08T08:20:18.966Z' }, + description: '', + deletedEventIds: [], + eventIdToNoteIds: {}, + eventType: 'all', + excludedRowRendererIds: [], + filters: [], + highlightedDropAndProviderId: '', + historyIds: [], + id: 'savedObject-1', + isFavorite: false, + isLive: false, + isSelectAllChecked: false, + isLoading: false, + isSaving: false, + itemsPerPage: 25, + itemsPerPageOptions: [10, 25, 50, 100], + kqlMode: 'filter', + kqlQuery: { + filterQuery: null, + filterQueryDraft: null, + }, + loadingEventIds: [], + noteIds: [], + pinnedEventIds: {}, + pinnedEventsSaveObject: {}, + savedObjectId: 'savedObject-1', + selectedEventIds: {}, + show: false, + showCheckboxes: false, + sort: { + columnId: '@timestamp', + sortDirection: 'desc', + }, + status: TimelineStatus.draft, + title: '', + timelineType: TimelineType.template, + templateTimelineId: null, + templateTimelineVersion: null, + version: '1', + width: 1100, + }); + }); + + test('if duplicates and timeline.timelineType is not matching with outcome timelineType it should return draft with empty title template', () => { + const timeline = { + savedObjectId: 'savedObject-1', + title: 'Awesome Template', + version: '1', + status: TimelineStatus.active, + timelineType: TimelineType.template, + }; + + const newTimeline = defaultTimelineToTimelineModel(timeline, false, TimelineType.default); + expect(newTimeline).toEqual({ + columns: [ + { + columnHeaderType: 'not-filtered', + id: '@timestamp', + width: 190, + }, + { + columnHeaderType: 'not-filtered', + id: 'message', + width: 180, + }, + { + columnHeaderType: 'not-filtered', + id: 'event.category', + width: 180, + }, + { + columnHeaderType: 'not-filtered', + id: 'event.action', + width: 180, + }, + { + columnHeaderType: 'not-filtered', + id: 'host.name', + width: 180, + }, + { + columnHeaderType: 'not-filtered', + id: 'source.ip', + width: 180, + }, + { + columnHeaderType: 'not-filtered', + id: 'destination.ip', + width: 180, + }, + { + columnHeaderType: 'not-filtered', + id: 'user.name', + width: 180, + }, + ], + dataProviders: [], + dateRange: { start: '2020-07-07T08:20:18.966Z', end: '2020-07-08T08:20:18.966Z' }, + description: '', + deletedEventIds: [], + eventIdToNoteIds: {}, + eventType: 'all', + excludedRowRendererIds: [], + filters: [], + highlightedDropAndProviderId: '', + historyIds: [], + id: 'savedObject-1', + isFavorite: false, + isLive: false, + isSelectAllChecked: false, + isLoading: false, + isSaving: false, + itemsPerPage: 25, + itemsPerPageOptions: [10, 25, 50, 100], + kqlMode: 'filter', + kqlQuery: { + filterQuery: null, + filterQueryDraft: null, + }, + loadingEventIds: [], + noteIds: [], + pinnedEventIds: {}, + pinnedEventsSaveObject: {}, + savedObjectId: 'savedObject-1', + selectedEventIds: {}, + show: false, + showCheckboxes: false, + sort: { + columnId: '@timestamp', + sortDirection: 'desc', + }, + status: TimelineStatus.draft, + title: '', + timelineType: TimelineType.default, + templateTimelineId: null, + templateTimelineVersion: null, + version: '1', + width: 1100, + }); + }); + test('if columns are null, we should get the default columns', () => { const timeline = { savedObjectId: 'savedObject-1', 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 9899b38f445f9..8a02aa03a0e75 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 @@ -13,6 +13,7 @@ import { Action } from 'typescript-fsa'; import uuid from 'uuid'; import { Dispatch } from 'redux'; import deepMerge from 'deepmerge'; +import { reducer } from 'recompose'; import { oneTimelineQuery } from '../../containers/one/index.gql_query'; import { TimelineResult, @@ -212,6 +213,28 @@ const getDataProviders = ( return dataProviders; }; +export const getTimelineTitle = ( + timeline: TimelineResult, + duplicate: boolean, + timelineType?: TimelineType +) => { + const isCreateFromAction = timeline.timelineType !== timelineType; + if (isCreateFromAction) return ''; + + return duplicate ? `${timeline.title} - Duplicate` : timeline.title || ''; +}; + +export const getTimelineStatus = ( + timeline: TimelineResult, + duplicate: boolean, + timelineType?: TimelineType +) => { + const isCreateTimelineFromAction = timeline.timelineType !== timelineType; + if (isCreateTimelineFromAction) return TimelineStatus.draft; + + return duplicate ? TimelineStatus.active : timeline.status; +}; + // eslint-disable-next-line complexity export const defaultTimelineToTimelineModel = ( timeline: TimelineResult, @@ -234,11 +257,11 @@ export const defaultTimelineToTimelineModel = ( pinnedEventIds: setPinnedEventIds(duplicate, timeline.pinnedEventIds), pinnedEventsSaveObject: setPinnedEventsSaveObject(duplicate, timeline.pinnedEventsSaveObject), id: duplicate ? '' : timeline.savedObjectId, - status: duplicate ? TimelineStatus.active : timeline.status, + status: getTimelineStatus(timeline, duplicate, timelineType), savedObjectId: duplicate ? null : timeline.savedObjectId, version: duplicate ? null : timeline.version, timelineType: timelineType ?? timeline.timelineType, - title: duplicate ? `${timeline.title} - Duplicate` : timeline.title || '', + title: getTimelineTitle(timeline, duplicate, timelineType), templateTimelineId: getTemplateTimelineId(timeline, duplicate, timelineType), templateTimelineVersion: duplicate && isTemplate ? 1 : timeline.templateTimelineVersion, }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.tsx index 13786c55e2a8d..5dd7f07c6c35a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.tsx @@ -183,7 +183,6 @@ export const OpenTimeline = React.memo( /> - {!!timelineFilter && timelineFilter} ( ({ hideActions = [], modalTitle, onClose, onOpen }) => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/open_timeline_modal_body.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/open_timeline_modal_body.tsx index b3ae39bf8b346..af2bd53df77db 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/open_timeline_modal_body.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/open_timeline_modal_body.tsx @@ -79,43 +79,43 @@ export const OpenTimelineModalBody = memo( selectedTimelinesCount={selectedItems.length} title={title} /> - <> - - {SearchRowContent} - - - + <> + + {SearchRowContent} + + + ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_timeline_status.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_timeline_status.tsx index a95f163349f05..8c4c686698c88 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_timeline_status.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_timeline_status.tsx @@ -33,9 +33,7 @@ export const useTimelineStatus = ({ templateTimelineFilter: JSX.Element[] | null; installPrepackagedTimelines: () => void; } => { - const [selectedTab, setSelectedTab] = useState( - TemplateTimelineType.elastic - ); + const [selectedTab, setSelectedTab] = useState(null); const isTemplateFilterEnabled = useMemo(() => timelineType === TimelineType.template, [ timelineType, ]); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/styles.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/styles.tsx index eb103d8e7e861..5c992fd640a97 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/styles.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/styles.tsx @@ -258,8 +258,7 @@ export const EventsTdContent = styled.div.attrs(({ className }) => ({ ? `${width}px` : '100%'}; /* Using width: 100% instead of flex: 1 and max-width: 100% for IE11 */ - > button.euiButtonIcon, - > .euiToolTipAnchor > button.euiButtonIcon { + button.euiButtonIcon { margin-left: ${({ theme }) => `-${theme.eui.paddingSizes.xs}`}; } `; From dd53acedf9dcccde5334b65da7ec78b241438d54 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Thu, 16 Jul 2020 23:04:43 +0200 Subject: [PATCH 2/8] Fix types --- .../public/timelines/components/open_timeline/helpers.ts | 1 - .../public/timelines/components/open_timeline/open_timeline.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) 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 8a02aa03a0e75..94c13d6320bb4 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 @@ -13,7 +13,6 @@ import { Action } from 'typescript-fsa'; import uuid from 'uuid'; import { Dispatch } from 'redux'; import deepMerge from 'deepmerge'; -import { reducer } from 'recompose'; import { oneTimelineQuery } from '../../containers/one/index.gql_query'; import { TimelineResult, diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.tsx index 5dd7f07c6c35a..d839a1deddf21 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiPanel, EuiBasicTable, EuiSpacer } from '@elastic/eui'; +import { EuiPanel, EuiBasicTable } from '@elastic/eui'; import React, { useCallback, useMemo, useRef } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; From 3eda4d006b4d72302f3a9cda8fa14ceac0556d0a Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Fri, 17 Jul 2020 10:55:51 +0200 Subject: [PATCH 3/8] Fix API --- .../security_solution/server/lib/timeline/saved_object.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object.ts index 82a2a866a71ff..19b038faaa568 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object.ts @@ -125,9 +125,7 @@ const getTimelineTypeFilter = ( status: TimelineStatusLiteralWithNull ) => { const typeFilter = - timelineType == null - ? null - : timelineType === TimelineType.template + timelineType === TimelineType.template ? `siem-ui-timeline.attributes.timelineType: ${TimelineType.template}` /** Show only whose timelineType exists and equals to "template" */ : /** Show me every timeline whose timelineType is not "template". * which includes timelineType === 'default' and From 4605896a1ffa3cffecd6038d4511d8928db79fdd Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Fri, 17 Jul 2020 12:54:07 +0200 Subject: [PATCH 4/8] Fix API --- x-pack/plugins/security_solution/common/constants.ts | 5 ----- .../timelines/components/open_timeline/helpers.ts | 6 +++--- .../server/lib/timeline/saved_object.ts | 12 ++++++------ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index b39a038c4cc3c..f934d90c740a5 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -167,8 +167,3 @@ export const showAllOthersBucket: string[] = [ 'destination.ip', 'user.name', ]; - -/* - * This should be set to true after https://github.com/elastic/kibana/pull/67496 is merged - */ -export const enableElasticFilter = false; 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 94c13d6320bb4..b0e64e2ce9980 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 @@ -217,8 +217,8 @@ export const getTimelineTitle = ( duplicate: boolean, timelineType?: TimelineType ) => { - const isCreateFromAction = timeline.timelineType !== timelineType; - if (isCreateFromAction) return ''; + const isCreateTimelineFromAction = timelineType && timeline.timelineType !== timelineType; + if (isCreateTimelineFromAction) return ''; return duplicate ? `${timeline.title} - Duplicate` : timeline.title || ''; }; @@ -228,7 +228,7 @@ export const getTimelineStatus = ( duplicate: boolean, timelineType?: TimelineType ) => { - const isCreateTimelineFromAction = timeline.timelineType !== timelineType; + const isCreateTimelineFromAction = timelineType && timeline.timelineType !== timelineType; if (isCreateTimelineFromAction) return TimelineStatus.draft; return duplicate ? TimelineStatus.active : timeline.status; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object.ts index 19b038faaa568..b50195219f993 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object.ts @@ -7,7 +7,7 @@ import { getOr } from 'lodash/fp'; import { SavedObjectsFindOptions } from '../../../../../../src/core/server'; -import { UNAUTHENTICATED_USER, enableElasticFilter } from '../../../common/constants'; +import { UNAUTHENTICATED_USER } from '../../../common/constants'; import { NoteSavedObject } from '../../../common/types/timeline/note'; import { PinnedEventSavedObject } from '../../../common/types/timeline/pinned_event'; import { @@ -125,7 +125,9 @@ const getTimelineTypeFilter = ( status: TimelineStatusLiteralWithNull ) => { const typeFilter = - timelineType === TimelineType.template + timelineType == null + ? null + : timelineType === TimelineType.template ? `siem-ui-timeline.attributes.timelineType: ${TimelineType.template}` /** Show only whose timelineType exists and equals to "template" */ : /** Show me every timeline whose timelineType is not "template". * which includes timelineType === 'default' and @@ -151,12 +153,10 @@ const getTimelineTypeFilter = ( templateTimelineType == null ? null : templateTimelineType === TemplateTimelineType.elastic - ? `siem-ui-timeline.attributes.createdBy: "Elsatic"` + ? `siem-ui-timeline.attributes.createdBy: "Elastic"` : `not siem-ui-timeline.attributes.createdBy: "Elastic"`; - const filters = enableElasticFilter - ? [typeFilter, draftFilter, immutableFilter, templateTimelineTypeFilter] - : [typeFilter, draftFilter, immutableFilter]; + const filters = [typeFilter, draftFilter, immutableFilter, templateTimelineTypeFilter]; return filters.filter((f) => f != null).join(' and '); }; From 12f1761d7fb9b213844c3f9a4d67cb6a3ab0a9c3 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Fri, 17 Jul 2020 18:25:41 +0200 Subject: [PATCH 5/8] Fix dataproviders --- .../components/alerts_table/helpers.ts | 2 +- .../security_solution/public/graphql/types.ts | 6 +++++ .../components/open_timeline/helpers.ts | 22 ++++++++++++------- .../data_providers/provider_badge.tsx | 2 +- .../containers/one/index.gql_query.ts | 1 + .../timelines/containers/persist.gql_query.ts | 2 ++ 6 files changed, 25 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/helpers.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_table/helpers.ts index 5025d782e2aa2..084e4bff7e0ac 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/helpers.ts +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/helpers.ts @@ -148,7 +148,7 @@ export const reformatDataProviderWithNewValue = { // Support for legacy "template-like" timeline behavior that is using hardcoded list of templateFields - if (timelineType === TimelineType.default) { + if (timelineType !== TimelineType.template) { if (templateFields.includes(dataProvider.queryMatch.field)) { const newValue = getStringArray(dataProvider.queryMatch.field, ecsData); if (newValue.length) { diff --git a/x-pack/plugins/security_solution/public/graphql/types.ts b/x-pack/plugins/security_solution/public/graphql/types.ts index 5f8595df23f9b..1557f5b88f7ec 100644 --- a/x-pack/plugins/security_solution/public/graphql/types.ts +++ b/x-pack/plugins/security_solution/public/graphql/types.ts @@ -5654,6 +5654,8 @@ export namespace GetOneTimeline { kqlQuery: Maybe; + type: Maybe; + queryMatch: Maybe<_QueryMatch>; }; @@ -5932,6 +5934,8 @@ export namespace PersistTimelineMutation { kqlQuery: Maybe; + type: Maybe; + queryMatch: Maybe; and: Maybe; @@ -5964,6 +5968,8 @@ export namespace PersistTimelineMutation { kqlQuery: Maybe; + type: Maybe; + queryMatch: Maybe<_QueryMatch>; }; 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 b0e64e2ce9980..8679df60a2f57 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 @@ -188,14 +188,20 @@ const getTemplateTimelineId = ( return uuid.v4(); }; -const convertToDefaultField = ({ and, ...dataProvider }: DataProviderResult) => - deepMerge(dataProvider, { - type: DataProviderType.default, - queryMatch: { - value: - dataProvider.queryMatch!.operator === IS_OPERATOR ? '' : dataProvider.queryMatch!.value, - }, - }); +const convertToDefaultField = ({ and, ...dataProvider }: DataProviderResult) => { + if (dataProvider.type === DataProviderType.template) { + return deepMerge(dataProvider, { + type: DataProviderType.default, + enabled: dataProvider.queryMatch!.operator !== IS_OPERATOR, + queryMatch: { + value: + dataProvider.queryMatch!.operator === IS_OPERATOR ? '' : dataProvider.queryMatch!.value, + }, + }); + } + + return dataProvider; +}; const getDataProviders = ( duplicate: boolean, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_badge.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_badge.tsx index af63957d35075..bf2094e7659ee 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_badge.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_badge.tsx @@ -92,7 +92,7 @@ const ConvertFieldBadge = styled(ProviderFieldBadge)` `; const TemplateFieldBadge: React.FC = ({ type, toggleType }) => { - if (type === DataProviderType.default) { + if (type !== DataProviderType.template) { return ( {i18n.CONVERT_TO_TEMPLATE_FIELD} ); diff --git a/x-pack/plugins/security_solution/public/timelines/containers/one/index.gql_query.ts b/x-pack/plugins/security_solution/public/timelines/containers/one/index.gql_query.ts index 0aaeb22d72afc..5e50a7fb3313e 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/one/index.gql_query.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/one/index.gql_query.ts @@ -42,6 +42,7 @@ export const oneTimelineQuery = gql` enabled excluded kqlQuery + type queryMatch { field displayField diff --git a/x-pack/plugins/security_solution/public/timelines/containers/persist.gql_query.ts b/x-pack/plugins/security_solution/public/timelines/containers/persist.gql_query.ts index 6a0609f9158f3..5cd7528e9765e 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/persist.gql_query.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/persist.gql_query.ts @@ -32,6 +32,7 @@ export const persistTimelineMutation = gql` enabled excluded kqlQuery + type queryMatch { field displayField @@ -45,6 +46,7 @@ export const persistTimelineMutation = gql` enabled excluded kqlQuery + type queryMatch { field displayField From c34119b8e235c7e3dfbb12d3b366223747cc78f4 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Mon, 20 Jul 2020 09:53:45 +0200 Subject: [PATCH 6/8] update tests --- .../apis/security_solution/saved_objects/timeline.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/test/api_integration/apis/security_solution/saved_objects/timeline.ts b/x-pack/test/api_integration/apis/security_solution/saved_objects/timeline.ts index 10ba9621c0430..a399c07e31065 100644 --- a/x-pack/test/api_integration/apis/security_solution/saved_objects/timeline.ts +++ b/x-pack/test/api_integration/apis/security_solution/saved_objects/timeline.ts @@ -114,6 +114,7 @@ export default function ({ getService }: FtrProviderContext) { enabled: true, excluded: false, kqlQuery: '', + type: 'default', queryMatch: { field: 'host.name', displayField: null, From 1d8a50ffb741eff2fe6cbb1bd0d2d0aeebfac826 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Mon, 20 Jul 2020 14:09:07 +0200 Subject: [PATCH 7/8] Fix duplicate saving --- .../plugins/security_solution/public/graphql/types.ts | 2 ++ .../timelines/components/open_timeline/helpers.ts | 10 ++++------ .../public/timelines/containers/persist.gql_query.ts | 1 + .../public/timelines/store/timeline/epic.ts | 1 + 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/security_solution/public/graphql/types.ts b/x-pack/plugins/security_solution/public/graphql/types.ts index 1557f5b88f7ec..1808d32547fbe 100644 --- a/x-pack/plugins/security_solution/public/graphql/types.ts +++ b/x-pack/plugins/security_solution/public/graphql/types.ts @@ -5872,6 +5872,8 @@ export namespace PersistTimelineMutation { eventType: Maybe; + excludedRowRendererIds: Maybe; + favorite: Maybe; filters: Maybe; 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 8679df60a2f57..af289f94c9a0d 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 @@ -173,10 +173,6 @@ const getTemplateTimelineId = ( duplicate: boolean, targetTimelineType?: TimelineType ) => { - if (!duplicate) { - return timeline.templateTimelineId; - } - if ( targetTimelineType === TimelineType.default && timeline.timelineType === TimelineType.template @@ -184,8 +180,10 @@ const getTemplateTimelineId = ( return timeline.templateTimelineId; } - // TODO: MOVE TO BACKEND - return uuid.v4(); + return duplicate && timeline.timelineType === TimelineType.template + ? // TODO: MOVE TO THE BACKEND + uuid.v4() + : timeline.templateTimelineId; }; const convertToDefaultField = ({ and, ...dataProvider }: DataProviderResult) => { diff --git a/x-pack/plugins/security_solution/public/timelines/containers/persist.gql_query.ts b/x-pack/plugins/security_solution/public/timelines/containers/persist.gql_query.ts index 5cd7528e9765e..c38aa67ccebb2 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/persist.gql_query.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/persist.gql_query.ts @@ -58,6 +58,7 @@ export const persistTimelineMutation = gql` } description eventType + excludedRowRendererIds favorite { fullName userName diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts index 2f9331ec9db8e..a880ca09300b4 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts @@ -88,6 +88,7 @@ import { ActionTimeline, TimelineEpicDependencies } from './types'; const timelineActionsType = [ applyKqlFilterQuery.type, addProvider.type, + addTimeline.type, dataProviderEdited.type, removeColumn.type, removeProvider.type, From ffea0c59ad0e5204f8113d2993e14745f9969598 Mon Sep 17 00:00:00 2001 From: Patryk Kopycinski Date: Mon, 20 Jul 2020 14:11:42 +0200 Subject: [PATCH 8/8] Save excludedRowRenderersId settings --- .../security_solution/public/timelines/store/timeline/epic.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts index a880ca09300b4..7757794c6dc9a 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts @@ -68,6 +68,7 @@ import { updateTimeline, updateTitle, updateAutoSaveMsg, + setExcludedRowRendererIds, setFilters, setSavedQueryId, startTimelineSaving, @@ -92,6 +93,7 @@ const timelineActionsType = [ dataProviderEdited.type, removeColumn.type, removeProvider.type, + setExcludedRowRendererIds.type, setFilters.type, setSavedQueryId.type, updateColumns.type,