Skip to content
Merged
26 changes: 23 additions & 3 deletions x-pack/plugins/siem/common/types/timeline/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,23 +130,42 @@ const SavedSortRuntimeType = runtimeTypes.partial({
sortDirection: unionWithNullType(runtimeTypes.string),
});

/*
* Timeline Statuses
*/

export enum TimelineStatus {
active = 'active',
draft = 'draft',
}

export const TimelineStatusLiteralRt = runtimeTypes.union([
runtimeTypes.literal(TimelineStatus.active),
runtimeTypes.literal(TimelineStatus.draft),
]);

const TimelineStatusLiteralWithNullRt = unionWithNullType(TimelineStatusLiteralRt);

export type TimelineStatusLiteral = runtimeTypes.TypeOf<typeof TimelineStatusLiteralRt>;
export type TimelineStatusLiteralWithNull = runtimeTypes.TypeOf<
typeof TimelineStatusLiteralWithNullRt
>;

/*
* Timeline Types
*/

export enum TimelineType {
default = 'default',
draft = 'draft',
template = 'template',
}

export const TimelineTypeLiteralRt = runtimeTypes.union([
runtimeTypes.literal(TimelineType.template),
runtimeTypes.literal(TimelineType.draft),
runtimeTypes.literal(TimelineType.default),
]);

const TimelineTypeLiteralWithNullRt = unionWithNullType(TimelineTypeLiteralRt);
export const TimelineTypeLiteralWithNullRt = unionWithNullType(TimelineTypeLiteralRt);

export type TimelineTypeLiteral = runtimeTypes.TypeOf<typeof TimelineTypeLiteralRt>;
export type TimelineTypeLiteralWithNull = runtimeTypes.TypeOf<typeof TimelineTypeLiteralWithNullRt>;
Expand All @@ -167,6 +186,7 @@ export const SavedTimelineRuntimeType = runtimeTypes.partial({
dateRange: unionWithNullType(SavedDateRangePickerRuntimeType),
savedQueryId: unionWithNullType(runtimeTypes.string),
sort: unionWithNullType(SavedSortRuntimeType),
status: unionWithNullType(TimelineStatusLiteralRt),
created: unionWithNullType(runtimeTypes.number),
createdBy: unionWithNullType(runtimeTypes.string),
updated: unionWithNullType(runtimeTypes.number),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from '../../../common/mock/';
import { CreateTimeline, UpdateTimelineLoading } from './types';
import { Ecs } from '../../../graphql/types';
import { TimelineType } from '../../../../common/types/timeline';
import { TimelineType, TimelineStatus } from '../../../../common/types/timeline';

jest.mock('apollo-client');

Expand Down Expand Up @@ -215,6 +215,7 @@ describe('signals actions', () => {
columnId: '@timestamp',
sortDirection: 'desc',
},
status: TimelineStatus.draft,
title: '',
timelineType: TimelineType.default,
templateTimelineId: null,
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/siem/public/common/mock/global_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
DEFAULT_INTERVAL_VALUE,
} from '../../../common/constants';
import { networkModel } from '../../network/store';
import { TimelineType } from '../../../common/types/timeline';
import { TimelineType, TimelineStatus } from '../../../common/types/timeline';

export const mockGlobalState: State = {
app: {
Expand Down Expand Up @@ -222,6 +222,7 @@ export const mockGlobalState: State = {
width: DEFAULT_TIMELINE_WIDTH,
isSaving: false,
version: null,
status: TimelineStatus.active,
},
},
},
Expand Down
6 changes: 4 additions & 2 deletions x-pack/plugins/siem/public/common/mock/timeline_results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
import { FilterStateStore } from '../../../../../../src/plugins/data/common/es_query/filters/meta_filter';

import { TimelineType } from '../../../common/types/timeline';
import { TimelineType, TimelineStatus } from '../../../common/types/timeline';

import { OpenTimelineResult } from '../../timelines/components/open_timeline/types';
import { GetAllTimeline, SortFieldTimeline, TimelineResult, Direction } from '../../graphql/types';
Expand Down Expand Up @@ -2142,6 +2142,7 @@ export const mockTimelineModel: TimelineModel = {
columnId: '@timestamp',
sortDirection: Direction.desc,
},
status: TimelineStatus.active,
title: 'Test rule',
timelineType: TimelineType.default,
templateTimelineId: null,
Expand Down Expand Up @@ -2242,8 +2243,9 @@ export const defaultTimelineProps: CreateTimelineProps = {
showCheckboxes: false,
showRowRenderers: true,
sort: { columnId: '@timestamp', sortDirection: Direction.desc },
status: TimelineStatus.draft,
title: '',
timelineType: TimelineType.draft,
timelineType: TimelineType.default,
templateTimelineVersion: null,
templateTimelineId: null,
version: null,
Expand Down
30 changes: 28 additions & 2 deletions x-pack/plugins/siem/public/graphql/introspection.json
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@
{
"name": "timelineType",
"description": "",
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
"type": { "kind": "ENUM", "name": "TimelineType", "ofType": null },
"defaultValue": null
}
],
Expand Down Expand Up @@ -9726,6 +9726,14 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "status",
"description": "",
"args": [],
"type": { "kind": "ENUM", "name": "TimelineStatus", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "title",
"description": "",
Expand Down Expand Up @@ -10353,6 +10361,19 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "ENUM",
"name": "TimelineStatus",
"description": "",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": [
{ "name": "active", "description": "", "isDeprecated": false, "deprecationReason": null },
{ "name": "draft", "description": "", "isDeprecated": false, "deprecationReason": null }
],
"possibleTypes": null
},
{
"kind": "SCALAR",
"name": "Int",
Expand All @@ -10377,7 +10398,6 @@
"isDeprecated": false,
"deprecationReason": null
},
{ "name": "draft", "description": "", "isDeprecated": false, "deprecationReason": null },
{
"name": "template",
"description": "",
Expand Down Expand Up @@ -10962,6 +10982,12 @@
"description": "",
"type": { "kind": "INPUT_OBJECT", "name": "SortTimelineInput", "ofType": null },
"defaultValue": null
},
{
"name": "status",
"description": "",
"type": { "kind": "ENUM", "name": "TimelineStatus", "ofType": null },
"defaultValue": null
}
],
"interfaces": null,
Expand Down
14 changes: 11 additions & 3 deletions x-pack/plugins/siem/public/graphql/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ export interface TimelineInput {
savedQueryId?: Maybe<string>;

sort?: Maybe<SortTimelineInput>;

status?: Maybe<TimelineStatus>;
}

export interface ColumnHeaderInput {
Expand Down Expand Up @@ -340,9 +342,13 @@ export enum TlsFields {
_id = '_id',
}

export enum TimelineStatus {
active = 'active',
draft = 'draft',
}

export enum TimelineType {
default = 'default',
draft = 'draft',
template = 'template',
}

Expand Down Expand Up @@ -1954,6 +1960,8 @@ export interface TimelineResult {

sort?: Maybe<SortTimelineResult>;

status?: Maybe<TimelineStatus>;

title?: Maybe<string>;

templateTimelineId?: Maybe<string>;
Expand Down Expand Up @@ -2237,7 +2245,7 @@ export interface GetAllTimelineQueryArgs {

onlyUserFavorite?: Maybe<boolean>;

timelineType?: Maybe<string>;
timelineType?: Maybe<TimelineType>;
}
export interface AuthenticationsSourceArgs {
timerange: TimerangeInput;
Expand Down Expand Up @@ -4298,7 +4306,7 @@ export namespace GetAllTimeline {
search?: Maybe<string>;
sort?: Maybe<SortTimeline>;
onlyUserFavorite?: Maybe<boolean>;
timelineType?: Maybe<string>;
timelineType?: Maybe<TimelineType>;
};

export type Query = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { KueryFilterQueryKind } from '../../../common/store/model';
import { Note } from '../../../common/lib/note';
import moment from 'moment';
import sinon from 'sinon';
import { TimelineType } from '../../../../common/types/timeline';
import { TimelineType, TimelineStatus } from '../../../../common/types/timeline';

jest.mock('../../../common/store/inputs/actions');
jest.mock('../../store/timeline/actions');
Expand Down Expand Up @@ -299,8 +299,9 @@ describe('helpers', () => {
columnId: '@timestamp',
sortDirection: 'desc',
},
status: TimelineStatus.draft,
title: '',
timelineType: TimelineType.draft,
timelineType: TimelineType.default,
templateTimelineId: null,
templateTimelineVersion: null,
version: '1',
Expand Down Expand Up @@ -396,8 +397,9 @@ describe('helpers', () => {
columnId: '@timestamp',
sortDirection: 'desc',
},
status: TimelineStatus.draft,
title: '',
timelineType: TimelineType.draft,
timelineType: TimelineType.default,
templateTimelineId: null,
templateTimelineVersion: null,
version: '1',
Expand Down Expand Up @@ -517,7 +519,7 @@ describe('helpers', () => {
},
loadingEventIds: [],
title: '',
timelineType: TimelineType.draft,
timelineType: TimelineType.default,
templateTimelineId: null,
templateTimelineVersion: null,
noteIds: [],
Expand All @@ -535,6 +537,7 @@ describe('helpers', () => {
columnId: '@timestamp',
sortDirection: 'desc',
},
status: TimelineStatus.draft,
width: 1100,
id: 'savedObject-1',
});
Expand Down Expand Up @@ -685,7 +688,7 @@ describe('helpers', () => {
},
loadingEventIds: [],
title: '',
timelineType: TimelineType.draft,
timelineType: TimelineType.default,
templateTimelineId: null,
templateTimelineVersion: null,
noteIds: [],
Expand All @@ -703,6 +706,7 @@ describe('helpers', () => {
columnId: '@timestamp',
sortDirection: 'desc',
},
status: TimelineStatus.draft,
width: 1100,
id: 'savedObject-1',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const allTimelinesQuery = gql`
$search: String
$sort: SortTimeline
$onlyUserFavorite: Boolean
$timelineType: String
$timelineType: TimelineType
) {
getAllTimeline(
pageInfo: $pageInfo
Expand Down
34 changes: 25 additions & 9 deletions x-pack/plugins/siem/public/timelines/containers/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import { pipe } from 'fp-ts/lib/pipeable';

import { throwErrors } from '../../../../case/common/api';
import {
SavedTimeline,
TimelineResponse,
TimelineResponseType,
TimelineType,
TimelineStatus,
} from '../../../common/types/timeline';
import { TimelineInput, TimelineType } from '../../graphql/types';
import {
TIMELINE_URL,
TIMELINE_DRAFT_URL,
Expand All @@ -31,7 +31,7 @@ import {
} from '../../alerts/containers/detection_engine/rules';

interface RequestPostTimeline {
timeline: SavedTimeline;
timeline: TimelineInput;
signal?: AbortSignal;
}

Expand Down Expand Up @@ -75,8 +75,8 @@ export const persistTimeline = async ({
timeline,
version,
}: RequestPersistTimeline): Promise<TimelineResponse> => {
if (timelineId == null && timeline.timelineType === TimelineType.draft) {
const draftTimeline = await cleanDraftTimeline();
if (timelineId == null && timeline.status === TimelineStatus.draft) {
const draftTimeline = await cleanDraftTimeline({ timelineType: timeline.timelineType! });
return patchTimeline({
timelineId: draftTimeline.data.persistTimeline.timeline.savedObjectId,
timeline,
Expand Down Expand Up @@ -133,14 +133,30 @@ export const exportSelectedTimeline: ExportSelectedData = async ({
return response.body!;
};

export const getDraftTimeline = async (): Promise<TimelineResponse> => {
const response = await KibanaServices.get().http.get<TimelineResponse>(TIMELINE_DRAFT_URL);
export const getDraftTimeline = async ({
timelineType,
}: {
timelineType: TimelineType;
}): Promise<TimelineResponse> => {
const response = await KibanaServices.get().http.get<TimelineResponse>(TIMELINE_DRAFT_URL, {
query: {
timelineType,
},
});

return decodeTimelineResponse(response);
};

export const cleanDraftTimeline = async (): Promise<TimelineResponse> => {
const response = await KibanaServices.get().http.post<TimelineResponse>(TIMELINE_DRAFT_URL);
export const cleanDraftTimeline = async ({
timelineType,
}: {
timelineType: TimelineType;
}): Promise<TimelineResponse> => {
const response = await KibanaServices.get().http.post<TimelineResponse>(TIMELINE_DRAFT_URL, {
body: JSON.stringify({
timelineType,
}),
});

return decodeTimelineResponse(response);
};
Loading