mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[SecuritySolution] Decouple more timeline saved objects types from their API representations (#159398)
## Summary Continuation of https://github.com/elastic/kibana/pull/158566. Tracked in https://github.com/elastic/security-team/issues/6479. In this PR we're separating the types for the `Note` and `PinnedEvent` saved object and the type of it's API response equivalent. Doing so will allow us to make changes to either representations individually which is necessary for versioning the SO and routes (individually) in the future. The saved object definition and their representative API equivalent now live in `*/saved_object.ts` and `*/api.ts` respectively. A clean cut of these two, now distinct types. You will encounter some duplication of types in these files which is unavoidable. In the future, depending on how both representations evolve when versioned, these two definitions will diverge. You will notice that only few types (and values) defined in `saved_object.ts` are exported. They are only used for the conversion logic. They are not exported so they're not accidentally required by frontend or server code that is not dealing with the conversion. The exported types all start with `SavedObject*` to clearly mark them as SO representations. The conversion files have been updated to use the new representations and there is no implicit conversion between them (e.g. through spreading or rest parameters). The bulk of the changes are updates of import statements to change the import to `**/api.ts`. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
160fa420ef
commit
0c4906af89
30 changed files with 420 additions and 378 deletions
|
@ -12,8 +12,8 @@ import { stringEnum, unionWithNullType } from '../../utility_types';
|
|||
|
||||
import type { Maybe } from '../../search_strategy';
|
||||
import { Direction } from '../../search_strategy';
|
||||
import type { PinnedEvent } from './pinned_event';
|
||||
import { PinnedEventToReturnSavedObjectRuntimeType } from './pinned_event';
|
||||
import type { PinnedEvent } from './pinned_event/api';
|
||||
import { PinnedEventRuntimeType } from './pinned_event/api';
|
||||
import {
|
||||
SavedObjectResolveAliasPurpose,
|
||||
SavedObjectResolveAliasTargetId,
|
||||
|
@ -24,8 +24,8 @@ import {
|
|||
success_count as successCount,
|
||||
} from '../../detection_engine/schemas/common/schemas';
|
||||
import { errorSchema } from '../../detection_engine/schemas/response/error_schema';
|
||||
import type { NoteResult } from './note';
|
||||
import { NoteSavedObjectToReturnRuntimeType } from './note';
|
||||
import type { Note } from './note/api';
|
||||
import { NoteRuntimeType } from './note/api';
|
||||
|
||||
/*
|
||||
* ColumnHeader Types
|
||||
|
@ -320,11 +320,11 @@ export const TimelineSavedToReturnObjectRuntimeType = runtimeTypes.intersection(
|
|||
version: runtimeTypes.string,
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
eventIdToNoteIds: runtimeTypes.array(NoteSavedObjectToReturnRuntimeType),
|
||||
eventIdToNoteIds: runtimeTypes.array(NoteRuntimeType),
|
||||
noteIds: runtimeTypes.array(runtimeTypes.string),
|
||||
notes: runtimeTypes.array(NoteSavedObjectToReturnRuntimeType),
|
||||
notes: runtimeTypes.array(NoteRuntimeType),
|
||||
pinnedEventIds: runtimeTypes.array(runtimeTypes.string),
|
||||
pinnedEventsSaveObject: runtimeTypes.array(PinnedEventToReturnSavedObjectRuntimeType),
|
||||
pinnedEventsSaveObject: runtimeTypes.array(PinnedEventRuntimeType),
|
||||
}),
|
||||
]);
|
||||
|
||||
|
@ -437,8 +437,8 @@ export const sortTimeline = runtimeTypes.type({
|
|||
* Import/export timelines
|
||||
*/
|
||||
|
||||
export type ExportedGlobalNotes = Array<Exclude<NoteResult, 'eventId'>>;
|
||||
export type ExportedEventNotes = NoteResult[];
|
||||
export type ExportedGlobalNotes = Array<Exclude<Note, 'eventId'>>;
|
||||
export type ExportedEventNotes = Note[];
|
||||
|
||||
export interface ExportedNotes {
|
||||
eventNotes: ExportedEventNotes;
|
||||
|
@ -606,7 +606,7 @@ export interface TimelineResult {
|
|||
dateRange?: Maybe<DateRangePickerResult>;
|
||||
description?: Maybe<string>;
|
||||
eqlOptions?: Maybe<EqlOptionsResult>;
|
||||
eventIdToNoteIds?: Maybe<NoteResult[]>;
|
||||
eventIdToNoteIds?: Maybe<Note[]>;
|
||||
eventType?: Maybe<string>;
|
||||
excludedRowRendererIds?: Maybe<RowRendererId[]>;
|
||||
favorite?: Maybe<FavoriteTimelineResult[]>;
|
||||
|
@ -614,7 +614,7 @@ export interface TimelineResult {
|
|||
kqlMode?: Maybe<string>;
|
||||
kqlQuery?: Maybe<SerializedFilterQueryResult>;
|
||||
indexNames?: Maybe<string[]>;
|
||||
notes?: Maybe<NoteResult[]>;
|
||||
notes?: Maybe<Note[]>;
|
||||
noteIds?: Maybe<string[]>;
|
||||
pinnedEventIds?: Maybe<string[]>;
|
||||
pinnedEventsSaveObject?: Maybe<PinnedEvent[]>;
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
|
||||
import * as runtimeTypes from 'io-ts';
|
||||
import type { Maybe } from '../../../search_strategy/common';
|
||||
|
||||
import { unionWithNullType } from '../../../utility_types';
|
||||
|
||||
export const BareNoteSchema = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
timelineId: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
eventId: unionWithNullType(runtimeTypes.string),
|
||||
note: unionWithNullType(runtimeTypes.string),
|
||||
created: unionWithNullType(runtimeTypes.number),
|
||||
createdBy: unionWithNullType(runtimeTypes.string),
|
||||
updated: unionWithNullType(runtimeTypes.number),
|
||||
updatedBy: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
export interface BareNote extends runtimeTypes.TypeOf<typeof BareNoteSchema> {}
|
||||
|
||||
/**
|
||||
* This type represents a note type stored in a saved object that does not include any fields that reference
|
||||
* other saved objects.
|
||||
*/
|
||||
export type BareNoteWithoutExternalRefs = Omit<BareNote, 'timelineId'>;
|
||||
|
||||
export const NoteRuntimeType = runtimeTypes.intersection([
|
||||
BareNoteSchema,
|
||||
runtimeTypes.type({
|
||||
noteId: runtimeTypes.string,
|
||||
version: runtimeTypes.string,
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
timelineVersion: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
export interface Note extends runtimeTypes.TypeOf<typeof NoteRuntimeType> {}
|
||||
|
||||
export interface ResponseNote {
|
||||
code?: Maybe<number>;
|
||||
|
||||
message?: Maybe<string>;
|
||||
|
||||
note: Note;
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
|
||||
import * as runtimeTypes from 'io-ts';
|
||||
import type { Maybe } from '../../../search_strategy/common';
|
||||
import { Direction } from '../../../search_strategy/common';
|
||||
|
||||
import { unionWithNullType } from '../../../utility_types';
|
||||
|
||||
/*
|
||||
* Note Types
|
||||
*/
|
||||
export const SavedNoteRuntimeType = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
timelineId: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
eventId: unionWithNullType(runtimeTypes.string),
|
||||
note: unionWithNullType(runtimeTypes.string),
|
||||
created: unionWithNullType(runtimeTypes.number),
|
||||
createdBy: unionWithNullType(runtimeTypes.string),
|
||||
updated: unionWithNullType(runtimeTypes.number),
|
||||
updatedBy: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
export interface SavedNote extends runtimeTypes.TypeOf<typeof SavedNoteRuntimeType> {}
|
||||
|
||||
/**
|
||||
* This type represents a note type stored in a saved object that does not include any fields that reference
|
||||
* other saved objects.
|
||||
*/
|
||||
export type NoteWithoutExternalRefs = Omit<SavedNote, 'timelineId'>;
|
||||
|
||||
/**
|
||||
* Note Saved object type with metadata
|
||||
*/
|
||||
|
||||
export const NoteSavedObjectRuntimeType = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
id: runtimeTypes.string,
|
||||
attributes: SavedNoteRuntimeType,
|
||||
version: runtimeTypes.string,
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
noteId: runtimeTypes.string,
|
||||
timelineVersion: runtimeTypes.union([
|
||||
runtimeTypes.string,
|
||||
runtimeTypes.null,
|
||||
runtimeTypes.undefined,
|
||||
]),
|
||||
}),
|
||||
]);
|
||||
|
||||
export const NoteSavedObjectToReturnRuntimeType = runtimeTypes.intersection([
|
||||
SavedNoteRuntimeType,
|
||||
runtimeTypes.type({
|
||||
noteId: runtimeTypes.string,
|
||||
version: runtimeTypes.string,
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
timelineVersion: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
export interface NoteSavedObject
|
||||
extends runtimeTypes.TypeOf<typeof NoteSavedObjectToReturnRuntimeType> {}
|
||||
|
||||
export enum SortFieldNote {
|
||||
updatedBy = 'updatedBy',
|
||||
updated = 'updated',
|
||||
}
|
||||
|
||||
export const pageInfoNoteRt = runtimeTypes.type({
|
||||
pageIndex: runtimeTypes.number,
|
||||
pageSize: runtimeTypes.number,
|
||||
});
|
||||
|
||||
export type PageInfoNote = runtimeTypes.TypeOf<typeof pageInfoNoteRt>;
|
||||
|
||||
export const sortNoteRt = runtimeTypes.type({
|
||||
sortField: runtimeTypes.union([
|
||||
runtimeTypes.literal(SortFieldNote.updatedBy),
|
||||
runtimeTypes.literal(SortFieldNote.updated),
|
||||
]),
|
||||
sortOrder: runtimeTypes.union([
|
||||
runtimeTypes.literal(Direction.asc),
|
||||
runtimeTypes.literal(Direction.desc),
|
||||
]),
|
||||
});
|
||||
|
||||
export type SortNote = runtimeTypes.TypeOf<typeof sortNoteRt>;
|
||||
|
||||
export const NoteServerRepresentation = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
timelineId: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
eventId: unionWithNullType(runtimeTypes.string),
|
||||
note: unionWithNullType(runtimeTypes.string),
|
||||
created: unionWithNullType(runtimeTypes.number),
|
||||
createdBy: unionWithNullType(runtimeTypes.string),
|
||||
updated: unionWithNullType(runtimeTypes.number),
|
||||
updatedBy: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
export type NoteServerRepresentationType = runtimeTypes.TypeOf<typeof NoteServerRepresentation>;
|
||||
|
||||
export interface NoteResult {
|
||||
eventId?: Maybe<string>;
|
||||
|
||||
note?: Maybe<string>;
|
||||
|
||||
timelineId?: Maybe<string>;
|
||||
|
||||
noteId: string;
|
||||
|
||||
created?: Maybe<number>;
|
||||
|
||||
createdBy?: Maybe<string>;
|
||||
|
||||
timelineVersion?: Maybe<string>;
|
||||
|
||||
updated?: Maybe<number>;
|
||||
|
||||
updatedBy?: Maybe<string>;
|
||||
|
||||
version?: Maybe<string>;
|
||||
}
|
||||
|
||||
export interface ResponseNotes {
|
||||
notes: NoteResult[];
|
||||
|
||||
totalCount?: Maybe<number>;
|
||||
}
|
||||
|
||||
export interface ResponseNote {
|
||||
code?: Maybe<number>;
|
||||
|
||||
message?: Maybe<string>;
|
||||
|
||||
note: NoteResult;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
|
||||
import * as runtimeTypes from 'io-ts';
|
||||
|
||||
import { unionWithNullType } from '../../../utility_types';
|
||||
|
||||
/*
|
||||
* Note Types
|
||||
*/
|
||||
const SavedNoteRuntimeType = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
timelineId: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
eventId: unionWithNullType(runtimeTypes.string),
|
||||
note: unionWithNullType(runtimeTypes.string),
|
||||
created: unionWithNullType(runtimeTypes.number),
|
||||
createdBy: unionWithNullType(runtimeTypes.string),
|
||||
updated: unionWithNullType(runtimeTypes.number),
|
||||
updatedBy: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
/**
|
||||
* Note Saved object type with metadata
|
||||
*/
|
||||
export const SavedObjectNoteRuntimeType = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
id: runtimeTypes.string,
|
||||
attributes: SavedNoteRuntimeType,
|
||||
version: runtimeTypes.string,
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
noteId: runtimeTypes.string,
|
||||
timelineVersion: runtimeTypes.union([
|
||||
runtimeTypes.string,
|
||||
runtimeTypes.null,
|
||||
runtimeTypes.undefined,
|
||||
]),
|
||||
}),
|
||||
]);
|
||||
|
||||
interface SavedObjectNote extends runtimeTypes.TypeOf<typeof SavedNoteRuntimeType> {}
|
||||
|
||||
/**
|
||||
* This type represents a note type stored in a saved object that does not include any fields that reference
|
||||
* other saved objects.
|
||||
*/
|
||||
export type SavedObjectNoteWithoutExternalRefs = Omit<SavedObjectNote, 'timelineId'>;
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
|
||||
import * as runtimeTypes from 'io-ts';
|
||||
|
||||
import { unionWithNullType } from '../../../utility_types';
|
||||
|
||||
/*
|
||||
* Note Types
|
||||
*/
|
||||
export const BarePinnedEventType = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
timelineId: runtimeTypes.string,
|
||||
eventId: runtimeTypes.string,
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
created: unionWithNullType(runtimeTypes.number),
|
||||
createdBy: unionWithNullType(runtimeTypes.string),
|
||||
updated: unionWithNullType(runtimeTypes.number),
|
||||
updatedBy: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
export interface BarePinnedEvent extends runtimeTypes.TypeOf<typeof BarePinnedEventType> {}
|
||||
|
||||
/**
|
||||
* This type represents a pinned event type stored in a saved object that does not include any fields that reference
|
||||
* other saved objects.
|
||||
*/
|
||||
export type BarePinnedEventWithoutExternalRefs = Omit<BarePinnedEvent, 'timelineId'>;
|
||||
|
||||
export const PinnedEventRuntimeType = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
pinnedEventId: runtimeTypes.string,
|
||||
version: runtimeTypes.string,
|
||||
}),
|
||||
BarePinnedEventType,
|
||||
runtimeTypes.partial({
|
||||
timelineVersion: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
export interface PinnedEvent extends runtimeTypes.TypeOf<typeof PinnedEventRuntimeType> {}
|
||||
|
||||
export type PinnedEventResponse = PinnedEvent & { code: number; message?: string };
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
|
||||
import * as runtimeTypes from 'io-ts';
|
||||
import type { Maybe } from '../../../search_strategy/common';
|
||||
|
||||
import { unionWithNullType } from '../../../utility_types';
|
||||
|
||||
/*
|
||||
* Note Types
|
||||
*/
|
||||
export const SavedPinnedEventRuntimeType = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
timelineId: runtimeTypes.string,
|
||||
eventId: runtimeTypes.string,
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
created: unionWithNullType(runtimeTypes.number),
|
||||
createdBy: unionWithNullType(runtimeTypes.string),
|
||||
updated: unionWithNullType(runtimeTypes.number),
|
||||
updatedBy: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
export interface SavedPinnedEvent extends runtimeTypes.TypeOf<typeof SavedPinnedEventRuntimeType> {}
|
||||
|
||||
/**
|
||||
* This type represents a pinned event type stored in a saved object that does not include any fields that reference
|
||||
* other saved objects.
|
||||
*/
|
||||
export type PinnedEventWithoutExternalRefs = Omit<SavedPinnedEvent, 'timelineId'>;
|
||||
|
||||
/**
|
||||
* Note Saved object type with metadata
|
||||
*/
|
||||
|
||||
export const PinnedEventSavedObjectRuntimeType = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
id: runtimeTypes.string,
|
||||
attributes: SavedPinnedEventRuntimeType,
|
||||
version: runtimeTypes.string,
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
pinnedEventId: unionWithNullType(runtimeTypes.string),
|
||||
timelineVersion: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
export const PinnedEventToReturnSavedObjectRuntimeType = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
pinnedEventId: runtimeTypes.string,
|
||||
version: runtimeTypes.string,
|
||||
}),
|
||||
SavedPinnedEventRuntimeType,
|
||||
runtimeTypes.partial({
|
||||
timelineVersion: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
export interface PinnedEventSavedObject
|
||||
extends runtimeTypes.TypeOf<typeof PinnedEventToReturnSavedObjectRuntimeType> {}
|
||||
|
||||
export interface PinnedEvent {
|
||||
code?: Maybe<number>;
|
||||
|
||||
message?: Maybe<string>;
|
||||
|
||||
pinnedEventId: string;
|
||||
|
||||
eventId?: Maybe<string>;
|
||||
|
||||
timelineId?: Maybe<string>;
|
||||
|
||||
timelineVersion?: Maybe<string>;
|
||||
|
||||
created?: Maybe<number>;
|
||||
|
||||
createdBy?: Maybe<string>;
|
||||
|
||||
updated?: Maybe<number>;
|
||||
|
||||
updatedBy?: Maybe<string>;
|
||||
|
||||
version?: Maybe<string>;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
|
||||
import * as runtimeTypes from 'io-ts';
|
||||
|
||||
import { unionWithNullType } from '../../../utility_types';
|
||||
|
||||
/*
|
||||
* Note Types
|
||||
*/
|
||||
const SavedPinnedEventType = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
timelineId: runtimeTypes.string,
|
||||
eventId: runtimeTypes.string,
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
created: unionWithNullType(runtimeTypes.number),
|
||||
createdBy: unionWithNullType(runtimeTypes.string),
|
||||
updated: unionWithNullType(runtimeTypes.number),
|
||||
updatedBy: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
/**
|
||||
* Pinned Event Saved object type with metadata
|
||||
*/
|
||||
|
||||
export const SavedObjectPinnedEventRuntimeType = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
id: runtimeTypes.string,
|
||||
attributes: SavedPinnedEventType,
|
||||
version: runtimeTypes.string,
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
pinnedEventId: unionWithNullType(runtimeTypes.string),
|
||||
timelineVersion: unionWithNullType(runtimeTypes.string),
|
||||
}),
|
||||
]);
|
||||
|
||||
export interface SavedObjectPinnedEvent extends runtimeTypes.TypeOf<typeof SavedPinnedEventType> {}
|
||||
|
||||
/**
|
||||
* This type represents a pinned event type stored in a saved object that does not include any fields that reference
|
||||
* other saved objects.
|
||||
*/
|
||||
export type SavedObjectPinnedEventWithoutExternalRefs = Omit<SavedObjectPinnedEvent, 'timelineId'>;
|
|
@ -9,7 +9,7 @@ import type { ISearchStart } from '@kbn/data-plugin/public';
|
|||
import type { Filter } from '@kbn/es-query';
|
||||
import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs';
|
||||
import type { Status } from '../../../../common/detection_engine/schemas/common/schemas';
|
||||
import type { NoteResult } from '../../../../common/types/timeline/note';
|
||||
import type { Note } from '../../../../common/types/timeline/note/api';
|
||||
import type { DataProvider } from '../../../timelines/components/timeline/data_providers/data_provider';
|
||||
import type { TimelineModel } from '../../../timelines/store/timeline/model';
|
||||
import type { inputsModel } from '../../../common/store';
|
||||
|
@ -65,7 +65,7 @@ export interface CreateTimelineProps {
|
|||
from: string;
|
||||
timeline: TimelineModel;
|
||||
to: string;
|
||||
notes: NoteResult[] | null;
|
||||
notes: Note[] | null;
|
||||
ruleNote?: string;
|
||||
ruleAuthor?: string | string[];
|
||||
}
|
||||
|
|
|
@ -847,6 +847,8 @@ describe('helpers', () => {
|
|||
updated: 1585233356356,
|
||||
noteId: 'note-id',
|
||||
note: 'I am a note',
|
||||
timelineId: null,
|
||||
version: 'testVersion',
|
||||
},
|
||||
],
|
||||
})();
|
||||
|
@ -864,7 +866,7 @@ describe('helpers', () => {
|
|||
user: 'unknown',
|
||||
saveObjectId: 'note-id',
|
||||
timelineId: null,
|
||||
version: undefined,
|
||||
version: 'testVersion',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -69,8 +69,8 @@ import {
|
|||
DEFAULT_TO_MOMENT,
|
||||
} from '../../../common/utils/default_date_settings';
|
||||
import { resolveTimeline } from '../../containers/api';
|
||||
import type { PinnedEvent } from '../../../../common/types/timeline/pinned_event';
|
||||
import type { NoteResult } from '../../../../common/types/timeline/note';
|
||||
import type { PinnedEvent } from '../../../../common/types/timeline/pinned_event/api';
|
||||
import type { Note } from '../../../../common/types/timeline/note/api';
|
||||
|
||||
export const OPEN_TIMELINE_CLASS_NAME = 'open-timeline';
|
||||
|
||||
|
@ -147,10 +147,7 @@ const setTimelineFilters = (filter: FilterTimelineResult) => ({
|
|||
...(filter.script != null ? { exists: parseString(filter.script) } : {}),
|
||||
});
|
||||
|
||||
const setEventIdToNoteIds = (
|
||||
duplicate: boolean,
|
||||
eventIdToNoteIds: NoteResult[] | null | undefined
|
||||
) =>
|
||||
const setEventIdToNoteIds = (duplicate: boolean, eventIdToNoteIds: Note[] | null | undefined) =>
|
||||
duplicate
|
||||
? {}
|
||||
: eventIdToNoteIds != null
|
||||
|
@ -309,7 +306,7 @@ export const formatTimelineResultToModel = (
|
|||
timelineToOpen: TimelineResult,
|
||||
duplicate: boolean = false,
|
||||
timelineType?: TimelineType
|
||||
): { notes: NoteResult[] | null | undefined; timeline: TimelineModel } => {
|
||||
): { notes: Note[] | null | undefined; timeline: TimelineModel } => {
|
||||
const { notes, ...timelineModel } = timelineToOpen;
|
||||
return {
|
||||
notes,
|
||||
|
@ -474,7 +471,7 @@ export const dispatchUpdateTimeline =
|
|||
dispatchAddNotes({
|
||||
notes:
|
||||
notes != null
|
||||
? notes.map((note: NoteResult) => ({
|
||||
? notes.map((note: Note) => ({
|
||||
created: note.created != null ? new Date(note.created) : new Date(),
|
||||
id: note.noteId,
|
||||
lastEdit: note.updated != null ? new Date(note.updated) : new Date(),
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import type React from 'react';
|
||||
import type { AllTimelinesVariables } from '../../containers/all';
|
||||
import type { TimelineModel } from '../../store/timeline/model';
|
||||
import type { NoteResult } from '../../../../common/types/timeline/note';
|
||||
import type { Note } from '../../../../common/types/timeline/note/api';
|
||||
import type {
|
||||
RowRendererId,
|
||||
SingleTimelineResolveResponse,
|
||||
|
@ -219,7 +219,7 @@ export interface UpdateTimeline {
|
|||
id: string;
|
||||
forceNotes?: boolean;
|
||||
from: string;
|
||||
notes: NoteResult[] | null | undefined;
|
||||
notes: Note[] | null | undefined;
|
||||
resolveTimelineConfig?: ResolveTimelineConfig;
|
||||
timeline: TimelineModel;
|
||||
to: string;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { NOTE_URL } from '../../../../common/constants';
|
||||
import type { NoteSavedObject, SavedNote } from '../../../../common/types/timeline/note';
|
||||
import type { BareNote, Note } from '../../../../common/types/timeline/note/api';
|
||||
import { KibanaServices } from '../../../common/lib/kibana';
|
||||
|
||||
export const persistNote = async ({
|
||||
|
@ -15,7 +15,7 @@ export const persistNote = async ({
|
|||
version,
|
||||
overrideOwner,
|
||||
}: {
|
||||
note: SavedNote;
|
||||
note: BareNote;
|
||||
noteId?: string | null;
|
||||
version?: string | null;
|
||||
overrideOwner?: boolean;
|
||||
|
@ -27,7 +27,7 @@ export const persistNote = async ({
|
|||
} catch (err) {
|
||||
return Promise.reject(new Error(`Failed to stringify query: ${JSON.stringify(err)}`));
|
||||
}
|
||||
const response = await KibanaServices.get().http.patch<NoteSavedObject[]>(NOTE_URL, {
|
||||
const response = await KibanaServices.get().http.patch<Note[]>(NOTE_URL, {
|
||||
method: 'PATCH',
|
||||
body: requestBody,
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { PINNED_EVENT_URL } from '../../../../common/constants';
|
||||
import type { PinnedEvent } from '../../../../common/types/timeline/pinned_event';
|
||||
import type { PinnedEvent } from '../../../../common/types/timeline/pinned_event/api';
|
||||
import { KibanaServices } from '../../../common/lib/kibana';
|
||||
|
||||
export const persistPinnedEvent = async ({
|
||||
|
|
|
@ -28,7 +28,7 @@ import { myEpicTimelineId } from './my_epic_timeline_id';
|
|||
import { dispatcherTimelinePersistQueue } from './epic_dispatcher_timeline_persistence_queue';
|
||||
import type { ActionTimeline, TimelineById } from './types';
|
||||
import { persistNote } from '../../containers/notes/api';
|
||||
import type { ResponseNote } from '../../../../common/types/timeline/note';
|
||||
import type { ResponseNote } from '../../../../common/types/timeline/note/api';
|
||||
|
||||
export const timelineNoteActionsType = [addNote.type, addNoteToEvent.type];
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import { filter, mergeMap, startWith, withLatestFrom, takeUntil } from 'rxjs/ope
|
|||
|
||||
import { addError } from '../../../common/store/app/actions';
|
||||
import type { inputsModel } from '../../../common/store/inputs';
|
||||
import type { PinnedEvent } from '../../../../common/types/timeline/pinned_event';
|
||||
import type { PinnedEventResponse } from '../../../../common/types/timeline/pinned_event/api';
|
||||
import {
|
||||
pinEvent,
|
||||
endTimelineSaving,
|
||||
|
@ -51,7 +51,7 @@ export const epicPersistPinnedEvent = (
|
|||
withLatestFrom(timeline$, allTimelineQuery$),
|
||||
mergeMap(([result, recentTimeline, allTimelineQuery]) => {
|
||||
const savedTimeline = recentTimeline[action.payload.id];
|
||||
const response: PinnedEvent = get('data.persistPinnedEventOnTimeline', result);
|
||||
const response: PinnedEventResponse = get('data.persistPinnedEventOnTimeline', result);
|
||||
const callOutMsg = response && response.code === 403 ? [showCallOutUnauthorizedMsg()] : [];
|
||||
|
||||
if (allTimelineQuery.refetch != null) {
|
||||
|
|
|
@ -26,7 +26,7 @@ import type {
|
|||
TimelineStatus,
|
||||
TimelineType,
|
||||
} from '../../../../common/types/timeline/api';
|
||||
import type { PinnedEvent } from '../../../../common/types/timeline/pinned_event';
|
||||
import type { PinnedEvent } from '../../../../common/types/timeline/pinned_event/api';
|
||||
import type { ResolveTimelineConfig } from '../../components/open_timeline/types';
|
||||
|
||||
export type KqlMode = 'filter' | 'search';
|
||||
|
|
|
@ -10,6 +10,7 @@ import { savePinnedEvents } from '../../../saved_object/pinned_events';
|
|||
import { getNote } from '../../../saved_object/notes';
|
||||
import type { FrameworkRequest } from '../../../../framework';
|
||||
import type { SavedTimeline } from '../../../../../../common/types/timeline/api';
|
||||
import type { Note } from '../../../../../../common/types/timeline/note/api';
|
||||
import { mockTemplate, mockTimeline } from '../../../__mocks__/create_timelines';
|
||||
import { buildFrameworkRequest } from '../../../utils/common';
|
||||
import type { SecurityPluginSetup } from '@kbn/security-plugin/server';
|
||||
|
@ -26,8 +27,15 @@ const timeline = { ...mockTimeline } as SavedTimeline;
|
|||
const timelineSavedObjectId = null;
|
||||
const timelineVersion = null;
|
||||
const pinnedEventIds = ['123'];
|
||||
const notes = [
|
||||
{ noteId: 'abc', note: 'new note', timelineId: '', created: 1603885051655, createdBy: 'elastic' },
|
||||
const notes: Note[] = [
|
||||
{
|
||||
noteId: 'abc',
|
||||
note: 'new note',
|
||||
timelineId: '',
|
||||
created: 1603885051655,
|
||||
createdBy: 'elastic',
|
||||
version: 'testVersion',
|
||||
},
|
||||
];
|
||||
const existingNoteIds = undefined;
|
||||
const isImmutable = true;
|
||||
|
@ -119,6 +127,7 @@ describe('createTimelines', () => {
|
|||
note: 'new note',
|
||||
noteId: 'abc',
|
||||
timelineId: '',
|
||||
version: 'testVersion',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@ import { timeline as timelineLib, pinnedEvent as pinnedEventLib } from '../../..
|
|||
import type { FrameworkRequest } from '../../../../framework';
|
||||
import type { ResponseTimeline, SavedTimeline } from '../../../../../../common/types/timeline/api';
|
||||
import { persistNotes } from '../../../saved_object/notes/persist_notes';
|
||||
import type { NoteResult } from '../../../../../../common/types/timeline/note';
|
||||
import type { Note } from '../../../../../../common/types/timeline/note/api';
|
||||
|
||||
interface CreateTimelineProps {
|
||||
frameworkRequest: FrameworkRequest;
|
||||
|
@ -21,7 +21,7 @@ interface CreateTimelineProps {
|
|||
timelineVersion?: string | null;
|
||||
overrideNotesOwner?: boolean;
|
||||
pinnedEventIds?: string[] | null;
|
||||
notes?: NoteResult[];
|
||||
notes?: Note[];
|
||||
existingNoteIds?: string[];
|
||||
isImmutable?: boolean;
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ import type {
|
|||
ExportedNotes,
|
||||
ExportTimelineNotFoundError,
|
||||
} from '../../../../../../common/types/timeline/api';
|
||||
import type { NoteSavedObject } from '../../../../../../common/types/timeline/note';
|
||||
import type { PinnedEventSavedObject } from '../../../../../../common/types/timeline/pinned_event';
|
||||
import type { Note } from '../../../../../../common/types/timeline/note/api';
|
||||
import type { PinnedEvent } from '../../../../../../common/types/timeline/pinned_event/api';
|
||||
|
||||
import type { FrameworkRequest } from '../../../../framework';
|
||||
import * as noteLib from '../../../saved_object/notes';
|
||||
|
@ -22,7 +22,7 @@ import * as pinnedEventLib from '../../../saved_object/pinned_events';
|
|||
|
||||
import { getSelectedTimelines } from '../../../saved_object/timelines';
|
||||
|
||||
const getGlobalEventNotesByTimelineId = (currentNotes: NoteSavedObject[]): ExportedNotes => {
|
||||
const getGlobalEventNotesByTimelineId = (currentNotes: Note[]): ExportedNotes => {
|
||||
const initialNotes: ExportedNotes = {
|
||||
eventNotes: [],
|
||||
globalNotes: [],
|
||||
|
@ -38,9 +38,7 @@ const getGlobalEventNotesByTimelineId = (currentNotes: NoteSavedObject[]): Expor
|
|||
}, initialNotes);
|
||||
};
|
||||
|
||||
const getPinnedEventsIdsByTimelineId = (
|
||||
currentPinnedEvents: PinnedEventSavedObject[]
|
||||
): string[] => {
|
||||
const getPinnedEventsIdsByTimelineId = (currentPinnedEvents: PinnedEvent[]): string[] => {
|
||||
return currentPinnedEvents.map((event) => event.eventId) ?? [];
|
||||
};
|
||||
|
||||
|
@ -60,9 +58,9 @@ const getTimelinesFromObjects = async (
|
|||
),
|
||||
]);
|
||||
|
||||
const myNotes = notes.reduce<NoteSavedObject[]>((acc, note) => [...acc, ...note], []);
|
||||
const myNotes = notes.reduce<Note[]>((acc, note) => [...acc, ...note], []);
|
||||
|
||||
const myPinnedEventIds = pinnedEvents.reduce<PinnedEventSavedObject[]>(
|
||||
const myPinnedEventIds = pinnedEvents.reduce<PinnedEvent[]>(
|
||||
(acc, pinnedEventId) => [...acc, ...pinnedEventId],
|
||||
[]
|
||||
);
|
||||
|
|
|
@ -268,28 +268,34 @@ describe('import timelines', () => {
|
|||
expect(mockPersistNote.mock.calls[0][0].note).toEqual({
|
||||
eventId: undefined,
|
||||
note: 'original note',
|
||||
noteId: 'd2649d40-6bc5-11ea-86f0-5db0048c6086',
|
||||
created: '1584830796960',
|
||||
createdBy: 'original author A',
|
||||
updated: '1584830796960',
|
||||
updatedBy: 'original author A',
|
||||
version: 'WzExNjQsMV0=',
|
||||
timelineId: mockCreatedTimeline.savedObjectId,
|
||||
});
|
||||
expect(mockPersistNote.mock.calls[1][0].note).toEqual({
|
||||
eventId: mockUniqueParsedObjects[0].eventNotes[0].eventId,
|
||||
note: 'original event note',
|
||||
noteId: '73ac2370-6bc2-11ea-a90b-f5341fb7a189',
|
||||
created: '1584830796960',
|
||||
createdBy: 'original author B',
|
||||
updated: '1584830796960',
|
||||
updatedBy: 'original author B',
|
||||
version: 'WzExMjgsMV0=',
|
||||
timelineId: mockCreatedTimeline.savedObjectId,
|
||||
});
|
||||
expect(mockPersistNote.mock.calls[2][0].note).toEqual({
|
||||
eventId: mockUniqueParsedObjects[0].eventNotes[1].eventId,
|
||||
note: 'event note2',
|
||||
noteId: 'f7b71620-6bc2-11ea-a0b6-33c7b2a78885',
|
||||
created: '1584830796960',
|
||||
createdBy: 'angela',
|
||||
updated: '1584830796960',
|
||||
updatedBy: 'angela',
|
||||
version: 'WzExMzUsMV0=',
|
||||
timelineId: mockCreatedTimeline.savedObjectId,
|
||||
});
|
||||
});
|
||||
|
@ -307,8 +313,11 @@ describe('import timelines', () => {
|
|||
updatedBy: mockUniqueParsedObjects[0].globalNotes[0].updatedBy,
|
||||
eventId: undefined,
|
||||
note: mockUniqueParsedObjects[0].globalNotes[0].note,
|
||||
noteId: mockUniqueParsedObjects[0].globalNotes[0].noteId,
|
||||
timelineId: mockCreatedTimeline.savedObjectId,
|
||||
version: mockUniqueParsedObjects[0].globalNotes[0].version,
|
||||
});
|
||||
|
||||
expect(mockPersistNote.mock.calls[1][0].note).toEqual({
|
||||
created: mockUniqueParsedObjects[0].eventNotes[0].created,
|
||||
createdBy: mockUniqueParsedObjects[0].eventNotes[0].createdBy,
|
||||
|
@ -316,7 +325,9 @@ describe('import timelines', () => {
|
|||
updatedBy: mockUniqueParsedObjects[0].eventNotes[0].updatedBy,
|
||||
eventId: mockUniqueParsedObjects[0].eventNotes[0].eventId,
|
||||
note: mockUniqueParsedObjects[0].eventNotes[0].note,
|
||||
noteId: mockUniqueParsedObjects[0].eventNotes[0].noteId,
|
||||
timelineId: mockCreatedTimeline.savedObjectId,
|
||||
version: mockUniqueParsedObjects[0].eventNotes[0].version,
|
||||
});
|
||||
expect(mockPersistNote.mock.calls[2][0].note).toEqual({
|
||||
created: mockUniqueParsedObjects[0].eventNotes[1].created,
|
||||
|
@ -325,7 +336,9 @@ describe('import timelines', () => {
|
|||
updatedBy: mockUniqueParsedObjects[0].eventNotes[1].updatedBy,
|
||||
eventId: mockUniqueParsedObjects[0].eventNotes[1].eventId,
|
||||
note: mockUniqueParsedObjects[0].eventNotes[1].note,
|
||||
noteId: mockUniqueParsedObjects[0].eventNotes[1].noteId,
|
||||
timelineId: mockCreatedTimeline.savedObjectId,
|
||||
version: mockUniqueParsedObjects[0].eventNotes[1].version,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -641,10 +654,12 @@ describe('import timeline templates', () => {
|
|||
expect(mockPersistNote.mock.calls[0][0].note).toEqual({
|
||||
eventId: undefined,
|
||||
note: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].note,
|
||||
noteId: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].noteId,
|
||||
created: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].created,
|
||||
createdBy: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].createdBy,
|
||||
updated: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].updated,
|
||||
updatedBy: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].updatedBy,
|
||||
version: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].version,
|
||||
timelineId: mockCreatedTemplateTimeline.savedObjectId,
|
||||
});
|
||||
});
|
||||
|
@ -787,10 +802,12 @@ describe('import timeline templates', () => {
|
|||
expect(mockPersistNote.mock.calls[0][0].note).toEqual({
|
||||
eventId: undefined,
|
||||
note: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].note,
|
||||
noteId: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].noteId,
|
||||
created: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].created,
|
||||
createdBy: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].createdBy,
|
||||
updated: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].updated,
|
||||
updatedBy: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].updatedBy,
|
||||
version: mockUniqueParsedTemplateTimelineObjects[0].globalNotes[0].version,
|
||||
timelineId: mockCreatedTemplateTimeline.savedObjectId,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,14 +8,14 @@ import type { BulkError } from '../../../../detection_engine/routes/utils';
|
|||
|
||||
import type { SavedTimeline } from '../../../../../../common/types/timeline/api';
|
||||
import type { TimelineStatusActions } from '../../../utils/common';
|
||||
import type { NoteResult } from '../../../../../../common/types/timeline/note';
|
||||
import type { Note } from '../../../../../../common/types/timeline/note/api';
|
||||
|
||||
export type ImportedTimeline = SavedTimeline & {
|
||||
savedObjectId: string | null;
|
||||
version: string | null;
|
||||
pinnedEventIds: string[];
|
||||
globalNotes: NoteResult[];
|
||||
eventNotes: NoteResult[];
|
||||
globalNotes: Note[];
|
||||
eventNotes: Note[];
|
||||
};
|
||||
|
||||
export type PromiseFromStreams = ImportedTimeline;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { NoteResult, SavedNote } from '../../../../../common/types/timeline/note';
|
||||
import type { Note } from '../../../../../common/types/timeline/note/api';
|
||||
import type { FrameworkRequest } from '../../../framework';
|
||||
import { getNote } from './saved_object';
|
||||
|
||||
|
@ -16,10 +16,10 @@ import { getNote } from './saved_object';
|
|||
|
||||
export const getOverridableNote = async (
|
||||
frameworkRequest: FrameworkRequest,
|
||||
note: NoteResult,
|
||||
note: Note,
|
||||
timelineSavedObjectId: string,
|
||||
overrideOwner: boolean
|
||||
): Promise<SavedNote> => {
|
||||
): Promise<Note> => {
|
||||
let savedNote = note;
|
||||
try {
|
||||
savedNote = await getNote(frameworkRequest, note.noteId);
|
||||
|
@ -30,6 +30,8 @@ export const getOverridableNote = async (
|
|||
eventId: note.eventId,
|
||||
note: note.note,
|
||||
timelineId: timelineSavedObjectId,
|
||||
version: note.version,
|
||||
noteId: note.noteId,
|
||||
}
|
||||
: {
|
||||
eventId: savedNote.eventId,
|
||||
|
@ -39,5 +41,7 @@ export const getOverridableNote = async (
|
|||
updated: savedNote.updated,
|
||||
updatedBy: savedNote.updatedBy,
|
||||
timelineId: timelineSavedObjectId,
|
||||
version: note.version,
|
||||
noteId: note.noteId,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
import type { FrameworkRequest } from '../../../framework';
|
||||
import { persistNote } from './saved_object';
|
||||
import { getOverridableNote } from './get_overridable_note';
|
||||
import type { NoteResult } from '../../../../../common/types/timeline/note';
|
||||
import type { Note } from '../../../../../common/types/timeline/note/api';
|
||||
|
||||
export const persistNotes = async (
|
||||
frameworkRequest: FrameworkRequest,
|
||||
timelineSavedObjectId: string,
|
||||
existingNoteIds?: string[],
|
||||
newNotes?: NoteResult[],
|
||||
newNotes?: Note[],
|
||||
overrideOwner: boolean = true
|
||||
) => {
|
||||
return Promise.all(
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
*/
|
||||
|
||||
import type { AuthenticatedUser } from '@kbn/security-plugin/common/model';
|
||||
import type { NoteSavedObject } from '../../../../../common/types/timeline/note';
|
||||
import type { Note } from '../../../../../common/types/timeline/note/api';
|
||||
|
||||
import { pickSavedNote } from './saved_object';
|
||||
|
||||
describe('saved_object', () => {
|
||||
const mockDateNow = new Date('2020-04-03T23:00:00.000Z').valueOf();
|
||||
const getMockSavedNote = (): NoteSavedObject => ({
|
||||
const getMockSavedNote = (): Note => ({
|
||||
noteId: '7ba7a520-03f4-11eb-9d9d-ffba20fabba8',
|
||||
version: 'WzQ0ODEsMV0=',
|
||||
note: '789',
|
||||
|
|
|
@ -18,13 +18,13 @@ import type { AuthenticatedUser } from '@kbn/security-plugin/common/model';
|
|||
import { getUserDisplayName } from '@kbn/user-profile-components';
|
||||
import { UNAUTHENTICATED_USER } from '../../../../../common/constants';
|
||||
import type {
|
||||
SavedNote,
|
||||
NoteSavedObject,
|
||||
NoteResult,
|
||||
Note,
|
||||
BareNote,
|
||||
BareNoteWithoutExternalRefs,
|
||||
ResponseNote,
|
||||
NoteWithoutExternalRefs,
|
||||
} from '../../../../../common/types/timeline/note';
|
||||
import { NoteSavedObjectRuntimeType } from '../../../../../common/types/timeline/note';
|
||||
} from '../../../../../common/types/timeline/note/api';
|
||||
import { SavedObjectNoteRuntimeType } from '../../../../../common/types/timeline/note/saved_object';
|
||||
import type { SavedObjectNoteWithoutExternalRefs } from '../../../../../common/types/timeline/note/saved_object';
|
||||
import type { FrameworkRequest } from '../../../framework';
|
||||
import { noteSavedObjectType } from '../../saved_object_mappings/notes';
|
||||
import { createTimeline } from '../timelines';
|
||||
|
@ -60,17 +60,14 @@ export const deleteNote = async ({
|
|||
await savedObjectsClient.delete(noteSavedObjectType, noteId);
|
||||
};
|
||||
|
||||
export const getNote = async (
|
||||
request: FrameworkRequest,
|
||||
noteId: string
|
||||
): Promise<NoteSavedObject> => {
|
||||
export const getNote = async (request: FrameworkRequest, noteId: string): Promise<Note> => {
|
||||
return getSavedNote(request, noteId);
|
||||
};
|
||||
|
||||
export const getNotesByTimelineId = async (
|
||||
request: FrameworkRequest,
|
||||
timelineId: string
|
||||
): Promise<NoteSavedObject[]> => {
|
||||
): Promise<Note[]> => {
|
||||
const options: SavedObjectsFindOptions = {
|
||||
type: noteSavedObjectType,
|
||||
hasReference: { type: timelineSavedObjectType, id: timelineId },
|
||||
|
@ -87,7 +84,7 @@ export const persistNote = async ({
|
|||
}: {
|
||||
request: FrameworkRequest;
|
||||
noteId: string | null;
|
||||
note: SavedNote;
|
||||
note: BareNote;
|
||||
overrideOwner?: boolean;
|
||||
}): Promise<ResponseNote> => {
|
||||
try {
|
||||
|
@ -104,7 +101,7 @@ export const persistNote = async ({
|
|||
return await updateNote({ request, noteId, note, overrideOwner });
|
||||
} catch (err) {
|
||||
if (getOr(null, 'output.statusCode', err) === 403) {
|
||||
const noteToReturn: NoteResult = {
|
||||
const noteToReturn: Note = {
|
||||
...note,
|
||||
noteId: uuidv1(),
|
||||
version: '',
|
||||
|
@ -129,7 +126,7 @@ const createNote = async ({
|
|||
}: {
|
||||
request: FrameworkRequest;
|
||||
noteId: string | null;
|
||||
note: SavedNote;
|
||||
note: BareNote;
|
||||
overrideOwner?: boolean;
|
||||
}) => {
|
||||
const savedObjectsClient = (await request.context.core).savedObjects.client;
|
||||
|
@ -155,13 +152,22 @@ const createNote = async ({
|
|||
: shallowCopyOfNote;
|
||||
|
||||
const { transformedFields: migratedAttributes, references } =
|
||||
noteFieldsMigrator.extractFieldsToReferences<NoteWithoutExternalRefs>({
|
||||
noteFieldsMigrator.extractFieldsToReferences<BareNoteWithoutExternalRefs>({
|
||||
data: noteWithCreator,
|
||||
});
|
||||
|
||||
const createdNote = await savedObjectsClient.create<NoteWithoutExternalRefs>(
|
||||
const noteAttributes: SavedObjectNoteWithoutExternalRefs = {
|
||||
eventId: migratedAttributes.eventId,
|
||||
note: migratedAttributes.note,
|
||||
created: migratedAttributes.created,
|
||||
createdBy: migratedAttributes.createdBy,
|
||||
updated: migratedAttributes.updated,
|
||||
updatedBy: migratedAttributes.updatedBy,
|
||||
};
|
||||
|
||||
const createdNote = await savedObjectsClient.create<SavedObjectNoteWithoutExternalRefs>(
|
||||
noteSavedObjectType,
|
||||
migratedAttributes,
|
||||
noteAttributes,
|
||||
{
|
||||
references,
|
||||
}
|
||||
|
@ -187,13 +193,13 @@ const updateNote = async ({
|
|||
}: {
|
||||
request: FrameworkRequest;
|
||||
noteId: string;
|
||||
note: SavedNote;
|
||||
note: BareNote;
|
||||
overrideOwner?: boolean;
|
||||
}) => {
|
||||
const savedObjectsClient = (await request.context.core).savedObjects.client;
|
||||
const userInfo = request.user;
|
||||
|
||||
const existingNote = await savedObjectsClient.get<NoteWithoutExternalRefs>(
|
||||
const existingNote = await savedObjectsClient.get<SavedObjectNoteWithoutExternalRefs>(
|
||||
noteSavedObjectType,
|
||||
noteId
|
||||
);
|
||||
|
@ -201,20 +207,24 @@ const updateNote = async ({
|
|||
const noteWithCreator = overrideOwner ? pickSavedNote(noteId, note, userInfo) : note;
|
||||
|
||||
const { transformedFields: migratedPatchAttributes, references } =
|
||||
noteFieldsMigrator.extractFieldsToReferences<NoteWithoutExternalRefs>({
|
||||
noteFieldsMigrator.extractFieldsToReferences<BareNoteWithoutExternalRefs>({
|
||||
data: noteWithCreator,
|
||||
existingReferences: existingNote.references,
|
||||
});
|
||||
|
||||
const updatedNote = await savedObjectsClient.update(
|
||||
noteSavedObjectType,
|
||||
noteId,
|
||||
migratedPatchAttributes,
|
||||
{
|
||||
version: existingNote.version || undefined,
|
||||
references,
|
||||
}
|
||||
);
|
||||
const noteAttributes: SavedObjectNoteWithoutExternalRefs = {
|
||||
eventId: migratedPatchAttributes.eventId,
|
||||
note: migratedPatchAttributes.note,
|
||||
created: migratedPatchAttributes.created,
|
||||
createdBy: migratedPatchAttributes.createdBy,
|
||||
updated: migratedPatchAttributes.updated,
|
||||
updatedBy: migratedPatchAttributes.updatedBy,
|
||||
};
|
||||
|
||||
const updatedNote = await savedObjectsClient.update(noteSavedObjectType, noteId, noteAttributes, {
|
||||
version: existingNote.version || undefined,
|
||||
references,
|
||||
});
|
||||
|
||||
const populatedNote = noteFieldsMigrator.populateFieldsFromReferencesForPatch({
|
||||
dataBeforeRequest: note,
|
||||
|
@ -232,7 +242,7 @@ const updateNote = async ({
|
|||
|
||||
const getSavedNote = async (request: FrameworkRequest, NoteId: string) => {
|
||||
const savedObjectsClient = (await request.context.core).savedObjects.client;
|
||||
const savedObject = await savedObjectsClient.get<NoteWithoutExternalRefs>(
|
||||
const savedObject = await savedObjectsClient.get<SavedObjectNoteWithoutExternalRefs>(
|
||||
noteSavedObjectType,
|
||||
NoteId
|
||||
);
|
||||
|
@ -244,7 +254,7 @@ const getSavedNote = async (request: FrameworkRequest, NoteId: string) => {
|
|||
|
||||
const getAllSavedNote = async (request: FrameworkRequest, options: SavedObjectsFindOptions) => {
|
||||
const savedObjectsClient = (await request.context.core).savedObjects.client;
|
||||
const savedObjects = await savedObjectsClient.find<NoteWithoutExternalRefs>(options);
|
||||
const savedObjects = await savedObjectsClient.find<SavedObjectNoteWithoutExternalRefs>(options);
|
||||
|
||||
return {
|
||||
totalCount: savedObjects.total,
|
||||
|
@ -259,15 +269,23 @@ const getAllSavedNote = async (request: FrameworkRequest, options: SavedObjectsF
|
|||
export const convertSavedObjectToSavedNote = (
|
||||
savedObject: unknown,
|
||||
timelineVersion?: string | undefined | null
|
||||
): NoteSavedObject =>
|
||||
): Note =>
|
||||
pipe(
|
||||
NoteSavedObjectRuntimeType.decode(savedObject),
|
||||
map((savedNote) => ({
|
||||
noteId: savedNote.id,
|
||||
version: savedNote.version,
|
||||
timelineVersion,
|
||||
...savedNote.attributes,
|
||||
})),
|
||||
SavedObjectNoteRuntimeType.decode(savedObject),
|
||||
map((savedNote) => {
|
||||
return {
|
||||
noteId: savedNote.id,
|
||||
version: savedNote.version,
|
||||
timelineVersion,
|
||||
timelineId: savedNote.attributes.timelineId,
|
||||
eventId: savedNote.attributes.eventId,
|
||||
note: savedNote.attributes.note,
|
||||
created: savedNote.attributes.created,
|
||||
createdBy: savedNote.attributes.createdBy,
|
||||
updated: savedNote.attributes.updated,
|
||||
updatedBy: savedNote.attributes.updatedBy,
|
||||
};
|
||||
}),
|
||||
fold((errors) => {
|
||||
throw new Error(failure(errors).join('\n'));
|
||||
}, identity)
|
||||
|
@ -275,7 +293,7 @@ export const convertSavedObjectToSavedNote = (
|
|||
|
||||
export const pickSavedNote = (
|
||||
noteId: string | null,
|
||||
savedNote: SavedNote,
|
||||
savedNote: BareNote,
|
||||
userInfo: AuthenticatedUser | null
|
||||
) => {
|
||||
if (noteId == null) {
|
||||
|
|
|
@ -15,12 +15,13 @@ import type { SavedObjectsFindOptions } from '@kbn/core/server';
|
|||
import type { AuthenticatedUser } from '@kbn/security-plugin/common/model';
|
||||
import { UNAUTHENTICATED_USER } from '../../../../../common/constants';
|
||||
import type {
|
||||
PinnedEventSavedObject,
|
||||
SavedPinnedEvent,
|
||||
PinnedEvent as PinnedEventResponse,
|
||||
PinnedEventWithoutExternalRefs,
|
||||
} from '../../../../../common/types/timeline/pinned_event';
|
||||
import { PinnedEventSavedObjectRuntimeType } from '../../../../../common/types/timeline/pinned_event';
|
||||
BarePinnedEvent,
|
||||
PinnedEvent,
|
||||
PinnedEventResponse,
|
||||
BarePinnedEventWithoutExternalRefs,
|
||||
} from '../../../../../common/types/timeline/pinned_event/api';
|
||||
import { SavedObjectPinnedEventRuntimeType } from '../../../../../common/types/timeline/pinned_event/saved_object';
|
||||
import type { SavedObjectPinnedEventWithoutExternalRefs } from '../../../../../common/types/timeline/pinned_event/saved_object';
|
||||
import type { FrameworkRequest } from '../../../framework';
|
||||
|
||||
import { createTimeline } from '../timelines';
|
||||
|
@ -64,7 +65,7 @@ export const PINNED_EVENTS_PER_PAGE = 10000; // overrides the saved object clien
|
|||
export const getAllPinnedEventsByTimelineId = async (
|
||||
request: FrameworkRequest,
|
||||
timelineId: string
|
||||
): Promise<PinnedEventSavedObject[]> => {
|
||||
): Promise<PinnedEvent[]> => {
|
||||
const options: SavedObjectsFindOptions = {
|
||||
type: pinnedEventSavedObjectType,
|
||||
hasReference: { type: timelineSavedObjectType, id: timelineId },
|
||||
|
@ -99,7 +100,7 @@ export const persistPinnedEventOnTimeline = async (
|
|||
|
||||
// we already had this event pinned so let's just return the one we already had
|
||||
if (pinnedEvents.length > 0) {
|
||||
return pinnedEvents[0];
|
||||
return { ...pinnedEvents[0], code: 200 };
|
||||
}
|
||||
|
||||
return await createPinnedEvent({
|
||||
|
@ -124,6 +125,8 @@ export const persistPinnedEventOnTimeline = async (
|
|||
pinnedEventId: eventId,
|
||||
timelineId: '',
|
||||
timelineVersion: '',
|
||||
version: '',
|
||||
eventId: '',
|
||||
}
|
||||
: null;
|
||||
}
|
||||
|
@ -161,7 +164,7 @@ const getPinnedEventsInTimelineWithEventId = async (
|
|||
request: FrameworkRequest,
|
||||
timelineId: string,
|
||||
eventId: string
|
||||
): Promise<PinnedEventSavedObject[]> => {
|
||||
): Promise<PinnedEvent[]> => {
|
||||
const allPinnedEventId = await getAllPinnedEventsByTimelineId(request, timelineId);
|
||||
const pinnedEvents = allPinnedEventId.filter((pinnedEvent) => pinnedEvent.eventId === eventId);
|
||||
|
||||
|
@ -178,10 +181,10 @@ const createPinnedEvent = async ({
|
|||
eventId: string;
|
||||
timelineId: string;
|
||||
timelineVersion?: string;
|
||||
}) => {
|
||||
}): Promise<PinnedEventResponse> => {
|
||||
const savedObjectsClient = (await request.context.core).savedObjects.client;
|
||||
|
||||
const savedPinnedEvent: SavedPinnedEvent = {
|
||||
const savedPinnedEvent: BarePinnedEvent = {
|
||||
eventId,
|
||||
timelineId,
|
||||
};
|
||||
|
@ -189,21 +192,33 @@ const createPinnedEvent = async ({
|
|||
const pinnedEventWithCreator = pickSavedPinnedEvent(null, savedPinnedEvent, request.user);
|
||||
|
||||
const { transformedFields: migratedAttributes, references } =
|
||||
pinnedEventFieldsMigrator.extractFieldsToReferences<PinnedEventWithoutExternalRefs>({
|
||||
pinnedEventFieldsMigrator.extractFieldsToReferences<BarePinnedEventWithoutExternalRefs>({
|
||||
data: pinnedEventWithCreator,
|
||||
});
|
||||
|
||||
const createdPinnedEvent = await savedObjectsClient.create<PinnedEventWithoutExternalRefs>(
|
||||
pinnedEventSavedObjectType,
|
||||
migratedAttributes,
|
||||
{ references }
|
||||
);
|
||||
const pinnedEventAttributes: SavedObjectPinnedEventWithoutExternalRefs = {
|
||||
eventId: migratedAttributes.eventId,
|
||||
created: migratedAttributes.created,
|
||||
createdBy: migratedAttributes.createdBy,
|
||||
updated: migratedAttributes.updated,
|
||||
updatedBy: migratedAttributes.updatedBy,
|
||||
};
|
||||
|
||||
const createdPinnedEvent =
|
||||
await savedObjectsClient.create<SavedObjectPinnedEventWithoutExternalRefs>(
|
||||
pinnedEventSavedObjectType,
|
||||
pinnedEventAttributes,
|
||||
{ references }
|
||||
);
|
||||
|
||||
const repopulatedSavedObject =
|
||||
pinnedEventFieldsMigrator.populateFieldsFromReferences(createdPinnedEvent);
|
||||
|
||||
// create Pinned Event on Timeline
|
||||
return convertSavedObjectToSavedPinnedEvent(repopulatedSavedObject, timelineVersion);
|
||||
return {
|
||||
...convertSavedObjectToSavedPinnedEvent(repopulatedSavedObject, timelineVersion),
|
||||
code: 200,
|
||||
};
|
||||
};
|
||||
|
||||
const getAllSavedPinnedEvents = async (
|
||||
|
@ -211,7 +226,9 @@ const getAllSavedPinnedEvents = async (
|
|||
options: SavedObjectsFindOptions
|
||||
) => {
|
||||
const savedObjectsClient = (await request.context.core).savedObjects.client;
|
||||
const savedObjects = await savedObjectsClient.find<PinnedEventWithoutExternalRefs>(options);
|
||||
const savedObjects = await savedObjectsClient.find<SavedObjectPinnedEventWithoutExternalRefs>(
|
||||
options
|
||||
);
|
||||
|
||||
return savedObjects.saved_objects.map((savedObject) => {
|
||||
const populatedPinnedEvent =
|
||||
|
@ -240,15 +257,22 @@ export const savePinnedEvents = (
|
|||
export const convertSavedObjectToSavedPinnedEvent = (
|
||||
savedObject: unknown,
|
||||
timelineVersion?: string | undefined | null
|
||||
): PinnedEventSavedObject =>
|
||||
): PinnedEvent =>
|
||||
pipe(
|
||||
PinnedEventSavedObjectRuntimeType.decode(savedObject),
|
||||
map((savedPinnedEvent) => ({
|
||||
pinnedEventId: savedPinnedEvent.id,
|
||||
version: savedPinnedEvent.version,
|
||||
timelineVersion,
|
||||
...savedPinnedEvent.attributes,
|
||||
})),
|
||||
SavedObjectPinnedEventRuntimeType.decode(savedObject),
|
||||
map((savedPinnedEvent) => {
|
||||
return {
|
||||
pinnedEventId: savedPinnedEvent.id,
|
||||
version: savedPinnedEvent.version,
|
||||
timelineVersion,
|
||||
timelineId: savedPinnedEvent.attributes.timelineId,
|
||||
created: savedPinnedEvent.attributes.created,
|
||||
createdBy: savedPinnedEvent.attributes.createdBy,
|
||||
eventId: savedPinnedEvent.attributes.eventId,
|
||||
updated: savedPinnedEvent.attributes.updated,
|
||||
updatedBy: savedPinnedEvent.attributes.updatedBy,
|
||||
};
|
||||
}),
|
||||
fold((errors) => {
|
||||
throw new Error(failure(errors).join('\n'));
|
||||
}, identity)
|
||||
|
@ -256,7 +280,7 @@ export const convertSavedObjectToSavedPinnedEvent = (
|
|||
|
||||
export const pickSavedPinnedEvent = (
|
||||
pinnedEventId: string | null,
|
||||
savedPinnedEvent: SavedPinnedEvent,
|
||||
savedPinnedEvent: BarePinnedEvent,
|
||||
userInfo: AuthenticatedUser | null
|
||||
) => {
|
||||
const dateNow = new Date().valueOf();
|
||||
|
|
|
@ -15,8 +15,8 @@ import {
|
|||
import type { AuthenticatedUser } from '@kbn/security-plugin/server';
|
||||
|
||||
import { UNAUTHENTICATED_USER } from '../../../../../common/constants';
|
||||
import type { NoteSavedObject } from '../../../../../common/types/timeline/note';
|
||||
import type { PinnedEventSavedObject } from '../../../../../common/types/timeline/pinned_event';
|
||||
import type { Note } from '../../../../../common/types/timeline/note/api';
|
||||
import type { PinnedEvent } from '../../../../../common/types/timeline/pinned_event/api';
|
||||
import type {
|
||||
AllTimelinesResponse,
|
||||
ExportTimelineNotFoundError,
|
||||
|
@ -684,8 +684,8 @@ const getAllSavedTimeline = async (request: FrameworkRequest, options: SavedObje
|
|||
export const convertStringToBase64 = (text: string): string => Buffer.from(text).toString('base64');
|
||||
|
||||
export const timelineWithReduxProperties = (
|
||||
notes: NoteSavedObject[],
|
||||
pinnedEvents: PinnedEventSavedObject[],
|
||||
notes: Note[],
|
||||
pinnedEvents: PinnedEvent[],
|
||||
timeline: TimelineSavedObject,
|
||||
userName: string
|
||||
): TimelineSavedObject => ({
|
||||
|
|
|
@ -9,7 +9,7 @@ import type { AuthenticatedUser } from '@kbn/security-plugin/common/model';
|
|||
|
||||
import type { SavedTimeline } from '../../../../../common/types/timeline/api';
|
||||
import { TimelineStatus, TimelineType } from '../../../../../common/types/timeline/api';
|
||||
import type { NoteSavedObject } from '../../../../../common/types/timeline/note';
|
||||
import type { Note } from '../../../../../common/types/timeline/note/api';
|
||||
|
||||
import { pickSavedTimeline } from './pick_saved_timeline';
|
||||
|
||||
|
@ -18,8 +18,8 @@ describe('pickSavedTimeline', () => {
|
|||
const getMockSavedTimeline = (): SavedTimeline & {
|
||||
savedObjectId?: string | null;
|
||||
version?: string;
|
||||
eventNotes?: NoteSavedObject[];
|
||||
globalNotes?: NoteSavedObject[];
|
||||
eventNotes?: Note[];
|
||||
globalNotes?: Note[];
|
||||
pinnedEventIds?: [];
|
||||
} => ({
|
||||
savedObjectId: '7af80430-03f4-11eb-9d9d-ffba20fabba8',
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
|
||||
import * as runtimeTypes from 'io-ts';
|
||||
import { unionWithNullType } from '../../../../../common/utility_types';
|
||||
import { NoteServerRepresentation } from '../../../../../common/types/timeline/note';
|
||||
import { BareNoteSchema } from '../../../../../common/types/timeline/note/api';
|
||||
|
||||
export const eventNotes = unionWithNullType(runtimeTypes.array(NoteServerRepresentation));
|
||||
export const globalNotes = unionWithNullType(runtimeTypes.array(NoteServerRepresentation));
|
||||
export const eventNotes = unionWithNullType(runtimeTypes.array(BareNoteSchema));
|
||||
export const globalNotes = unionWithNullType(runtimeTypes.array(BareNoteSchema));
|
||||
|
||||
export const persistNoteSchema = runtimeTypes.intersection([
|
||||
runtimeTypes.type({
|
||||
note: NoteServerRepresentation,
|
||||
note: BareNoteSchema,
|
||||
}),
|
||||
runtimeTypes.partial({
|
||||
overrideOwner: unionWithNullType(runtimeTypes.boolean),
|
||||
|
|
|
@ -12,9 +12,9 @@ import {
|
|||
timelineSavedObjectType,
|
||||
} from '@kbn/security-solution-plugin/server/lib/timeline/saved_object_mappings';
|
||||
import { TimelineWithoutExternalRefs } from '@kbn/security-solution-plugin/common/types/timeline/api';
|
||||
import { NoteWithoutExternalRefs } from '@kbn/security-solution-plugin/common/types/timeline/note';
|
||||
import { BareNoteWithoutExternalRefs } from '@kbn/security-solution-plugin/common/types/timeline/note/api';
|
||||
|
||||
import { PinnedEventWithoutExternalRefs } from '@kbn/security-solution-plugin/common/types/timeline/pinned_event';
|
||||
import { BarePinnedEventWithoutExternalRefs } from '@kbn/security-solution-plugin/common/types/timeline/pinned_event/api';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { getSavedObjectFromES } from './utils';
|
||||
|
||||
|
@ -23,11 +23,11 @@ interface TimelineWithoutSavedQueryId {
|
|||
}
|
||||
|
||||
interface NoteWithoutTimelineId {
|
||||
[noteSavedObjectType]: NoteWithoutExternalRefs;
|
||||
[noteSavedObjectType]: BareNoteWithoutExternalRefs;
|
||||
}
|
||||
|
||||
interface PinnedEventWithoutTimelineId {
|
||||
[pinnedEventSavedObjectType]: PinnedEventWithoutExternalRefs;
|
||||
[pinnedEventSavedObjectType]: BarePinnedEventWithoutExternalRefs;
|
||||
}
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue