From ed3d037759309a6fb27d4b20850c51e961cd5fca Mon Sep 17 00:00:00 2001 From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com> Date: Wed, 26 Apr 2023 11:47:39 -0400 Subject: [PATCH] [Cases] Separating http request contract from saved object persistence layer (#155325) This PR separates the http API io-ts types from the types that are used in the cases service layer to interact with the saved object client. This PR is specifically for the user actions it only affects the types used when interacting with the saved object client and doesn't touch the transformation logic yet. Issue: https://github.com/elastic/kibana/issues/153726 --- .../plugins/cases/server/common/types/user.ts | 2 +- .../cases/server/common/types/user_actions.ts | 20 +++ .../server/services/user_actions/index.ts | 160 ++++-------------- .../user_actions/operations/create.ts | 71 ++------ .../services/user_actions/operations/find.ts | 34 ++-- .../server/services/user_actions/transform.ts | 14 +- .../server/services/user_actions/types.ts | 152 +++++++++++++++-- 7 files changed, 235 insertions(+), 218 deletions(-) create mode 100644 x-pack/plugins/cases/server/common/types/user_actions.ts diff --git a/x-pack/plugins/cases/server/common/types/user.ts b/x-pack/plugins/cases/server/common/types/user.ts index 34e5e226517e07..fa32986ef8d979 100644 --- a/x-pack/plugins/cases/server/common/types/user.ts +++ b/x-pack/plugins/cases/server/common/types/user.ts @@ -9,7 +9,7 @@ export interface User { email: string | null | undefined; full_name: string | null | undefined; username: string | null | undefined; - profile_uid?: string | undefined; + profile_uid?: string; } export interface UserProfile { diff --git a/x-pack/plugins/cases/server/common/types/user_actions.ts b/x-pack/plugins/cases/server/common/types/user_actions.ts new file mode 100644 index 00000000000000..bc5366a2adaa83 --- /dev/null +++ b/x-pack/plugins/cases/server/common/types/user_actions.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +import type { User } from './user'; + +interface UserActionCommonPersistedAttributes { + action: string; + created_at: string; + created_by: User; + owner: string; +} + +export interface UserActionPersistedAttributes extends UserActionCommonPersistedAttributes { + type: string; + payload: Record; +} diff --git a/x-pack/plugins/cases/server/services/user_actions/index.ts b/x-pack/plugins/cases/server/services/user_actions/index.ts index 252e3985a74836..167f0e123fb077 100644 --- a/x-pack/plugins/cases/server/services/user_actions/index.ts +++ b/x-pack/plugins/cases/server/services/user_actions/index.ts @@ -5,20 +5,13 @@ * 2.0. */ -import type { - SavedObject, - SavedObjectReference, - SavedObjectsFindResponse, - SavedObjectsRawDoc, -} from '@kbn/core/server'; +import type { SavedObject, SavedObjectsFindResponse, SavedObjectsRawDoc } from '@kbn/core/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { KueryNode } from '@kbn/es-query'; import type { - CaseUserActionAttributesWithoutConnectorId, CaseUserActionDeprecatedResponse, CaseUserActionInjectedAttributes, - User, } from '../../../common/api'; import { ActionTypes } from '../../../common/api'; import { @@ -30,97 +23,22 @@ import { buildFilter, combineFilters } from '../../client/utils'; import type { CaseConnectorActivity, CaseConnectorFields, + ConnectorActivityAggsResult, + ConnectorFieldsBeforePushAggsResult, + GetUsersResponse, + ParticipantsAggsResult, PushInfo, PushTimeFrameInfo, ServiceContext, + TimeFrameInfo, + TopHits, + UserActionsStatsAggsResult, } from './types'; import { defaultSortField } from '../../common/utils'; import { UserActionPersister } from './operations/create'; import { UserActionFinder } from './operations/find'; import { transformToExternalModel, legacyTransformFindResponseToExternalModel } from './transform'; - -export interface UserActionItem { - attributes: CaseUserActionAttributesWithoutConnectorId; - references: SavedObjectReference[]; -} - -interface TopHits { - hits: { - total: number; - hits: SavedObjectsRawDoc[]; - }; -} - -interface TimeFrameInfo { - mostRecent: TopHits; - oldest: TopHits; -} - -interface ConnectorActivityAggsResult { - references: { - connectors: { - ids: { - buckets: Array<{ - key: string; - reverse: { - connectorActivity: { - buckets: { - changeConnector: TimeFrameInfo; - createCase: TimeFrameInfo; - pushInfo: TimeFrameInfo; - }; - }; - }; - }>; - }; - }; - }; -} - -interface ConnectorFieldsBeforePushAggsResult { - references: { - connectors: { - reverse: { - ids: { - buckets: Record; - }; - }; - }; - }; -} - -interface UserActionsStatsAggsResult { - total: number; - totals: { - buckets: Array<{ - key: string; - doc_count: number; - }>; - }; -} - -interface ParticipantsAggsResult { - participants: { - buckets: Array<{ - key: string; - docs: { - hits: { - hits: SavedObjectsRawDoc[]; - }; - }; - }>; - }; - assignees: { - buckets: Array<{ - key: string; - }>; - }; -} - -interface GetUsersResponse { - participants: Array<{ id: string; owner: string; user: User }>; - assignedAndUnassignedUsers: Set; -} +import type { UserActionPersistedAttributes } from '../../common/types/user_actions'; export class CaseUserActionService { private readonly _creator: UserActionPersister; @@ -160,7 +78,7 @@ export class CaseUserActionService { }); const response = await this.context.unsecuredSavedObjectsClient.find< - CaseUserActionAttributesWithoutConnectorId, + UserActionPersistedAttributes, ConnectorFieldsBeforePushAggsResult >({ type: CASE_USER_ACTION_SAVED_OBJECT, @@ -286,7 +204,7 @@ export class CaseUserActionService { if (fields.mostRecent.hits.hits.length > 0) { const rawFieldsDoc = fields.mostRecent.hits.hits[0]; const doc = - this.context.savedObjectsSerializer.rawToSavedObject( + this.context.savedObjectsSerializer.rawToSavedObject( rawFieldsDoc ); @@ -326,17 +244,15 @@ export class CaseUserActionService { }); const userActions = - await this.context.unsecuredSavedObjectsClient.find( - { - type: CASE_USER_ACTION_SAVED_OBJECT, - hasReference: { type, id }, - page: 1, - perPage: 1, - sortField: 'created_at', - sortOrder: 'desc', - filter: connectorsFilter, - } - ); + await this.context.unsecuredSavedObjectsClient.find({ + type: CASE_USER_ACTION_SAVED_OBJECT, + hasReference: { type, id }, + page: 1, + perPage: 1, + sortField: 'created_at', + sortOrder: 'desc', + filter: connectorsFilter, + }); if (userActions.saved_objects.length <= 0) { return; @@ -366,7 +282,7 @@ export class CaseUserActionService { }); const response = await this.context.unsecuredSavedObjectsClient.find< - CaseUserActionAttributesWithoutConnectorId, + UserActionPersistedAttributes, ConnectorActivityAggsResult >({ type: CASE_USER_ACTION_SAVED_OBJECT, @@ -414,7 +330,7 @@ export class CaseUserActionService { let fieldsDoc: SavedObject | undefined; if (rawFieldsDoc != null) { const doc = - this.context.savedObjectsSerializer.rawToSavedObject( + this.context.savedObjectsSerializer.rawToSavedObject( rawFieldsDoc ); @@ -459,7 +375,7 @@ export class CaseUserActionService { const rawPushDoc = topHits.hits.hits[0]; const doc = - this.context.savedObjectsSerializer.rawToSavedObject( + this.context.savedObjectsSerializer.rawToSavedObject( rawPushDoc ); @@ -568,16 +484,14 @@ export class CaseUserActionService { const type = CASE_SAVED_OBJECT; const userActions = - await this.context.unsecuredSavedObjectsClient.find( - { - type: CASE_USER_ACTION_SAVED_OBJECT, - hasReference: { type, id }, - page: 1, - perPage: MAX_DOCS_PER_PAGE, - sortField: 'created_at', - sortOrder: 'asc', - } - ); + await this.context.unsecuredSavedObjectsClient.find({ + type: CASE_USER_ACTION_SAVED_OBJECT, + hasReference: { type, id }, + page: 1, + perPage: MAX_DOCS_PER_PAGE, + sortField: 'created_at', + sortOrder: 'asc', + }); return legacyTransformFindResponseToExternalModel( userActions, @@ -595,6 +509,8 @@ export class CaseUserActionService { `Attempting to retrieve user actions associated with cases: [${caseIds}]` ); + // We are intentionally not adding the type here because we only want to interact with the id and this function + // should not use the attributes const finder = this.context.unsecuredSavedObjectsClient.createPointInTimeFinder({ type: CASE_USER_ACTION_SAVED_OBJECT, hasReference: caseIds.map((id) => ({ id, type: CASE_SAVED_OBJECT })), @@ -640,7 +556,7 @@ export class CaseUserActionService { const combinedFilter = combineFilters([connectorsFilter, filter]); const response = await this.context.unsecuredSavedObjectsClient.find< - CaseUserActionAttributesWithoutConnectorId, + UserActionPersistedAttributes, { references: { connectors: { ids: { buckets: Array<{ key: string }> } } } } >({ type: CASE_USER_ACTION_SAVED_OBJECT, @@ -698,7 +614,7 @@ export class CaseUserActionService { public async getCaseUserActionStats({ caseId }: { caseId: string }) { const response = await this.context.unsecuredSavedObjectsClient.find< - CaseUserActionAttributesWithoutConnectorId, + UserActionPersistedAttributes, UserActionsStatsAggsResult >({ type: CASE_USER_ACTION_SAVED_OBJECT, @@ -742,7 +658,7 @@ export class CaseUserActionService { public async getUsers({ caseId }: { caseId: string }): Promise { const response = await this.context.unsecuredSavedObjectsClient.find< - CaseUserActionAttributesWithoutConnectorId, + UserActionPersistedAttributes, ParticipantsAggsResult >({ type: CASE_USER_ACTION_SAVED_OBJECT, @@ -762,9 +678,7 @@ export class CaseUserActionService { for (const bucket of participantsBuckets) { const rawDoc = bucket.docs.hits.hits[0]; const user = - this.context.savedObjectsSerializer.rawToSavedObject( - rawDoc - ); + this.context.savedObjectsSerializer.rawToSavedObject(rawDoc); /** * We are interested only for the created_by diff --git a/x-pack/plugins/cases/server/services/user_actions/operations/create.ts b/x-pack/plugins/cases/server/services/user_actions/operations/create.ts index 351fbb9326a9ea..25096baddf479a 100644 --- a/x-pack/plugins/cases/server/services/user_actions/operations/create.ts +++ b/x-pack/plugins/cases/server/services/user_actions/operations/create.ts @@ -5,81 +5,38 @@ * 2.0. */ -import type { - SavedObject, - SavedObjectReference, - SavedObjectsBulkResponse, - SavedObjectsUpdateResponse, -} from '@kbn/core/server'; +import type { SavedObject, SavedObjectsBulkResponse } from '@kbn/core/server'; import { get, isEmpty } from 'lodash'; -import type { CaseSavedObjectTransformed } from '../../../common/types/case'; +import type { UserActionPersistedAttributes } from '../../../common/types/user_actions'; import { CASE_SAVED_OBJECT, CASE_USER_ACTION_SAVED_OBJECT } from '../../../../common/constants'; import { arraysDifference } from '../../../client/utils'; import { isUserActionType } from '../../../../common/utils/user_actions'; import type { ActionTypeValues, CaseAssignees, - CaseAttributes, CaseUserProfile, - CommentRequest, - User, UserAction as Action, } from '../../../../common/api'; import { Actions, ActionTypes } from '../../../../common/api'; import { BuilderFactory } from '../builder_factory'; import type { - Attributes, BuilderParameters, - CommonArguments, - CreateUserAction, + BulkCreateAttachmentUserAction, + BulkCreateBulkUpdateCaseUserActions, + CommonUserActionArgs, + CreatePayloadFunction, + CreateUserActionClient, + CreateUserActionES, + GetUserActionItemByDifference, + PostCaseUserActionArgs, ServiceContext, + TypedUserActionDiffedItems, UserActionEvent, - UserActionParameters, } from '../types'; import { isAssigneesArray, isStringArray } from '../type_guards'; import type { IndexRefresh } from '../../types'; import { UserActionAuditLogger } from '../audit_logger'; -type CommonUserActionArgs = CommonArguments; - -interface GetUserActionItemByDifference extends CommonUserActionArgs { - field: string; - originalValue: unknown; - newValue: unknown; -} - -interface TypedUserActionDiffedItems extends GetUserActionItemByDifference { - originalValue: T[]; - newValue: T[]; -} - -type CreatePayloadFunction = ( - items: Item[] -) => UserActionParameters['payload']; - -interface BulkCreateBulkUpdateCaseUserActions extends IndexRefresh { - originalCases: CaseSavedObjectTransformed[]; - updatedCases: Array>; - user: User; -} - -interface BulkCreateAttachmentUserAction extends Omit, IndexRefresh { - attachments: Array<{ id: string; owner: string; attachment: CommentRequest }>; -} - -type CreateUserActionClient = CreateUserAction & - CommonUserActionArgs & - IndexRefresh; - -interface CreateUserActionES extends IndexRefresh { - attributes: T; - references: SavedObjectReference[]; -} - -interface PostCaseUserActionArgs extends IndexRefresh { - actions: UserActionEvent[]; -} - export class UserActionPersister { private static readonly userActionFieldsAllowed: Set = new Set(Object.keys(ActionTypes)); @@ -335,7 +292,9 @@ export class UserActionPersister { private async bulkCreate({ actions, refresh, - }: PostCaseUserActionArgs): Promise | undefined> { + }: PostCaseUserActionArgs): Promise< + SavedObjectsBulkResponse | undefined + > { if (isEmpty(actions)) { return; } @@ -343,7 +302,7 @@ export class UserActionPersister { try { this.context.log.debug(`Attempting to POST a new case user action`); - return await this.context.unsecuredSavedObjectsClient.bulkCreate( + return await this.context.unsecuredSavedObjectsClient.bulkCreate( actions.map((action) => ({ type: CASE_USER_ACTION_SAVED_OBJECT, ...action.parameters, diff --git a/x-pack/plugins/cases/server/services/user_actions/operations/find.ts b/x-pack/plugins/cases/server/services/user_actions/operations/find.ts index b04cb76f3022c8..5ce99d41a5ed26 100644 --- a/x-pack/plugins/cases/server/services/user_actions/operations/find.ts +++ b/x-pack/plugins/cases/server/services/user_actions/operations/find.ts @@ -8,12 +8,10 @@ import type { KueryNode } from '@kbn/es-query'; import { fromKueryExpression } from '@kbn/es-query'; import type { SavedObjectsFindResponse } from '@kbn/core-saved-objects-api-server'; -import type { SavedObject } from '@kbn/core-saved-objects-common'; +import type { SavedObject } from '@kbn/core-saved-objects-server'; import { DEFAULT_PAGE, DEFAULT_PER_PAGE } from '../../../routes/api'; import { defaultSortField } from '../../../common/utils'; import type { - CaseUserActionAttributesWithoutConnectorId, - UserActionFindRequest, ActionTypeValues, FindTypeField, CaseUserActionInjectedAttributes, @@ -25,14 +23,10 @@ import { MAX_DOCS_PER_PAGE, } from '../../../../common/constants'; -import type { ServiceContext } from '../types'; +import type { FindOptions, ServiceContext } from '../types'; import { transformFindResponseToExternalModel, transformToExternalModel } from '../transform'; import { buildFilter, combineFilters, NodeBuilderOperators } from '../../../client/utils'; - -interface FindOptions extends UserActionFindRequest { - caseId: string; - filter?: KueryNode; -} +import type { UserActionPersistedAttributes } from '../../../common/types/user_actions'; export class UserActionFinder { constructor(private readonly context: ServiceContext) {} @@ -51,17 +45,15 @@ export class UserActionFinder { const finalFilter = combineFilters([filter, UserActionFinder.buildFilter(types)]); const userActions = - await this.context.unsecuredSavedObjectsClient.find( - { - type: CASE_USER_ACTION_SAVED_OBJECT, - hasReference: { type: CASE_SAVED_OBJECT, id: caseId }, - page: page ?? DEFAULT_PAGE, - perPage: perPage ?? DEFAULT_PER_PAGE, - sortField: 'created_at', - sortOrder: sortOrder ?? 'asc', - filter: finalFilter, - } - ); + await this.context.unsecuredSavedObjectsClient.find({ + type: CASE_USER_ACTION_SAVED_OBJECT, + hasReference: { type: CASE_SAVED_OBJECT, id: caseId }, + page: page ?? DEFAULT_PAGE, + perPage: perPage ?? DEFAULT_PER_PAGE, + sortField: 'created_at', + sortOrder: sortOrder ?? 'asc', + filter: finalFilter, + }); return transformFindResponseToExternalModel( userActions, @@ -197,7 +189,7 @@ export class UserActionFinder { const combinedFilters = combineFilters([updateActionFilter, statusChangeFilter, filter]); const finder = - this.context.unsecuredSavedObjectsClient.createPointInTimeFinder( + this.context.unsecuredSavedObjectsClient.createPointInTimeFinder( { type: CASE_USER_ACTION_SAVED_OBJECT, hasReference: { type: CASE_SAVED_OBJECT, id: caseId }, diff --git a/x-pack/plugins/cases/server/services/user_actions/transform.ts b/x-pack/plugins/cases/server/services/user_actions/transform.ts index 439e57eed386d1..1efc991cc59ac5 100644 --- a/x-pack/plugins/cases/server/services/user_actions/transform.ts +++ b/x-pack/plugins/cases/server/services/user_actions/transform.ts @@ -16,7 +16,6 @@ import { } from '../../../common/utils/user_actions'; import type { CaseUserActionAttributes, - CaseUserActionAttributesWithoutConnectorId, CaseUserActionDeprecatedResponse, CaseUserActionInjectedAttributes, } from '../../../common/api'; @@ -34,9 +33,10 @@ import { isCommentRequestTypeExternalReferenceSO } from '../../common/utils'; import type { PersistableStateAttachmentTypeRegistry } from '../../attachment_framework/persistable_state_registry'; import { injectPersistableReferencesToSO } from '../../attachment_framework/so_references'; import { findReferenceId } from '../../common/references'; +import type { UserActionPersistedAttributes } from '../../common/types/user_actions'; export function transformFindResponseToExternalModel( - userActions: SavedObjectsFindResponse, + userActions: SavedObjectsFindResponse, persistableStateAttachmentTypeRegistry: PersistableStateAttachmentTypeRegistry ): SavedObjectsFindResponse { return { @@ -49,7 +49,7 @@ export function transformFindResponseToExternalModel( } export function transformToExternalModel( - userAction: SavedObject, + userAction: SavedObject, persistableStateAttachmentTypeRegistry: PersistableStateAttachmentTypeRegistry ): SavedObject { const { references } = userAction; @@ -75,7 +75,7 @@ export function transformToExternalModel( * @deprecated remove when the getAllRoute is removed */ export function legacyTransformFindResponseToExternalModel( - userActions: SavedObjectsFindResponse, + userActions: SavedObjectsFindResponse, persistableStateAttachmentTypeRegistry: PersistableStateAttachmentTypeRegistry ): SavedObjectsFindResponse { return { @@ -91,7 +91,7 @@ export function legacyTransformFindResponseToExternalModel( * @deprecated remove when the getAll route is removed */ function legacyTransformToExternalModel( - userAction: SavedObject, + userAction: SavedObject, persistableStateAttachmentTypeRegistry: PersistableStateAttachmentTypeRegistry ): SavedObject { const { references } = userAction; @@ -114,7 +114,7 @@ function legacyTransformToExternalModel( } const addReferenceIdToPayload = ( - userAction: SavedObject, + userAction: SavedObject, persistableStateAttachmentTypeRegistry: PersistableStateAttachmentTypeRegistry ): CaseUserActionAttributes['payload'] => { const connectorId = getConnectorIdFromReferences(userAction); @@ -176,7 +176,7 @@ const addReferenceIdToPayload = ( }; function getConnectorIdFromReferences( - userAction: SavedObject + userAction: SavedObject ): string | null { const { references } = userAction; diff --git a/x-pack/plugins/cases/server/services/user_actions/types.ts b/x-pack/plugins/cases/server/services/user_actions/types.ts index 4d9813c42591d8..f88bd2ba3fe155 100644 --- a/x-pack/plugins/cases/server/services/user_actions/types.ts +++ b/x-pack/plugins/cases/server/services/user_actions/types.ts @@ -11,23 +11,34 @@ import type { Logger, ISavedObjectsSerializer, SavedObject, + SavedObjectsRawDoc, + SavedObjectsUpdateResponse, } from '@kbn/core/server'; +import type { KueryNode } from '@kbn/es-query'; import type { AuditLogger } from '@kbn/security-plugin/server'; import type { CaseAssignees } from '../../../common/api/cases/assignee'; import type { + ActionTypeValues, + CaseAttributes, CasePostRequest, CaseSettings, CaseSeverity, CaseStatuses, + CaseUserActionAttributesWithoutConnectorId, CaseUserActionInjectedAttributes, + CommentRequest, CommentUserAction, ConnectorUserAction, PushedUserAction, User, UserAction, + UserActionFindRequest, UserActionTypes, } from '../../../common/api'; import type { PersistableStateAttachmentTypeRegistry } from '../../attachment_framework/persistable_state_registry'; +import type { UserActionPersistedAttributes } from '../../common/types/user_actions'; +import type { IndexRefresh } from '../types'; +import type { CaseSavedObjectTransformed } from '../../common/types/case'; export interface BuilderParameters { title: { @@ -97,17 +108,8 @@ export interface CommonArguments { action?: UserAction; } -export interface Attributes { - action: UserAction; - created_at: string; - created_by: User; - owner: string; - type: UserActionTypes; - payload: Record; -} - export interface SavedObjectParameters { - attributes: Attributes; + attributes: UserActionPersistedAttributes; references: SavedObjectReference[]; } @@ -160,3 +162,133 @@ export interface PushInfo { date: Date; connectorId: string; } + +export interface UserActionItem { + attributes: CaseUserActionAttributesWithoutConnectorId; + references: SavedObjectReference[]; +} + +export interface TopHits { + hits: { + total: number; + hits: SavedObjectsRawDoc[]; + }; +} + +export interface TimeFrameInfo { + mostRecent: TopHits; + oldest: TopHits; +} + +export interface ConnectorActivityAggsResult { + references: { + connectors: { + ids: { + buckets: Array<{ + key: string; + reverse: { + connectorActivity: { + buckets: { + changeConnector: TimeFrameInfo; + createCase: TimeFrameInfo; + pushInfo: TimeFrameInfo; + }; + }; + }; + }>; + }; + }; + }; +} + +export interface ConnectorFieldsBeforePushAggsResult { + references: { + connectors: { + reverse: { + ids: { + buckets: Record; + }; + }; + }; + }; +} + +export interface UserActionsStatsAggsResult { + total: number; + totals: { + buckets: Array<{ + key: string; + doc_count: number; + }>; + }; +} + +export interface ParticipantsAggsResult { + participants: { + buckets: Array<{ + key: string; + docs: { + hits: { + hits: SavedObjectsRawDoc[]; + }; + }; + }>; + }; + assignees: { + buckets: Array<{ + key: string; + }>; + }; +} + +export interface GetUsersResponse { + participants: Array<{ id: string; owner: string; user: User }>; + assignedAndUnassignedUsers: Set; +} + +export interface FindOptions extends UserActionFindRequest { + caseId: string; + filter?: KueryNode; +} + +export type CommonUserActionArgs = CommonArguments; + +export interface GetUserActionItemByDifference extends CommonUserActionArgs { + field: string; + originalValue: unknown; + newValue: unknown; +} + +export interface TypedUserActionDiffedItems extends GetUserActionItemByDifference { + originalValue: T[]; + newValue: T[]; +} + +export type CreatePayloadFunction = ( + items: Item[] +) => UserActionParameters['payload']; + +export interface BulkCreateBulkUpdateCaseUserActions extends IndexRefresh { + originalCases: CaseSavedObjectTransformed[]; + updatedCases: Array>; + user: User; +} + +export interface BulkCreateAttachmentUserAction + extends Omit, + IndexRefresh { + attachments: Array<{ id: string; owner: string; attachment: CommentRequest }>; +} + +export type CreateUserActionClient = CreateUserAction & + CommonUserActionArgs & + IndexRefresh; + +export interface CreateUserActionES extends IndexRefresh { + attributes: T; + references: SavedObjectReference[]; +} + +export interface PostCaseUserActionArgs extends IndexRefresh { + actions: UserActionEvent[]; +}