Skip to content

Commit

Permalink
[SecuritySolution] Decouple more timeline saved objects types from th…
Browse files Browse the repository at this point in the history
…eir API representations (#159398)

## Summary

Continuation of #158566. Tracked
in elastic/security-team#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
  • Loading branch information
janmonschke committed Jun 13, 2023
1 parent 160fa42 commit 0c4906a
Show file tree
Hide file tree
Showing 30 changed files with 420 additions and 378 deletions.
22 changes: 11 additions & 11 deletions x-pack/plugins/security_solution/common/types/timeline/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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),
}),
]);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -606,15 +606,15 @@ 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[]>;
filters?: Maybe<FilterTimelineResult[]>;
kqlMode?: Maybe<string>;
kqlQuery?: Maybe<SerializedFilterQueryResult>;
indexNames?: Maybe<string[]>;
notes?: Maybe<NoteResult[]>;
notes?: Maybe<Note[]>;
noteIds?: Maybe<string[]>;
pinnedEventIds?: Maybe<string[]>;
pinnedEventsSaveObject?: Maybe<PinnedEvent[]>;
Expand Down
56 changes: 56 additions & 0 deletions x-pack/plugins/security_solution/common/types/timeline/note/api.ts
Original file line number Diff line number Diff line change
@@ -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;
}
150 changes: 0 additions & 150 deletions x-pack/plugins/security_solution/common/types/timeline/note/index.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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'>;
Original file line number Diff line number Diff line change
@@ -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 };
Loading

0 comments on commit 0c4906a

Please sign in to comment.