Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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';
import { initialPolicyListState } from '../../endpoint_policy/store/policy_list/reducer';
import { initialAlertListState } from '../../endpoint_alerts/store/reducer';
import { initialPolicyDetailsState } from '../../endpoint_policy/store/policy_details/reducer';
Expand Down Expand Up @@ -231,6 +231,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('../../../timelines/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