From 6d5e2456d97ff6e531599fc8fb2fa760b330a244 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com> Date: Fri, 28 Apr 2023 08:31:21 -0400 Subject: [PATCH] [Cases] Separate Cases SO attributes from HTTP APIs (#155898) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR separates the persisted SO attributes from the fields received in the HTTP API requests. This is to address step 2 in preparing our HTTP routes as versioned. Issue: https://github.com/elastic/kibana/issues/153726 This PR encompasses a few PRs here which have been reviewed individually by the cases team members: https://github.com/elastic/kibana/pull/155325 - User actions https://github.com/elastic/kibana/pull/155440 - Attachments https://github.com/elastic/kibana/pull/155444 - Configure, Connector Mappings https://github.com/elastic/kibana/pull/155277 - Cases The large number of files is because of renaming some types throughout the frontend code. There shouldn't be many functionality changes, mostly just type changes. --------- Co-authored-by: Christos Nasikas Co-authored-by: Patryk KopyciƄski --- x-pack/plugins/cases/common/api/cases/case.ts | 30 +- .../plugins/cases/common/api/saved_object.ts | 2 - x-pack/plugins/cases/common/index.ts | 6 +- x-pack/plugins/cases/common/ui/types.ts | 10 +- x-pack/plugins/cases/public/api/decoders.ts | 8 +- x-pack/plugins/cases/public/api/index.ts | 8 +- x-pack/plugins/cases/public/api/utils.ts | 14 +- .../plugins/cases/public/client/api/index.ts | 4 +- .../client/attachment_framework/types.ts | 4 +- .../cases/public/common/use_cases_toast.tsx | 8 +- .../assignees/edit_assignees_flyout.tsx | 4 +- .../assignees/edit_assignees_selectable.tsx | 4 +- .../assignees/use_assignees_action.tsx | 6 +- .../actions/copy_id/use_copy_id_action.tsx | 4 +- .../actions/delete/use_delete_action.tsx | 8 +- .../actions/severity/use_severity_action.tsx | 10 +- .../actions/status/use_status_action.tsx | 10 +- .../actions/tags/edit_tags_flyout.tsx | 4 +- .../actions/tags/edit_tags_selectable.tsx | 4 +- .../actions/tags/use_tags_action.tsx | 6 +- .../components/actions/use_items_action.tsx | 8 +- .../components/actions/use_items_state.tsx | 10 +- .../public/components/add_comment/index.tsx | 4 +- .../components/all_cases/all_cases_list.tsx | 10 +- .../components/all_cases/assignees_column.tsx | 4 +- .../all_cases_selector_modal.tsx | 6 +- ..._cases_add_to_existing_case_modal.test.tsx | 14 +- .../use_cases_add_to_existing_case_modal.tsx | 14 +- .../public/components/all_cases/table.tsx | 16 +- .../components/all_cases/use_actions.tsx | 8 +- .../components/all_cases/use_bulk_actions.tsx | 4 +- .../all_cases/use_cases_columns.tsx | 38 +- .../components/all_cases/utility_bar.tsx | 4 +- .../components/case_action_bar/actions.tsx | 6 +- .../components/case_action_bar/helpers.ts | 4 +- .../components/case_action_bar/index.tsx | 4 +- .../components/case_view/case_view_tabs.tsx | 4 +- .../components/case_view_activity.test.tsx | 4 +- .../components/case_view_activity.tsx | 4 +- .../components/case_view_alerts.test.tsx | 6 +- .../case_view/components/case_view_alerts.tsx | 4 +- .../components/case_view_files.test.tsx | 4 +- .../case_view/components/case_view_files.tsx | 4 +- .../case_view/components/user_list.tsx | 4 +- .../public/components/case_view/mocks.ts | 4 +- .../public/components/case_view/types.ts | 8 +- .../case_view/use_on_update_field.ts | 4 +- .../create/flyout/create_case_flyout.tsx | 6 +- .../use_cases_add_to_new_case_flyout.tsx | 4 +- .../cases/public/components/create/form.tsx | 8 +- .../public/components/create/form_context.tsx | 6 +- .../public/components/description/index.tsx | 4 +- .../components/edit_connector/index.tsx | 4 +- .../create_case_modal.tsx | 4 +- .../use_create_case_modal/index.tsx | 4 +- .../public/components/user_actions/types.ts | 6 +- .../user_actions/use_user_actions_handler.tsx | 4 +- .../cases/public/containers/__mocks__/api.ts | 20 +- x-pack/plugins/cases/public/containers/api.ts | 55 ++- .../plugins/cases/public/containers/mock.ts | 33 +- .../containers/use_create_attachments.tsx | 4 +- .../cases/public/containers/use_get_cases.tsx | 6 +- .../containers/use_post_push_to_service.tsx | 4 +- .../cases/public/containers/utils.test.ts | 6 +- .../plugins/cases/public/containers/utils.ts | 22 +- x-pack/plugins/cases/public/types.ts | 8 +- .../cases/server/client/attachments/add.ts | 7 +- .../server/client/attachments/bulk_create.ts | 4 +- .../cases/server/client/attachments/client.ts | 8 +- .../cases/server/client/attachments/update.ts | 4 +- .../server/client/cases/bulk_get.test.ts | 8 +- .../cases/server/client/cases/bulk_get.ts | 18 +- .../cases/server/client/cases/client.ts | 4 +- .../cases/server/client/cases/create.ts | 11 +- .../cases/server/client/cases/find.test.ts | 4 +- .../plugins/cases/server/client/cases/get.ts | 14 +- .../plugins/cases/server/client/cases/push.ts | 14 +- .../cases/server/client/cases/update.ts | 28 +- .../cases/server/client/cases/utils.ts | 16 +- .../client/metrics/actions/actions.test.ts | 4 +- .../client/metrics/alerts/count.test.ts | 4 +- .../client/metrics/all_cases/mttr.test.ts | 4 +- .../client/metrics/get_case_metrics.test.ts | 8 +- .../cases/server/client/typedoc_interfaces.ts | 8 +- .../plugins/cases/server/client/utils.test.ts | 16 +- .../plugins/cases/server/common/constants.ts | 38 +- .../common/models/case_with_comments.ts | 25 +- x-pack/plugins/cases/server/common/types.ts | 22 +- .../cases/server/common/types/attachments.ts | 48 +++ .../plugins/cases/server/common/types/case.ts | 52 +++ .../cases/server/common/types/configure.ts | 19 + .../server/common/types/connector_mappings.ts | 15 + .../cases/server/common/types/connectors.ts | 17 + .../server/common/types/external_service.ts | 17 + .../plugins/cases/server/common/types/user.ts | 17 + .../cases/server/common/types/user_actions.ts | 20 ++ .../plugins/cases/server/common/utils.test.ts | 4 +- x-pack/plugins/cases/server/common/utils.ts | 28 +- .../server/connectors/jira/format.test.ts | 6 +- .../connectors/resilient/format.test.ts | 6 +- .../connectors/servicenow/itsm_format.test.ts | 6 +- .../connectors/servicenow/sir_format.test.ts | 8 +- .../server/connectors/swimlane/format.test.ts | 4 +- .../plugins/cases/server/connectors/types.ts | 4 +- x-pack/plugins/cases/server/mocks.ts | 4 +- .../cases/server/saved_object_types/cases.ts | 6 +- .../import_export/export.ts | 8 +- .../migrations/cases.test.ts | 20 +- .../saved_object_types/migrations/cases.ts | 17 +- .../saved_object_types/migrations/comments.ts | 10 +- .../migrations/configuration.test.ts | 10 +- .../server/services/attachments/index.ts | 78 +---- .../services/attachments/operations/get.ts | 63 ++-- .../server/services/attachments/types.ts | 60 ++++ .../cases/server/services/cases/index.test.ts | 331 ++++++++++-------- .../cases/server/services/cases/index.ts | 188 ++++------ .../server/services/cases/transform.test.ts | 44 +-- .../cases/server/services/cases/transform.ts | 48 +-- .../cases/server/services/cases/types.ts | 131 ++++--- .../server/services/configure/index.test.ts | 36 +- .../cases/server/services/configure/index.ts | 65 ++-- .../cases/server/services/configure/types.ts | 35 +- .../services/connector_mappings/index.ts | 93 ++--- .../services/connector_mappings/types.ts | 30 ++ x-pack/plugins/cases/server/services/index.ts | 12 - .../email_notification_service.ts | 6 +- .../server/services/notifications/types.ts | 4 +- .../cases/server/services/so_references.ts | 39 ++- .../cases/server/services/test_utils.ts | 21 +- .../cases/server/services/transform.ts | 12 +- .../cases/server/services/type_guards.ts | 22 ++ .../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 | 16 +- .../server/services/user_actions/types.ts | 152 +++++++- .../server/telemetry/queries/cases.test.ts | 4 +- .../cases/server/telemetry/queries/cases.ts | 15 +- .../exploratory_view/hooks/use_add_to_case.ts | 8 +- .../osquery/cypress/tasks/api_fixtures.ts | 4 +- .../endpoint/data_loaders/index_case.ts | 6 +- .../management/cypress/tasks/api_fixtures.ts | 4 +- .../cases_table/use_case_items.ts | 5 +- .../flyout/add_to_case_button/index.tsx | 4 +- .../common/lib/alerts.ts | 4 +- .../common/lib/api/attachments.ts | 10 +- .../common/lib/api/case.ts | 4 +- .../common/lib/api/connectors.ts | 4 +- .../common/lib/api/index.ts | 26 +- .../common/lib/api/omit.ts | 8 +- .../cases_api_integration/common/lib/mock.ts | 4 +- .../common/lib/validation.ts | 4 +- .../tests/common/alerts/get_cases.ts | 6 +- .../tests/common/cases/find_cases.ts | 11 +- .../tests/common/cases/import_export.ts | 9 +- .../tests/common/cases/migrations.ts | 25 +- .../tests/common/cases/patch_cases.ts | 10 +- .../common/client/update_alert_status.ts | 4 +- .../internal/bulk_create_attachments.ts | 4 +- .../internal/bulk_delete_file_attachments.ts | 4 +- .../common/internal/bulk_get_attachments.ts | 8 +- .../common/user_actions/find_user_actions.ts | 10 +- .../user_actions/get_all_user_actions.ts | 4 +- .../user_actions/get_user_action_stats.ts | 9 +- x-pack/test/functional/services/cases/api.ts | 13 +- .../apps/cases/group2/attachment_framework.ts | 6 +- 166 files changed, 1720 insertions(+), 1449 deletions(-) create mode 100644 x-pack/plugins/cases/server/common/types/attachments.ts create mode 100644 x-pack/plugins/cases/server/common/types/case.ts create mode 100644 x-pack/plugins/cases/server/common/types/configure.ts create mode 100644 x-pack/plugins/cases/server/common/types/connector_mappings.ts create mode 100644 x-pack/plugins/cases/server/common/types/connectors.ts create mode 100644 x-pack/plugins/cases/server/common/types/external_service.ts create mode 100644 x-pack/plugins/cases/server/common/types/user.ts create mode 100644 x-pack/plugins/cases/server/common/types/user_actions.ts create mode 100644 x-pack/plugins/cases/server/services/connector_mappings/types.ts create mode 100644 x-pack/plugins/cases/server/services/type_guards.ts diff --git a/x-pack/plugins/cases/common/api/cases/case.ts b/x-pack/plugins/cases/common/api/cases/case.ts index 4eaf633fb98c7..17319a71732e1 100644 --- a/x-pack/plugins/cases/common/api/cases/case.ts +++ b/x-pack/plugins/cases/common/api/cases/case.ts @@ -249,7 +249,7 @@ export const CasesByAlertIDRequestRt = rt.partial({ owner: rt.union([rt.array(rt.string), rt.string]), }); -export const CaseResponseRt = rt.intersection([ +export const CaseRt = rt.intersection([ CaseAttributesRt, rt.type({ id: rt.string, @@ -264,7 +264,7 @@ export const CaseResponseRt = rt.intersection([ export const CaseResolveResponseRt = rt.intersection([ rt.type({ - case: CaseResponseRt, + case: CaseRt, outcome: rt.union([rt.literal('exactMatch'), rt.literal('aliasMatch'), rt.literal('conflict')]), }), rt.partial({ @@ -275,7 +275,7 @@ export const CaseResolveResponseRt = rt.intersection([ export const CasesFindResponseRt = rt.intersection([ rt.type({ - cases: rt.array(CaseResponseRt), + cases: rt.array(CaseRt), page: rt.number, per_page: rt.number, total: rt.number, @@ -292,7 +292,7 @@ export const CasePatchRequestRt = rt.intersection([ ]); export const CasesPatchRequestRt = rt.type({ cases: rt.array(CasePatchRequestRt) }); -export const CasesResponseRt = rt.array(CaseResponseRt); +export const CasesRt = rt.array(CaseRt); export const CasePushRequestParamsRt = rt.type({ case_id: rt.string, @@ -339,7 +339,7 @@ export const CasesBulkGetRequestRt = rt.intersection([ ]); export const CasesBulkGetResponseRt = rt.type({ - cases: CasesResponseRt, + cases: CasesRt, errors: rt.array( rt.type({ error: rt.string, @@ -353,9 +353,9 @@ export const CasesBulkGetResponseRt = rt.type({ export type CaseAttributes = rt.TypeOf; export type CasePostRequest = rt.TypeOf; -export type CaseResponse = rt.TypeOf; +export type Case = rt.TypeOf; export type CaseResolveResponse = rt.TypeOf; -export type CasesResponse = rt.TypeOf; +export type Cases = rt.TypeOf; export type CasesFindRequest = rt.TypeOf; export type CasesByAlertIDRequest = rt.TypeOf; export type CasesFindResponse = rt.TypeOf; @@ -375,13 +375,15 @@ export type CasesByAlertId = rt.TypeOf; export type CasesBulkGetRequest = rt.TypeOf; export type CasesBulkGetResponse = rt.TypeOf; -export type CasesBulkGetRequestCertainFields< - Field extends keyof CaseResponse = keyof CaseResponse -> = Omit & { +export type CasesBulkGetRequestCertainFields = Omit< + CasesBulkGetRequest, + 'fields' +> & { fields?: Field[]; }; -export type CasesBulkGetResponseCertainFields< - Field extends keyof CaseResponse = keyof CaseResponse -> = Omit & { - cases: Array>; +export type CasesBulkGetResponseCertainFields = Omit< + CasesBulkGetResponse, + 'cases' +> & { + cases: Array>; }; diff --git a/x-pack/plugins/cases/common/api/saved_object.ts b/x-pack/plugins/cases/common/api/saved_object.ts index 2ed6ec2acdfe4..44af143284bce 100644 --- a/x-pack/plugins/cases/common/api/saved_object.ts +++ b/x-pack/plugins/cases/common/api/saved_object.ts @@ -68,5 +68,3 @@ export const SavedObjectFindOptionsRt = rt.partial({ */ sortOrder: rt.union([rt.literal('desc'), rt.literal('asc')]), }); - -export type SavedObjectFindOptions = rt.TypeOf; diff --git a/x-pack/plugins/cases/common/index.ts b/x-pack/plugins/cases/common/index.ts index d41de5543654d..6483bba8ce4f2 100644 --- a/x-pack/plugins/cases/common/index.ts +++ b/x-pack/plugins/cases/common/index.ts @@ -38,13 +38,15 @@ export { } from './api'; export type { - CaseResponse, + Case, + Cases, CasesBulkGetRequestCertainFields, CasesBulkGetResponseCertainFields, } from './api'; export type { - Case, + CaseUI, + CasesUI, Ecs, CasesFeatures, CaseViewRefreshPropInterface, diff --git a/x-pack/plugins/cases/common/ui/types.ts b/x-pack/plugins/cases/common/ui/types.ts index e9bfcd0682f5b..c513f5a8e2337 100644 --- a/x-pack/plugins/cases/common/ui/types.ts +++ b/x-pack/plugins/cases/common/ui/types.ts @@ -20,7 +20,7 @@ import type { CaseUserActionResponse, SingleCaseMetricsResponse, CommentResponse, - CaseResponse, + Case as CaseSnakeCase, UserActionFindResponse, FindTypeField as UserActionFindTypeField, CommentResponseAlertsType, @@ -92,8 +92,8 @@ export type FindCaseUserActions = Omit, userActions: CaseUserActions[]; }; export type CaseUserActionsStats = SnakeToCamelCase; -export type Case = Omit, 'comments'> & { comments: Comment[] }; -export type Cases = Omit, 'cases'> & { cases: Case[] }; +export type CaseUI = Omit, 'comments'> & { comments: Comment[] }; +export type CasesUI = Omit, 'cases'> & { cases: CaseUI[] }; export type CasesStatus = SnakeToCamelCase; export type CasesMetrics = SnakeToCamelCase; export type CaseUpdateRequest = SnakeToCamelCase; @@ -101,7 +101,7 @@ export type CaseConnectors = SnakeToCamelCase; export type CaseUsers = GetCaseUsersResponse; export interface ResolvedCase { - case: Case; + case: CaseUI; outcome: ResolvedSimpleSavedObject['outcome']; aliasTargetId?: ResolvedSimpleSavedObject['alias_target_id']; aliasPurpose?: ResolvedSimpleSavedObject['alias_purpose']; @@ -191,7 +191,7 @@ export type UpdateKey = keyof Pick< export interface UpdateByKey { updateKey: UpdateKey; updateValue: CasePatchRequest[UpdateKey]; - caseData: Case; + caseData: CaseUI; onSuccess?: () => void; onError?: () => void; } diff --git a/x-pack/plugins/cases/public/api/decoders.ts b/x-pack/plugins/cases/public/api/decoders.ts index 6402b2d56a342..121595ccb0414 100644 --- a/x-pack/plugins/cases/public/api/decoders.ts +++ b/x-pack/plugins/cases/public/api/decoders.ts @@ -16,12 +16,12 @@ import type { CasesStatusResponse, CasesMetricsResponse, CasesBulkGetResponseCertainFields, - CaseResponse, + Case, } from '../../common/api'; import { CasesFindResponseRt, CasesStatusResponseRt, - CasesResponseRt, + CasesRt, getTypeForCertainFieldsFromArray, CasesMetricsResponseRt, } from '../../common/api'; @@ -41,11 +41,11 @@ export const decodeCasesMetricsResponse = (metrics?: CasesMetricsResponse) => fold(throwErrors(createToasterPlainError), identity) ); -export const decodeCasesBulkGetResponse = ( +export const decodeCasesBulkGetResponse = ( res: CasesBulkGetResponseCertainFields, fields?: string[] ) => { - const typeToDecode = getTypeForCertainFieldsFromArray(CasesResponseRt, fields); + const typeToDecode = getTypeForCertainFieldsFromArray(CasesRt, fields); pipe(typeToDecode.decode(res.cases), fold(throwErrors(createToasterPlainError), identity)); return res; diff --git a/x-pack/plugins/cases/public/api/index.ts b/x-pack/plugins/cases/public/api/index.ts index c89b1ff94f9e9..9d30cd0b58557 100644 --- a/x-pack/plugins/cases/public/api/index.ts +++ b/x-pack/plugins/cases/public/api/index.ts @@ -6,7 +6,7 @@ */ import type { HttpStart } from '@kbn/core/public'; -import type { Cases, CasesStatus, CasesMetrics } from '../../common/ui'; +import type { CasesUI, CasesStatus, CasesMetrics } from '../../common/ui'; import { CASE_FIND_URL, CASE_METRICS_URL, @@ -14,7 +14,7 @@ import { INTERNAL_BULK_GET_CASES_URL, } from '../../common/constants'; import type { - CaseResponse, + Case, CasesBulkGetRequestCertainFields, CasesBulkGetResponseCertainFields, CasesFindRequest, @@ -41,7 +41,7 @@ export const getCases = async ({ http, signal, query, -}: HTTPService & { query: CasesFindRequest }): Promise => { +}: HTTPService & { query: CasesFindRequest }): Promise => { const res = await http.get(CASE_FIND_URL, { query, signal }); return convertAllCasesToCamel(decodeCasesFindResponse(res)); }; @@ -68,7 +68,7 @@ export const getCasesMetrics = async ({ return convertToCamelCase(decodeCasesMetricsResponse(res)); }; -export const bulkGetCases = async ({ +export const bulkGetCases = async ({ http, signal, params, diff --git a/x-pack/plugins/cases/public/api/utils.ts b/x-pack/plugins/cases/public/api/utils.ts index f7ce3bf0817d2..d463fb4304249 100644 --- a/x-pack/plugins/cases/public/api/utils.ts +++ b/x-pack/plugins/cases/public/api/utils.ts @@ -13,15 +13,15 @@ import { } from '../../common/utils/attachments'; import type { CasesFindResponse, - CaseResponse, + Case, CaseUserActionsResponse, CommentRequest, CommentResponse, CaseResolveResponse, - CasesResponse, + Cases, } from '../../common/api'; import { isCommentUserAction } from '../../common/utils/user_actions'; -import type { Cases, Case, Comment, ResolvedCase } from '../containers/types'; +import type { CasesUI, CaseUI, Comment, ResolvedCase } from '../containers/types'; export const convertArrayToCamelCase = (arrayOfSnakes: unknown[]): unknown[] => arrayOfSnakes.reduce((acc: unknown[], value) => { @@ -46,15 +46,15 @@ export const convertToCamelCase = (obj: T): U => return acc; }, {} as U); -export const convertCaseToCamelCase = (theCase: CaseResponse): Case => { +export const convertCaseToCamelCase = (theCase: Case): CaseUI => { const { comments, ...restCase } = theCase; return { - ...convertToCamelCase(restCase), + ...convertToCamelCase(restCase), ...(comments != null ? { comments: convertAttachmentsToCamelCase(comments) } : {}), }; }; -export const convertCasesToCamelCase = (cases: CasesResponse): Case[] => +export const convertCasesToCamelCase = (cases: Cases): CaseUI[] => cases.map(convertCaseToCamelCase); export const convertCaseResolveToCamelCase = (res: CaseResolveResponse): ResolvedCase => { @@ -113,7 +113,7 @@ const convertAttachmentToCamelExceptProperty = ( } as Comment; }; -export const convertAllCasesToCamel = (snakeCases: CasesFindResponse): Cases => ({ +export const convertAllCasesToCamel = (snakeCases: CasesFindResponse): CasesUI => ({ cases: convertCasesToCamelCase(snakeCases.cases), countOpenCases: snakeCases.count_open_cases, countInProgressCases: snakeCases.count_in_progress_cases, diff --git a/x-pack/plugins/cases/public/client/api/index.ts b/x-pack/plugins/cases/public/client/api/index.ts index 09a172121d08c..d040c3a8e7fb9 100644 --- a/x-pack/plugins/cases/public/client/api/index.ts +++ b/x-pack/plugins/cases/public/client/api/index.ts @@ -14,7 +14,7 @@ import type { CasesMetricsRequest, } from '../../../common/api'; import { getCasesFromAlertsUrl } from '../../../common/api'; -import type { Cases, CasesStatus, CasesMetrics } from '../../../common/ui'; +import type { CasesUI, CasesStatus, CasesMetrics } from '../../../common/ui'; import { bulkGetCases, getCases, getCasesMetrics, getCasesStatus } from '../../api'; import type { CasesUiStart } from '../../types'; @@ -26,7 +26,7 @@ export const createClientAPI = ({ http }: { http: HttpStart }): CasesUiStart['ap ): Promise => http.get(getCasesFromAlertsUrl(alertId), { query }), cases: { - find: (query: CasesFindRequest, signal?: AbortSignal): Promise => + find: (query: CasesFindRequest, signal?: AbortSignal): Promise => getCases({ http, query, signal }), getCasesStatus: (query: CasesStatusRequest, signal?: AbortSignal): Promise => getCasesStatus({ http, query, signal }), diff --git a/x-pack/plugins/cases/public/client/attachment_framework/types.ts b/x-pack/plugins/cases/public/client/attachment_framework/types.ts index 95a453b9d0a12..793bcca8d15eb 100644 --- a/x-pack/plugins/cases/public/client/attachment_framework/types.ts +++ b/x-pack/plugins/cases/public/client/attachment_framework/types.ts @@ -11,7 +11,7 @@ import type { CommentRequestExternalReferenceType, CommentRequestPersistableStateType, } from '../../../common/api'; -import type { Case } from '../../containers/types'; +import type { CaseUI } from '../../containers/types'; export enum AttachmentActionType { BUTTON = 'button', @@ -48,7 +48,7 @@ export interface AttachmentViewObject { } export interface CommonAttachmentViewProps { - caseData: Pick; + caseData: Pick; } export interface ExternalReferenceAttachmentViewProps extends CommonAttachmentViewProps { diff --git a/x-pack/plugins/cases/public/common/use_cases_toast.tsx b/x-pack/plugins/cases/public/common/use_cases_toast.tsx index 26027905f8f0e..d123cc1bdd5e8 100644 --- a/x-pack/plugins/cases/public/common/use_cases_toast.tsx +++ b/x-pack/plugins/cases/public/common/use_cases_toast.tsx @@ -11,7 +11,7 @@ import React from 'react'; import styled from 'styled-components'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; import { isValidOwner } from '../../common/utils/owner'; -import type { Case } from '../../common'; +import type { CaseUI } from '../../common'; import { CommentType } from '../../common'; import { useKibana, useToasts } from './lib/kibana'; import { generateCaseViewPath } from './navigation'; @@ -61,7 +61,7 @@ function getToastTitle({ title, attachments, }: { - theCase: Case; + theCase: CaseUI; title?: string; attachments?: CaseAttachmentsWithoutOwner; }): string { @@ -82,7 +82,7 @@ function getToastContent({ content, attachments, }: { - theCase: Case; + theCase: CaseUI; content?: string; attachments?: CaseAttachmentsWithoutOwner; }): string | undefined { @@ -131,7 +131,7 @@ export const useCasesToast = () => { title, content, }: { - theCase: Case; + theCase: CaseUI; attachments?: CaseAttachmentsWithoutOwner; title?: string; content?: string; diff --git a/x-pack/plugins/cases/public/components/actions/assignees/edit_assignees_flyout.tsx b/x-pack/plugins/cases/public/components/actions/assignees/edit_assignees_flyout.tsx index 42f4ef30ec594..2d9ee31171e42 100644 --- a/x-pack/plugins/cases/public/components/actions/assignees/edit_assignees_flyout.tsx +++ b/x-pack/plugins/cases/public/components/actions/assignees/edit_assignees_flyout.tsx @@ -21,13 +21,13 @@ import { EuiTitle, } from '@elastic/eui'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import { EditAssigneesSelectable } from './edit_assignees_selectable'; import * as i18n from './translations'; import type { ItemsSelectionState } from '../types'; interface Props { - selectedCases: Case[]; + selectedCases: CaseUI[]; onClose: () => void; onSaveAssignees: (args: ItemsSelectionState) => void; } diff --git a/x-pack/plugins/cases/public/components/actions/assignees/edit_assignees_selectable.tsx b/x-pack/plugins/cases/public/components/actions/assignees/edit_assignees_selectable.tsx index afcbbd4e165f5..3630c7114c009 100644 --- a/x-pack/plugins/cases/public/components/actions/assignees/edit_assignees_selectable.tsx +++ b/x-pack/plugins/cases/public/components/actions/assignees/edit_assignees_selectable.tsx @@ -27,7 +27,7 @@ import { getUserDisplayName } from '@kbn/user-profile-components'; import { useBulkGetUserProfiles } from '../../../containers/user_profiles/use_bulk_get_user_profiles'; import { useIsUserTyping } from '../../../common/use_is_user_typing'; import { useSuggestUserProfiles } from '../../../containers/user_profiles/use_suggest_user_profiles'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import * as i18n from './translations'; import { useItemsState } from '../use_items_state'; import type { ItemSelectableOption, ItemsSelectionState } from '../types'; @@ -38,7 +38,7 @@ import { SmallUserAvatar } from '../../user_profiles/small_user_avatar'; import { NoSelectedAssignees } from './no_selected_assignees'; interface Props { - selectedCases: Case[]; + selectedCases: CaseUI[]; onChangeAssignees: (args: ItemsSelectionState) => void; } diff --git a/x-pack/plugins/cases/public/components/actions/assignees/use_assignees_action.tsx b/x-pack/plugins/cases/public/components/actions/assignees/use_assignees_action.tsx index f2b1cb6947c9b..76e5d2239135e 100644 --- a/x-pack/plugins/cases/public/components/actions/assignees/use_assignees_action.tsx +++ b/x-pack/plugins/cases/public/components/actions/assignees/use_assignees_action.tsx @@ -7,14 +7,14 @@ import { EuiIcon } from '@elastic/eui'; import React from 'react'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import type { UseActionProps } from '../types'; import { useItemsAction } from '../use_items_action'; import * as i18n from './translations'; export const useAssigneesAction = ({ onAction, onActionSuccess, isDisabled }: UseActionProps) => { const { isFlyoutOpen, onFlyoutClosed, onSaveItems, openFlyout, isActionDisabled } = - useItemsAction({ + useItemsAction({ fieldKey: 'assignees', isDisabled, onAction, @@ -27,7 +27,7 @@ export const useAssigneesAction = ({ onAction, onActionSuccess, isDisabled }: Us })), }); - const getAction = (selectedCases: Case[]) => { + const getAction = (selectedCases: CaseUI[]) => { return { name: i18n.EDIT_ASSIGNEES, onClick: () => openFlyout(selectedCases), diff --git a/x-pack/plugins/cases/public/components/actions/copy_id/use_copy_id_action.tsx b/x-pack/plugins/cases/public/components/actions/copy_id/use_copy_id_action.tsx index be2166ba5b250..260726daa5950 100644 --- a/x-pack/plugins/cases/public/components/actions/copy_id/use_copy_id_action.tsx +++ b/x-pack/plugins/cases/public/components/actions/copy_id/use_copy_id_action.tsx @@ -10,13 +10,13 @@ import { EuiIcon, EuiTextColor } from '@elastic/eui'; import * as i18n from '../../../common/translations'; import { useCasesToast } from '../../../common/use_cases_toast'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import type { UseCopyIDActionProps } from '../types'; export const useCopyIDAction = ({ onActionSuccess }: UseCopyIDActionProps) => { const { showSuccessToast } = useCasesToast(); - const getAction = (selectedCase: Case) => { + const getAction = (selectedCase: CaseUI) => { return { name: {i18n.COPY_ID_ACTION_LABEL}, onClick: () => { diff --git a/x-pack/plugins/cases/public/components/actions/delete/use_delete_action.tsx b/x-pack/plugins/cases/public/components/actions/delete/use_delete_action.tsx index 608af0e66444b..52370742a6685 100644 --- a/x-pack/plugins/cases/public/components/actions/delete/use_delete_action.tsx +++ b/x-pack/plugins/cases/public/components/actions/delete/use_delete_action.tsx @@ -7,7 +7,7 @@ import React, { useCallback, useState } from 'react'; import { EuiIcon, EuiTextColor, useEuiTheme } from '@elastic/eui'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import { useDeleteCases } from '../../../containers/use_delete_cases'; import * as i18n from './translations'; @@ -21,13 +21,13 @@ export const useDeleteAction = ({ onAction, onActionSuccess, isDisabled }: UseAc const euiTheme = useEuiTheme(); const { permissions } = useCasesContext(); const [isModalVisible, setIsModalVisible] = useState(false); - const [caseToBeDeleted, setCaseToBeDeleted] = useState([]); + const [caseToBeDeleted, setCaseToBeDeleted] = useState([]); const canDelete = permissions.delete; const isActionDisabled = isDisabled || !canDelete; const onCloseModal = useCallback(() => setIsModalVisible(false), []); const openModal = useCallback( - (selectedCases: Case[]) => { + (selectedCases: CaseUI[]) => { onAction(); setIsModalVisible(true); setCaseToBeDeleted(selectedCases); @@ -50,7 +50,7 @@ export const useDeleteAction = ({ onAction, onActionSuccess, isDisabled }: UseAc const color = isActionDisabled ? euiTheme.euiTheme.colors.disabled : 'danger'; - const getAction = (selectedCases: Case[]) => { + const getAction = (selectedCases: CaseUI[]) => { return { name: {getDeleteActionTitle(selectedCases.length)}, onClick: () => openModal(selectedCases), diff --git a/x-pack/plugins/cases/public/components/actions/severity/use_severity_action.tsx b/x-pack/plugins/cases/public/components/actions/severity/use_severity_action.tsx index 614bb0cbef77c..d271f8891bfeb 100644 --- a/x-pack/plugins/cases/public/components/actions/severity/use_severity_action.tsx +++ b/x-pack/plugins/cases/public/components/actions/severity/use_severity_action.tsx @@ -9,14 +9,14 @@ import { useCallback } from 'react'; import type { EuiContextMenuPanelItemDescriptor } from '@elastic/eui'; import { CaseSeverity } from '../../../../common/api'; import { useUpdateCases } from '../../../containers/use_bulk_update_case'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import * as i18n from './translations'; import type { UseActionProps } from '../types'; import { useCasesContext } from '../../cases_context/use_cases_context'; import { severities } from '../../severity/config'; -const getSeverityToasterMessage = (severity: CaseSeverity, cases: Case[]): string => { +const getSeverityToasterMessage = (severity: CaseSeverity, cases: CaseUI[]): string => { const totalCases = cases.length; const caseTitle = totalCases === 1 ? cases[0].title : ''; @@ -39,7 +39,7 @@ interface UseSeverityActionProps extends UseActionProps { selectedSeverity?: CaseSeverity; } -const shouldDisableSeverity = (cases: Case[], severity: CaseSeverity) => +const shouldDisableSeverity = (cases: CaseUI[], severity: CaseSeverity) => cases.every((theCase) => theCase.severity === severity); export const useSeverityAction = ({ @@ -54,7 +54,7 @@ export const useSeverityAction = ({ const isActionDisabled = isDisabled || !canUpdateSeverity; const handleUpdateCaseSeverity = useCallback( - (selectedCases: Case[], severity: CaseSeverity) => { + (selectedCases: CaseUI[], severity: CaseSeverity) => { onAction(); const casesToUpdate = selectedCases.map((theCase) => ({ severity, @@ -76,7 +76,7 @@ export const useSeverityAction = ({ const getSeverityIcon = (severity: CaseSeverity): string => selectedSeverity && selectedSeverity === severity ? 'check' : 'empty'; - const getActions = (selectedCases: Case[]): EuiContextMenuPanelItemDescriptor[] => { + const getActions = (selectedCases: CaseUI[]): EuiContextMenuPanelItemDescriptor[] => { return [ { name: severities[CaseSeverity.LOW].label, diff --git a/x-pack/plugins/cases/public/components/actions/status/use_status_action.tsx b/x-pack/plugins/cases/public/components/actions/status/use_status_action.tsx index 6b9fe58c15105..6c32d2cdbd865 100644 --- a/x-pack/plugins/cases/public/components/actions/status/use_status_action.tsx +++ b/x-pack/plugins/cases/public/components/actions/status/use_status_action.tsx @@ -8,7 +8,7 @@ import { useCallback } from 'react'; import type { EuiContextMenuPanelItemDescriptor } from '@elastic/eui'; import { useUpdateCases } from '../../../containers/use_bulk_update_case'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import { CaseStatuses } from '../../../../common'; import * as i18n from './translations'; @@ -16,7 +16,7 @@ import type { UseActionProps } from '../types'; import { statuses } from '../../status'; import { useCasesContext } from '../../cases_context/use_cases_context'; -const getStatusToasterMessage = (status: CaseStatuses, cases: Case[]): string => { +const getStatusToasterMessage = (status: CaseStatuses, cases: CaseUI[]): string => { const totalCases = cases.length; const caseTitle = totalCases === 1 ? cases[0].title : ''; @@ -35,7 +35,7 @@ interface UseStatusActionProps extends UseActionProps { selectedStatus?: CaseStatuses; } -const shouldDisableStatus = (cases: Case[], status: CaseStatuses) => +const shouldDisableStatus = (cases: CaseUI[], status: CaseStatuses) => cases.every((theCase) => theCase.status === status); export const useStatusAction = ({ @@ -50,7 +50,7 @@ export const useStatusAction = ({ const isActionDisabled = isDisabled || !canUpdateStatus; const handleUpdateCaseStatus = useCallback( - (selectedCases: Case[], status: CaseStatuses) => { + (selectedCases: CaseUI[], status: CaseStatuses) => { onAction(); const casesToUpdate = selectedCases.map((theCase) => ({ status, @@ -72,7 +72,7 @@ export const useStatusAction = ({ const getStatusIcon = (status: CaseStatuses): string => selectedStatus && selectedStatus === status ? 'check' : 'empty'; - const getActions = (selectedCases: Case[]): EuiContextMenuPanelItemDescriptor[] => { + const getActions = (selectedCases: CaseUI[]): EuiContextMenuPanelItemDescriptor[] => { return [ { name: statuses[CaseStatuses.open].label, diff --git a/x-pack/plugins/cases/public/components/actions/tags/edit_tags_flyout.tsx b/x-pack/plugins/cases/public/components/actions/tags/edit_tags_flyout.tsx index babedee38611c..6bf5853d5e671 100644 --- a/x-pack/plugins/cases/public/components/actions/tags/edit_tags_flyout.tsx +++ b/x-pack/plugins/cases/public/components/actions/tags/edit_tags_flyout.tsx @@ -22,14 +22,14 @@ import { EuiTitle, } from '@elastic/eui'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import { useGetTags } from '../../../containers/use_get_tags'; import { EditTagsSelectable } from './edit_tags_selectable'; import * as i18n from './translations'; import type { ItemsSelectionState } from '../types'; interface Props { - selectedCases: Case[]; + selectedCases: CaseUI[]; onClose: () => void; onSaveTags: (args: ItemsSelectionState) => void; } diff --git a/x-pack/plugins/cases/public/components/actions/tags/edit_tags_selectable.tsx b/x-pack/plugins/cases/public/components/actions/tags/edit_tags_selectable.tsx index 3bdbb60cac8e8..437c3c94b1915 100644 --- a/x-pack/plugins/cases/public/components/actions/tags/edit_tags_selectable.tsx +++ b/x-pack/plugins/cases/public/components/actions/tags/edit_tags_selectable.tsx @@ -20,13 +20,13 @@ import { } from '@elastic/eui'; import { isEmpty } from 'lodash'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import * as i18n from './translations'; import { useItemsState } from '../use_items_state'; import type { ItemSelectableOption, ItemsSelectionState } from '../types'; interface Props { - selectedCases: Case[]; + selectedCases: CaseUI[]; tags: string[]; isLoading: boolean; onChangeTags: (args: ItemsSelectionState) => void; diff --git a/x-pack/plugins/cases/public/components/actions/tags/use_tags_action.tsx b/x-pack/plugins/cases/public/components/actions/tags/use_tags_action.tsx index 2e4acd618b34f..ff7d9dc078f39 100644 --- a/x-pack/plugins/cases/public/components/actions/tags/use_tags_action.tsx +++ b/x-pack/plugins/cases/public/components/actions/tags/use_tags_action.tsx @@ -7,14 +7,14 @@ import { EuiIcon } from '@elastic/eui'; import React from 'react'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import type { UseActionProps } from '../types'; import { useItemsAction } from '../use_items_action'; import * as i18n from './translations'; export const useTagsAction = ({ onAction, onActionSuccess, isDisabled }: UseActionProps) => { const { isFlyoutOpen, onFlyoutClosed, onSaveItems, openFlyout, isActionDisabled } = - useItemsAction({ + useItemsAction({ fieldKey: 'tags', isDisabled, onAction, @@ -24,7 +24,7 @@ export const useTagsAction = ({ onAction, onActionSuccess, isDisabled }: UseActi itemsTransformer: (items) => items, }); - const getAction = (selectedCases: Case[]) => { + const getAction = (selectedCases: CaseUI[]) => { return { name: i18n.EDIT_TAGS, onClick: () => openFlyout(selectedCases), diff --git a/x-pack/plugins/cases/public/components/actions/use_items_action.tsx b/x-pack/plugins/cases/public/components/actions/use_items_action.tsx index 6ab5dce5f48ef..464f14bbee11b 100644 --- a/x-pack/plugins/cases/public/components/actions/use_items_action.tsx +++ b/x-pack/plugins/cases/public/components/actions/use_items_action.tsx @@ -9,14 +9,14 @@ import { useCallback, useState } from 'react'; import { difference, isEqual } from 'lodash'; import type { CaseUpdateRequest } from '../../../common/ui'; import { useUpdateCases } from '../../containers/use_bulk_update_case'; -import type { Case } from '../../../common'; +import type { CaseUI } from '../../../common'; import { useCasesContext } from '../cases_context/use_cases_context'; import type { UseActionProps, ItemsSelectionState } from './types'; type UseItemsActionProps = UseActionProps & { fieldKey: 'tags' | 'assignees'; successToasterTitle: (totalCases: number) => string; - fieldSelector: (theCase: Case) => string[]; + fieldSelector: (theCase: CaseUI) => string[]; itemsTransformer: (items: string[]) => T; }; @@ -32,13 +32,13 @@ export const useItemsAction = ({ const { mutate: updateCases } = useUpdateCases(); const { permissions } = useCasesContext(); const [isFlyoutOpen, setIsFlyoutOpen] = useState(false); - const [selectedCasesToEdit, setSelectedCasesToEdit] = useState([]); + const [selectedCasesToEdit, setSelectedCasesToEdit] = useState([]); const canUpdateStatus = permissions.update; const isActionDisabled = isDisabled || !canUpdateStatus; const onFlyoutClosed = useCallback(() => setIsFlyoutOpen(false), []); const openFlyout = useCallback( - (selectedCases: Case[]) => { + (selectedCases: CaseUI[]) => { onAction(); setIsFlyoutOpen(true); setSelectedCasesToEdit(selectedCases); diff --git a/x-pack/plugins/cases/public/components/actions/use_items_state.tsx b/x-pack/plugins/cases/public/components/actions/use_items_state.tsx index bd5db49336b5a..99ccf9b9e2055 100644 --- a/x-pack/plugins/cases/public/components/actions/use_items_state.tsx +++ b/x-pack/plugins/cases/public/components/actions/use_items_state.tsx @@ -8,14 +8,14 @@ import type { EuiSelectableOption, IconType } from '@elastic/eui'; import { assertNever } from '@elastic/eui'; import { useCallback, useReducer, useMemo } from 'react'; -import type { Case } from '../../../common'; +import type { CaseUI } from '../../../common'; import type { ItemSelectableOption, ItemsSelectionState } from './types'; interface UseItemsStateProps { items: string[]; - selectedCases: Case[]; + selectedCases: CaseUI[]; itemToSelectableOption: (item: Payload[number]) => EuiSelectableOption; - fieldSelector: (theCase: Case) => string[]; + fieldSelector: (theCase: CaseUI) => string[]; onChangeItems: (args: ItemsSelectionState) => void; } @@ -153,7 +153,7 @@ const getInitialItemsState = ({ fieldSelector, }: { items: string[]; - selectedCases: Case[]; + selectedCases: CaseUI[]; fieldSelector: UseItemsStateProps['fieldSelector']; }): State => { const itemCounterMap = createItemsCounterMapping({ selectedCases, fieldSelector }); @@ -183,7 +183,7 @@ const createItemsCounterMapping = ({ selectedCases, fieldSelector, }: { - selectedCases: Case[]; + selectedCases: CaseUI[]; fieldSelector: UseItemsStateProps['fieldSelector']; }) => { const counterMap = new Map(); diff --git a/x-pack/plugins/cases/public/components/add_comment/index.tsx b/x-pack/plugins/cases/public/components/add_comment/index.tsx index d75401841b6f5..fceeef2d31412 100644 --- a/x-pack/plugins/cases/public/components/add_comment/index.tsx +++ b/x-pack/plugins/cases/public/components/add_comment/index.tsx @@ -25,7 +25,7 @@ import { } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { CommentType } from '../../../common/api'; import { useCreateAttachments } from '../../containers/use_create_attachments'; -import type { Case } from '../../containers/types'; +import type { CaseUI } from '../../containers/types'; import type { EuiMarkdownEditorRef } from '../markdown_editor'; import { MarkdownEditorForm } from '../markdown_editor'; import { getMarkdownEditorStorageKey } from '../markdown_editor/utils'; @@ -57,7 +57,7 @@ export interface AddCommentProps { id: string; caseId: string; onCommentSaving?: () => void; - onCommentPosted: (newCase: Case) => void; + onCommentPosted: (newCase: CaseUI) => void; showLoading?: boolean; statusActionButton: JSX.Element | null; } diff --git a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx index 7666d518fe9b4..f30fd33fd0995 100644 --- a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx @@ -11,7 +11,7 @@ import { EuiProgress } from '@elastic/eui'; import { difference, head, isEmpty } from 'lodash/fp'; import styled, { css } from 'styled-components'; -import type { Case, CaseStatusWithAllStatus, FilterOptions } from '../../../common/ui/types'; +import type { CaseUI, CaseStatusWithAllStatus, FilterOptions } from '../../../common/ui/types'; import { SortFieldCase, StatusAll } from '../../../common/ui/types'; import { CaseStatuses, caseStatuses } from '../../../common/api'; import { OWNER_INFO } from '../../../common/constants'; @@ -64,7 +64,7 @@ const mapToReadableSolutionName = (solution: string): Solution => { export interface AllCasesListProps { hiddenStatuses?: CaseStatusWithAllStatus[]; isSelectorView?: boolean; - onRowClick?: (theCase?: Case) => void; + onRowClick?: (theCase?: CaseUI) => void; } export const AllCasesList = React.memo( @@ -84,7 +84,7 @@ export const AllCasesList = React.memo( isSelectorView, initialFilterOptions ); - const [selectedCases, setSelectedCases] = useState([]); + const [selectedCases, setSelectedCases] = useState([]); const { data = initialData, isFetching: isLoadingCases } = useGetCases({ filterOptions, @@ -224,7 +224,7 @@ export const AllCasesList = React.memo( [data, queryParams] ); - const euiBasicTableSelectionProps = useMemo>( + const euiBasicTableSelectionProps = useMemo>( () => ({ onSelectionChange: setSelectedCases, initialSelected: selectedCases, @@ -235,7 +235,7 @@ export const AllCasesList = React.memo( const isDataEmpty = useMemo(() => data.total === 0, [data]); const tableRowProps = useCallback( - (theCase: Case) => ({ + (theCase: CaseUI) => ({ 'data-test-subj': `cases-table-row-${theCase.id}`, }), [] diff --git a/x-pack/plugins/cases/public/components/all_cases/assignees_column.tsx b/x-pack/plugins/cases/public/components/all_cases/assignees_column.tsx index 8b5444f9a9d91..41e936a7021c0 100644 --- a/x-pack/plugins/cases/public/components/all_cases/assignees_column.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/assignees_column.tsx @@ -8,7 +8,7 @@ import React, { useCallback, useMemo, useState } from 'react'; import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; -import type { Case } from '../../../common/ui/types'; +import type { CaseUI } from '../../../common/ui/types'; import { getEmptyTagValue } from '../empty_value'; import { UserToolTip } from '../user_profiles/user_tooltip'; import { useAssignees } from '../../containers/user_profiles/use_assignees'; @@ -19,7 +19,7 @@ import * as i18n from './translations'; const COMPRESSED_AVATAR_LIMIT = 3; export interface AssigneesColumnProps { - assignees: Case['assignees']; + assignees: CaseUI['assignees']; userProfiles: Map; compressedDisplayLimit?: number; } diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx index 6a9629699734b..1aaf9c87cf245 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx @@ -17,14 +17,14 @@ import { import styled from 'styled-components'; import { QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; -import type { Case, CaseStatusWithAllStatus } from '../../../../common/ui/types'; +import type { CaseUI, CaseStatusWithAllStatus } from '../../../../common/ui/types'; import * as i18n from '../../../common/translations'; import { AllCasesList } from '../all_cases_list'; import { casesQueryClient } from '../../cases_context/query_client'; export interface AllCasesSelectorModalProps { hiddenStatuses?: CaseStatusWithAllStatus[]; - onRowClick?: (theCase?: Case) => void; + onRowClick?: (theCase?: CaseUI) => void; onClose?: () => void; } @@ -46,7 +46,7 @@ export const AllCasesSelectorModal = React.memo( }, [onClose]); const onClick = useCallback( - (theCase?: Case) => { + (theCase?: CaseUI) => { closeModal(); if (onRowClick) { onRowClick(theCase); diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx index e98397d8bb37e..a63fd6ceaef10 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx @@ -10,7 +10,7 @@ import { act, renderHook } from '@testing-library/react-hooks'; import userEvent from '@testing-library/user-event'; import React from 'react'; import AllCasesSelectorModal from '.'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import { CaseStatuses, StatusAll } from '../../../../common'; import type { AppMockRenderer } from '../../../common/mock'; import { allCasesPermissions, createAppMockRenderer } from '../../../common/mock'; @@ -144,7 +144,7 @@ describe('use cases add to existing case modal hook', () => { it('should call getAttachments with the case info', async () => { AllCasesSelectorModalMock.mockImplementation(({ onRowClick }) => { - onRowClick({ id: 'test' } as Case); + onRowClick({ id: 'test' } as CaseUI); return null; }); @@ -159,7 +159,7 @@ describe('use cases add to existing case modal hook', () => { it('should show a toaster info when no attachments are defined and noAttachmentsToaster is defined', async () => { AllCasesSelectorModalMock.mockImplementation(({ onRowClick }) => { - onRowClick({ id: 'test' } as Case); + onRowClick({ id: 'test' } as CaseUI); return null; }); @@ -182,7 +182,7 @@ describe('use cases add to existing case modal hook', () => { it('should show a toaster info when no attachments are defined and noAttachmentsToaster is not defined', async () => { AllCasesSelectorModalMock.mockImplementation(({ onRowClick }) => { - onRowClick({ id: 'test' } as Case); + onRowClick({ id: 'test' } as CaseUI); return null; }); @@ -213,7 +213,7 @@ describe('use cases add to existing case modal hook', () => { }); AllCasesSelectorModalMock.mockImplementation(({ onRowClick }) => { - onRowClick({ id: 'test' } as Case); + onRowClick({ id: 'test' } as CaseUI); return null; }); @@ -244,7 +244,7 @@ describe('use cases add to existing case modal hook', () => { }); AllCasesSelectorModalMock.mockImplementation(({ onRowClick }) => { - onRowClick({ id: 'test' } as Case); + onRowClick({ id: 'test' } as CaseUI); return null; }); @@ -295,7 +295,7 @@ describe('use cases add to existing case modal hook', () => { // simulate a case selected AllCasesSelectorModalMock.mockImplementation(({ onRowClick }) => { - onRowClick({ id: 'test' } as Case); + onRowClick({ id: 'test' } as CaseUI); return null; }); diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.tsx index ea2e0f200433e..fb7a40d5725df 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.tsx @@ -9,7 +9,7 @@ import { useCallback } from 'react'; import { CaseStatuses, StatusAll } from '../../../../common'; import type { AllCasesSelectorModalProps } from '.'; import { useCasesToast } from '../../../common/use_cases_toast'; -import type { Case } from '../../../containers/types'; +import type { CaseUI } from '../../../containers/types'; import { CasesContextStoreActionsList } from '../../cases_context/cases_context_reducer'; import { useCasesContext } from '../../cases_context/use_cases_context'; import { useCasesAddToNewCaseFlyout } from '../../create/flyout/use_cases_add_to_new_case_flyout'; @@ -27,13 +27,13 @@ export type AddToExistingCaseModalProps = Omit void; + onSuccess?: (theCase: CaseUI) => void; }; export const useCasesAddToExistingCaseModal = (props: AddToExistingCaseModalProps = {}) => { const createNewCaseFlyout = useCasesAddToNewCaseFlyout({ onClose: props.onClose, - onSuccess: (theCase?: Case) => { + onSuccess: (theCase?: CaseUI) => { if (props.onSuccess && theCase) { return props.onSuccess(theCase); } @@ -60,8 +60,8 @@ export const useCasesAddToExistingCaseModal = (props: AddToExistingCaseModalProp const handleOnRowClick = useCallback( async ( - theCase: Case | undefined, - getAttachments?: ({ theCase }: { theCase?: Case }) => CaseAttachmentsWithoutOwner + theCase: CaseUI | undefined, + getAttachments?: ({ theCase }: { theCase?: CaseUI }) => CaseAttachmentsWithoutOwner ) => { const attachments = getAttachments?.({ theCase }) ?? []; // when the case is undefined in the modal @@ -121,14 +121,14 @@ export const useCasesAddToExistingCaseModal = (props: AddToExistingCaseModalProp ({ getAttachments, }: { - getAttachments?: ({ theCase }: { theCase?: Case }) => CaseAttachmentsWithoutOwner; + getAttachments?: ({ theCase }: { theCase?: CaseUI }) => CaseAttachmentsWithoutOwner; } = {}) => { dispatch({ type: CasesContextStoreActionsList.OPEN_ADD_TO_CASE_MODAL, payload: { ...props, hiddenStatuses: [CaseStatuses.closed, StatusAll], - onRowClick: (theCase?: Case) => { + onRowClick: (theCase?: CaseUI) => { handleOnRowClick(theCase, getAttachments); }, onClose: () => { diff --git a/x-pack/plugins/cases/public/components/all_cases/table.tsx b/x-pack/plugins/cases/public/components/all_cases/table.tsx index 61fb081a0dd9a..0aa9f78c5d0bf 100644 --- a/x-pack/plugins/cases/public/components/all_cases/table.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/table.tsx @@ -14,26 +14,26 @@ import styled from 'styled-components'; import { CasesTableUtilityBar } from './utility_bar'; import { LinkButton } from '../links'; -import type { Cases, Case } from '../../../common/ui/types'; +import type { CasesUI, CaseUI } from '../../../common/ui/types'; import * as i18n from './translations'; import { useCreateCaseNavigation } from '../../common/navigation'; import { useCasesContext } from '../cases_context/use_cases_context'; interface CasesTableProps { - columns: EuiBasicTableProps['columns']; - data: Cases; + columns: EuiBasicTableProps['columns']; + data: CasesUI; goToCreateCase?: () => void; isCasesLoading: boolean; isCommentUpdating: boolean; isDataEmpty: boolean; isSelectorView?: boolean; - onChange: EuiBasicTableProps['onChange']; + onChange: EuiBasicTableProps['onChange']; pagination: Pagination; - selectedCases: Case[]; - selection: EuiTableSelectionType; - sorting: EuiBasicTableProps['sorting']; + selectedCases: CaseUI[]; + selection: EuiTableSelectionType; + sorting: EuiBasicTableProps['sorting']; tableRef: MutableRefObject; - tableRowProps: EuiBasicTableProps['rowProps']; + tableRowProps: EuiBasicTableProps['rowProps']; deselectCases: () => void; } diff --git a/x-pack/plugins/cases/public/components/all_cases/use_actions.tsx b/x-pack/plugins/cases/public/components/all_cases/use_actions.tsx index 88d94f65f900c..ea43f79b4954e 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_actions.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_actions.tsx @@ -13,7 +13,7 @@ import type { } from '@elastic/eui'; import { EuiButtonIcon, EuiContextMenu, EuiPopover } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { Case } from '../../containers/types'; +import type { CaseUI } from '../../containers/types'; import { useDeleteAction } from '../actions/delete/use_delete_action'; import { ConfirmDeleteCaseModal } from '../confirm_delete_case'; import { useStatusAction } from '../actions/status/use_status_action'; @@ -29,7 +29,7 @@ import { useAssigneesAction } from '../actions/assignees/use_assignees_action'; import { EditAssigneesFlyout } from '../actions/assignees/edit_assignees_flyout'; import { useCopyIDAction } from '../actions/copy_id/use_copy_id_action'; -const ActionColumnComponent: React.FC<{ theCase: Case; disableActions: boolean }> = ({ +const ActionColumnComponent: React.FC<{ theCase: CaseUI; disableActions: boolean }> = ({ theCase, disableActions, }) => { @@ -223,7 +223,7 @@ ActionColumnComponent.displayName = 'ActionColumnComponent'; const ActionColumn = React.memo(ActionColumnComponent); interface UseBulkActionsReturnValue { - actions: EuiTableComputedColumnType | null; + actions: EuiTableComputedColumnType | null; } interface UseBulkActionsProps { @@ -239,7 +239,7 @@ export const useActions = ({ disableActions }: UseBulkActionsProps): UseBulkActi ? { name: i18n.ACTIONS, align: 'right', - render: (theCase: Case) => { + render: (theCase: CaseUI) => { return ( ); diff --git a/x-pack/plugins/cases/public/components/all_cases/use_bulk_actions.tsx b/x-pack/plugins/cases/public/components/all_cases/use_bulk_actions.tsx index 1d7efd62736fb..eadd3eb884081 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_bulk_actions.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_bulk_actions.tsx @@ -11,7 +11,7 @@ import type { } from '@elastic/eui'; import React, { useMemo } from 'react'; -import type { Case } from '../../containers/types'; +import type { CaseUI } from '../../containers/types'; import { useDeleteAction } from '../actions/delete/use_delete_action'; import { useSeverityAction } from '../actions/severity/use_severity_action'; import { useStatusAction } from '../actions/status/use_status_action'; @@ -23,7 +23,7 @@ import { EditAssigneesFlyout } from '../actions/assignees/edit_assignees_flyout' import * as i18n from './translations'; interface UseBulkActionsProps { - selectedCases: Case[]; + selectedCases: CaseUI[]; onAction: () => void; onActionSuccess: () => void; } diff --git a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx index 1f267eca40a84..b2048893b1895 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx @@ -28,7 +28,7 @@ import { Status } from '@kbn/cases-components'; import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import type { Case } from '../../../common/ui/types'; +import type { CaseUI } from '../../../common/ui/types'; import type { ActionConnector } from '../../../common/api'; import { CaseStatuses, CaseSeverity } from '../../../common/api'; import { OWNER_INFO } from '../../../common/constants'; @@ -47,9 +47,9 @@ import { useCasesFeatures } from '../../common/use_cases_features'; import { AssigneesColumn } from './assignees_column'; type CasesColumns = - | EuiTableActionsColumnType - | EuiTableComputedColumnType - | EuiTableFieldDataColumnType; + | EuiTableActionsColumnType + | EuiTableComputedColumnType + | EuiTableFieldDataColumnType; const MediumShadeText = styled.p` color: ${({ theme }) => theme.eui.euiColorMediumShade}; @@ -80,7 +80,7 @@ export interface GetCasesColumn { userProfiles: Map; isSelectorView: boolean; connectors?: ActionConnector[]; - onRowClick?: (theCase: Case) => void; + onRowClick?: (theCase: CaseUI) => void; showSolutionColumn?: boolean; disableActions?: boolean; } @@ -102,7 +102,7 @@ export const useCasesColumns = ({ const { actions } = useActions({ disableActions }); const assignCaseAction = useCallback( - async (theCase: Case) => { + async (theCase: CaseUI) => { if (onRowClick) { onRowClick(theCase); } @@ -115,7 +115,7 @@ export const useCasesColumns = ({ field: 'title', name: i18n.NAME, sortable: true, - render: (title: string, theCase: Case) => { + render: (title: string, theCase: CaseUI) => { if (theCase.id != null && theCase.title != null) { const caseDetailsLinkComponent = isSelectorView ? ( theCase.title @@ -145,7 +145,7 @@ export const useCasesColumns = ({ columns.push({ field: 'assignees', name: i18n.ASSIGNEES, - render: (assignees: Case['assignees']) => ( + render: (assignees: CaseUI['assignees']) => ( ), width: '180px', @@ -156,7 +156,7 @@ export const useCasesColumns = ({ columns.push({ field: 'tags', name: i18n.TAGS, - render: (tags: Case['tags']) => { + render: (tags: CaseUI['tags']) => { if (tags != null && tags.length > 0) { const clampedBadges = ( @@ -207,7 +207,7 @@ export const useCasesColumns = ({ align: RIGHT_ALIGNMENT, field: 'totalAlerts', name: ALERTS, - render: (totalAlerts: Case['totalAlerts']) => + render: (totalAlerts: CaseUI['totalAlerts']) => totalAlerts != null ? renderStringField(`${totalAlerts}`, `case-table-column-alertsCount`) : getEmptyTagValue(), @@ -241,7 +241,7 @@ export const useCasesColumns = ({ align: RIGHT_ALIGNMENT, field: 'totalComment', name: i18n.COMMENTS, - render: (totalComment: Case['totalComment']) => + render: (totalComment: CaseUI['totalComment']) => totalComment != null ? renderStringField(`${totalComment}`, `case-table-column-commentCount`) : getEmptyTagValue(), @@ -253,7 +253,7 @@ export const useCasesColumns = ({ field: 'closedAt', name: i18n.CLOSED_ON, sortable: true, - render: (closedAt: Case['closedAt']) => { + render: (closedAt: CaseUI['closedAt']) => { if (closedAt != null) { return ( @@ -269,7 +269,7 @@ export const useCasesColumns = ({ field: 'createdAt', name: i18n.CREATED_ON, sortable: true, - render: (createdAt: Case['createdAt']) => { + render: (createdAt: CaseUI['createdAt']) => { if (createdAt != null) { return ( @@ -287,7 +287,7 @@ export const useCasesColumns = ({ field: 'updatedAt', name: i18n.UPDATED_ON, sortable: true, - render: (updatedAt: Case['updatedAt']) => { + render: (updatedAt: CaseUI['updatedAt']) => { if (updatedAt != null) { return ( @@ -304,7 +304,7 @@ export const useCasesColumns = ({ columns.push( { name: i18n.EXTERNAL_INCIDENT, - render: (theCase: Case) => { + render: (theCase: CaseUI) => { if (theCase.id != null) { return ; } @@ -316,7 +316,7 @@ export const useCasesColumns = ({ field: 'status', name: i18n.STATUS, sortable: true, - render: (status: Case['status']) => { + render: (status: CaseUI['status']) => { if (status != null) { return ; } @@ -330,7 +330,7 @@ export const useCasesColumns = ({ field: 'severity', name: i18n.SEVERITY, sortable: true, - render: (severity: Case['severity']) => { + render: (severity: CaseUI['severity']) => { if (severity != null) { const severityData = severities[severity ?? CaseSeverity.LOW]; return ( @@ -349,7 +349,7 @@ export const useCasesColumns = ({ if (isSelectorView) { columns.push({ align: RIGHT_ALIGNMENT, - render: (theCase: Case) => { + render: (theCase: CaseUI) => { if (theCase.id != null) { return ( void; } diff --git a/x-pack/plugins/cases/public/components/case_action_bar/actions.tsx b/x-pack/plugins/cases/public/components/case_action_bar/actions.tsx index b80cd5c2dbe74..b6d9248839f3c 100644 --- a/x-pack/plugins/cases/public/components/case_action_bar/actions.tsx +++ b/x-pack/plugins/cases/public/components/case_action_bar/actions.tsx @@ -12,15 +12,15 @@ import * as i18n from '../case_view/translations'; import { useDeleteCases } from '../../containers/use_delete_cases'; import { ConfirmDeleteCaseModal } from '../confirm_delete_case'; import { PropertyActions } from '../property_actions'; -import type { Case } from '../../../common/ui/types'; +import type { CaseUI } from '../../../common/ui/types'; import { useAllCasesNavigation } from '../../common/navigation'; import { useCasesContext } from '../cases_context/use_cases_context'; import { useCasesToast } from '../../common/use_cases_toast'; import { AttachmentActionType } from '../../client/attachment_framework/types'; interface CaseViewActions { - caseData: Case; - currentExternalIncident: Case['externalService']; + caseData: CaseUI; + currentExternalIncident: CaseUI['externalService']; } const ActionsComponent: React.FC = ({ caseData, currentExternalIncident }) => { diff --git a/x-pack/plugins/cases/public/components/case_action_bar/helpers.ts b/x-pack/plugins/cases/public/components/case_action_bar/helpers.ts index 772bedd266dd8..2e1e176ff850a 100644 --- a/x-pack/plugins/cases/public/components/case_action_bar/helpers.ts +++ b/x-pack/plugins/cases/public/components/case_action_bar/helpers.ts @@ -6,10 +6,10 @@ */ import { CaseStatuses } from '../../../common/api'; -import type { Case } from '../../containers/types'; +import type { CaseUI } from '../../containers/types'; import { statuses } from '../status'; -export const getStatusDate = (theCase: Case): string | null => { +export const getStatusDate = (theCase: CaseUI): string | null => { if (theCase.status === CaseStatuses.open) { return theCase.createdAt; } else if (theCase.status === CaseStatuses['in-progress']) { diff --git a/x-pack/plugins/cases/public/components/case_action_bar/index.tsx b/x-pack/plugins/cases/public/components/case_action_bar/index.tsx index b8be843e8c659..f412dd7371561 100644 --- a/x-pack/plugins/cases/public/components/case_action_bar/index.tsx +++ b/x-pack/plugins/cases/public/components/case_action_bar/index.tsx @@ -16,7 +16,7 @@ import { EuiFlexItem, EuiIconTip, } from '@elastic/eui'; -import type { Case } from '../../../common/ui/types'; +import type { CaseUI } from '../../../common/ui/types'; import type { CaseStatuses } from '../../../common/api'; import * as i18n from '../case_view/translations'; import { Actions } from './actions'; @@ -44,7 +44,7 @@ const MyDescriptionList = styled(EuiDescriptionList)` `; export interface CaseActionBarProps { - caseData: Case; + caseData: CaseUI; isLoading: boolean; onUpdateField: (args: OnUpdateFields) => void; } diff --git a/x-pack/plugins/cases/public/components/case_view/case_view_tabs.tsx b/x-pack/plugins/cases/public/components/case_view/case_view_tabs.tsx index 630248bf79d52..b1e41d7c38b30 100644 --- a/x-pack/plugins/cases/public/components/case_view/case_view_tabs.tsx +++ b/x-pack/plugins/cases/public/components/case_view/case_view_tabs.tsx @@ -13,7 +13,7 @@ import { useCaseViewNavigation } from '../../common/navigation'; import { useCasesContext } from '../cases_context/use_cases_context'; import { EXPERIMENTAL_DESC, EXPERIMENTAL_LABEL } from '../header_page/translations'; import { ACTIVITY_TAB, ALERTS_TAB, FILES_TAB } from './translations'; -import type { Case } from '../../../common'; +import type { CaseUI } from '../../../common'; import { useGetCaseFileStats } from '../../containers/use_get_case_file_stats'; const ExperimentalBadge = styled(EuiBetaBadge)` @@ -49,7 +49,7 @@ const FilesTab = ({ FilesTab.displayName = 'FilesTab'; export interface CaseViewTabsProps { - caseData: Case; + caseData: CaseUI; activeTab: CASE_VIEW_PAGE_TABS; } diff --git a/x-pack/plugins/cases/public/components/case_view/components/case_view_activity.test.tsx b/x-pack/plugins/cases/public/components/case_view/components/case_view_activity.test.tsx index 7386d8bcd7ea1..51c1ad17eaba6 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/case_view_activity.test.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/case_view_activity.test.tsx @@ -21,7 +21,7 @@ import type { AppMockRenderer } from '../../../common/mock'; import { createAppMockRenderer, noUpdateCasesPermissions } from '../../../common/mock'; import { CaseViewActivity } from './case_view_activity'; import { ConnectorTypes } from '../../../../common/api/connectors'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import { CASE_VIEW_PAGE_TABS } from '../../../../common/types'; import type { CaseViewProps } from '../types'; import { useFindCaseUserActions } from '../../../containers/use_find_case_user_actions'; @@ -54,7 +54,7 @@ jest.mock('../../../containers/use_get_case_users'); (useGetTags as jest.Mock).mockReturnValue({ data: ['coke', 'pepsi'], refetch: jest.fn() }); -const caseData: Case = { +const caseData: CaseUI = { ...basicCase, comments: [...basicCase.comments, alertComment], connector: { diff --git a/x-pack/plugins/cases/public/components/case_view/components/case_view_activity.tsx b/x-pack/plugins/cases/public/components/case_view/components/case_view_activity.tsx index c4f387c617417..b0774ccbefce5 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/case_view_activity.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/case_view_activity.tsx @@ -18,7 +18,7 @@ import { useGetCurrentUserProfile } from '../../../containers/user_profiles/use_ import { useGetSupportedActionConnectors } from '../../../containers/configure/use_get_supported_action_connectors'; import type { CaseSeverity } from '../../../../common/api'; import type { CaseUsers, UseFetchAlertData } from '../../../../common/ui/types'; -import type { Case, CaseStatuses } from '../../../../common'; +import type { CaseUI, CaseStatuses } from '../../../../common'; import { EditConnector } from '../../edit_connector'; import type { CasesNavigation } from '../../links'; import { StatusActionButton } from '../../status/button'; @@ -81,7 +81,7 @@ export const CaseViewActivity = ({ useFetchAlertData, }: { ruleDetailsNavigation?: CasesNavigation; - caseData: Case; + caseData: CaseUI; actionsNavigation?: CasesNavigation; showAlertDetails?: (alertId: string, index: string) => void; useFetchAlertData: UseFetchAlertData; diff --git a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx index 54e5a0bc2febb..6833df2804630 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx @@ -11,18 +11,18 @@ import { OBSERVABILITY_OWNER } from '../../../../common/constants'; import { alertCommentWithIndices, basicCase } from '../../../containers/mock'; import type { AppMockRenderer } from '../../../common/mock'; import { createAppMockRenderer } from '../../../common/mock'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import { CaseViewAlerts } from './case_view_alerts'; import * as api from '../../../containers/api'; jest.mock('../../../containers/api'); -const caseData: Case = { +const caseData: CaseUI = { ...basicCase, comments: [...basicCase.comments, alertCommentWithIndices], }; -describe('Case View Page activity tab', () => { +describe('CaseUI View Page activity tab', () => { const getAlertsStateTableMock = jest.fn(); let appMockRender: AppMockRenderer; diff --git a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.tsx b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.tsx index 6b884325d3f73..e3393bf7f3544 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.tsx @@ -10,7 +10,7 @@ import React, { useMemo } from 'react'; import type { EuiFlyoutSize } from '@elastic/eui'; import { EuiFlexItem, EuiFlexGroup, EuiProgress } from '@elastic/eui'; import { SECURITY_SOLUTION_OWNER } from '../../../../common/constants'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import { useKibana } from '../../../common/lib/kibana'; import { getManualAlertIds, getRegistrationContextFromAlerts } from './helpers'; import { useGetFeatureIds } from '../../../containers/use_get_feature_ids'; @@ -18,7 +18,7 @@ import { CaseViewAlertsEmpty } from './case_view_alerts_empty'; import { CaseViewTabs } from '../case_view_tabs'; import { CASE_VIEW_PAGE_TABS } from '../../../../common/types'; interface CaseViewAlertsProps { - caseData: Case; + caseData: CaseUI; } export const CaseViewAlerts = ({ caseData }: CaseViewAlertsProps) => { const { triggersActionsUi } = useKibana().services; diff --git a/x-pack/plugins/cases/public/components/case_view/components/case_view_files.test.tsx b/x-pack/plugins/cases/public/components/case_view/components/case_view_files.test.tsx index dc5b937bd8781..1480ab7fb43f1 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/case_view_files.test.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/case_view_files.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import type { Case } from '../../../../common'; +import type { CaseUI } from '../../../../common'; import type { AppMockRenderer } from '../../../common/mock'; import { createAppMockRenderer } from '../../../common/mock'; @@ -21,7 +21,7 @@ jest.mock('../../../containers/use_get_case_files'); const useGetCaseFilesMock = useGetCaseFiles as jest.Mock; -const caseData: Case = { +const caseData: CaseUI = { ...basicCase, comments: [...basicCase.comments, alertCommentWithIndices], }; diff --git a/x-pack/plugins/cases/public/components/case_view/components/case_view_files.tsx b/x-pack/plugins/cases/public/components/case_view/components/case_view_files.tsx index 54693acfa2390..85cd4685a41fb 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/case_view_files.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/case_view_files.tsx @@ -12,7 +12,7 @@ import type { FileJSON } from '@kbn/shared-ux-file-types'; import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; -import type { Case } from '../../../../common/ui/types'; +import type { CaseUI } from '../../../../common/ui/types'; import type { CaseFilesFilteringOptions } from '../../../containers/use_get_case_files'; import { CASE_VIEW_PAGE_TABS } from '../../../../common/types'; @@ -22,7 +22,7 @@ import { CaseViewTabs } from '../case_view_tabs'; import { FilesUtilityBar } from '../../files/files_utility_bar'; interface CaseViewFilesProps { - caseData: Case; + caseData: CaseUI; } export const DEFAULT_CASE_FILES_FILTERING_OPTIONS = { diff --git a/x-pack/plugins/cases/public/components/case_view/components/user_list.tsx b/x-pack/plugins/cases/public/components/case_view/components/user_list.tsx index 47bd0ac3750a9..96b4c80c723f9 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/user_list.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/user_list.tsx @@ -22,7 +22,7 @@ import styled, { css } from 'styled-components'; import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; import { useCaseViewNavigation } from '../../../common/navigation'; -import type { Case } from '../../../containers/types'; +import type { CaseUI } from '../../../containers/types'; import * as i18n from '../translations'; import type { CaseUserWithProfileInfo, UserInfoWithAvatar } from '../../user_profiles/types'; import { HoverableUserWithAvatar } from '../../user_profiles/hoverable_user_with_avatar'; @@ -30,7 +30,7 @@ import { convertToUserInfo } from '../../user_profiles/user_converter'; import { getSortField } from '../../user_profiles/sort'; interface UserListProps { - theCase: Case; + theCase: CaseUI; headline: string; loading?: boolean; users: CaseUserWithProfileInfo[]; diff --git a/x-pack/plugins/cases/public/components/case_view/mocks.ts b/x-pack/plugins/cases/public/components/case_view/mocks.ts index 1f656ea42aa8c..af335653a9a51 100644 --- a/x-pack/plugins/cases/public/components/case_view/mocks.ts +++ b/x-pack/plugins/cases/public/components/case_view/mocks.ts @@ -13,7 +13,7 @@ import { caseUserActions, getAlertUserAction, } from '../../containers/mock'; -import type { Case } from '../../containers/types'; +import type { CaseUI } from '../../containers/types'; import type { CaseViewProps } from './types'; export const alertsHit = [ @@ -63,7 +63,7 @@ export const caseViewProps: CaseViewProps = { ], }; -export const caseData: Case = { +export const caseData: CaseUI = { ...basicCase, comments: [...basicCase.comments, alertComment], connector: { diff --git a/x-pack/plugins/cases/public/components/case_view/types.ts b/x-pack/plugins/cases/public/components/case_view/types.ts index 0e6bf82c5fef9..0dba765f0d5cb 100644 --- a/x-pack/plugins/cases/public/components/case_view/types.ts +++ b/x-pack/plugins/cases/public/components/case_view/types.ts @@ -7,7 +7,7 @@ import type { MutableRefObject } from 'react'; import type { CasesTimelineIntegration } from '../timeline_context'; import type { CasesNavigation } from '../links'; -import type { CaseViewRefreshPropInterface, Case } from '../../../common'; +import type { CaseViewRefreshPropInterface, CaseUI } from '../../../common'; import type { UseFetchAlertData } from '../../../common/ui'; export interface CaseViewBaseProps { @@ -30,12 +30,12 @@ export interface CaseViewProps extends CaseViewBaseProps { export interface CaseViewPageProps extends CaseViewBaseProps { caseId: string; fetchCase: () => void; - caseData: Case; + caseData: CaseUI; } export interface OnUpdateFields { - key: keyof Case; - value: Case[keyof Case]; + key: keyof CaseUI; + value: CaseUI[keyof CaseUI]; onSuccess?: () => void; onError?: () => void; } diff --git a/x-pack/plugins/cases/public/components/case_view/use_on_update_field.ts b/x-pack/plugins/cases/public/components/case_view/use_on_update_field.ts index d0fc6f98f0ce6..713c73d9b830c 100644 --- a/x-pack/plugins/cases/public/components/case_view/use_on_update_field.ts +++ b/x-pack/plugins/cases/public/components/case_view/use_on_update_field.ts @@ -11,12 +11,12 @@ import deepEqual from 'fast-deep-equal'; import type { CaseConnector } from '../../../common/api'; import type { CaseAttributes } from '../../../common/api/cases/case'; import type { CaseStatuses } from '../../../common/api/cases/status'; -import type { Case, UpdateByKey, UpdateKey } from '../../containers/types'; +import type { CaseUI, UpdateByKey, UpdateKey } from '../../containers/types'; import { useUpdateCase } from '../../containers/use_update_case'; import { getTypedPayload } from '../../containers/utils'; import type { OnUpdateFields } from './types'; -export const useOnUpdateField = ({ caseData }: { caseData: Case }) => { +export const useOnUpdateField = ({ caseData }: { caseData: CaseUI }) => { const { isLoading, updateKey: loadingKey, updateCaseProperty } = useUpdateCase(); const onUpdateField = useCallback( diff --git a/x-pack/plugins/cases/public/components/create/flyout/create_case_flyout.tsx b/x-pack/plugins/cases/public/components/create/flyout/create_case_flyout.tsx index 216d80a702dec..66c83d5b968cb 100644 --- a/x-pack/plugins/cases/public/components/create/flyout/create_case_flyout.tsx +++ b/x-pack/plugins/cases/public/components/create/flyout/create_case_flyout.tsx @@ -14,7 +14,7 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { noop } from 'lodash'; import type { CasePostRequest } from '../../../../common/api'; import * as i18n from '../translations'; -import type { Case } from '../../../../common/ui/types'; +import type { CaseUI } from '../../../../common/ui/types'; import { CreateCaseForm } from '../form'; import type { UseCreateAttachments } from '../../../containers/use_create_attachments'; import type { CaseAttachmentsWithoutOwner } from '../../../types'; @@ -22,11 +22,11 @@ import { casesQueryClient } from '../../cases_context/query_client'; export interface CreateCaseFlyoutProps { afterCaseCreated?: ( - theCase: Case, + theCase: CaseUI, createAttachments: UseCreateAttachments['createAttachments'] ) => Promise; onClose?: () => void; - onSuccess?: (theCase: Case) => void; + onSuccess?: (theCase: CaseUI) => void; attachments?: CaseAttachmentsWithoutOwner; headerContent?: React.ReactNode; initialValue?: Pick; diff --git a/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.tsx b/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.tsx index a92046e8c9928..a8e234f9bb96a 100644 --- a/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.tsx +++ b/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.tsx @@ -9,7 +9,7 @@ import type React from 'react'; import { useCallback } from 'react'; import type { CaseAttachmentsWithoutOwner } from '../../../types'; import { useCasesToast } from '../../../common/use_cases_toast'; -import type { Case } from '../../../containers/types'; +import type { CaseUI } from '../../../containers/types'; import { CasesContextStoreActionsList } from '../../cases_context/cases_context_reducer'; import { useCasesContext } from '../../cases_context/use_cases_context'; import type { CreateCaseFlyoutProps } from './create_case_flyout'; @@ -46,7 +46,7 @@ export const useCasesAddToNewCaseFlyout = (props: AddToNewCaseFlyoutProps = {}) return props.onClose(); } }, - onSuccess: async (theCase: Case) => { + onSuccess: async (theCase: CaseUI) => { if (theCase) { casesToasts.showSuccessAttach({ theCase, diff --git a/x-pack/plugins/cases/public/components/create/form.tsx b/x-pack/plugins/cases/public/components/create/form.tsx index 05dfef2063630..76344989ac0b2 100644 --- a/x-pack/plugins/cases/public/components/create/form.tsx +++ b/x-pack/plugins/cases/public/components/create/form.tsx @@ -24,7 +24,7 @@ import { Connector } from './connector'; import * as i18n from './translations'; import { SyncAlertsToggle } from './sync_alerts_toggle'; import type { ActionConnector, CasePostRequest } from '../../../common/api'; -import type { Case } from '../../containers/types'; +import type { CaseUI } from '../../containers/types'; import type { CasesTimelineIntegration } from '../timeline_context'; import { CasesTimelineIntegrationProvider } from '../timeline_context'; import { InsertTimeline } from '../insert_timeline'; @@ -69,9 +69,9 @@ export interface CreateCaseFormFieldsProps { } export interface CreateCaseFormProps extends Pick, 'withSteps'> { onCancel: () => void; - onSuccess: (theCase: Case) => void; + onSuccess: (theCase: CaseUI) => void; afterCaseCreated?: ( - theCase: Case, + theCase: CaseUI, createAttachments: UseCreateAttachments['createAttachments'] ) => Promise; timelineIntegration?: CasesTimelineIntegration; @@ -208,7 +208,7 @@ export const CreateCaseForm: React.FC = React.memo( onConfirmationCallback: handleOnConfirmationCallback, }); - const handleOnSuccess = (theCase: Case): void => { + const handleOnSuccess = (theCase: CaseUI): void => { removeItemFromSessionStorage(draftStorageKey); return onSuccess(theCase); }; diff --git a/x-pack/plugins/cases/public/components/create/form_context.tsx b/x-pack/plugins/cases/public/components/create/form_context.tsx index f3a78e8a1b9ca..d62f8e155badf 100644 --- a/x-pack/plugins/cases/public/components/create/form_context.tsx +++ b/x-pack/plugins/cases/public/components/create/form_context.tsx @@ -13,7 +13,7 @@ import { getNoneConnector, normalizeActionConnector } from '../configure_cases/u import { usePostCase } from '../../containers/use_post_case'; import { usePostPushToService } from '../../containers/use_post_push_to_service'; -import type { Case } from '../../containers/types'; +import type { CaseUI } from '../../containers/types'; import type { CasePostRequest } from '../../../common/api'; import { CaseSeverity, NONE_CONNECTOR_ID } from '../../../common/api'; import type { UseCreateAttachments } from '../../containers/use_create_attachments'; @@ -39,11 +39,11 @@ const initialCaseValue: FormProps = { interface Props { afterCaseCreated?: ( - theCase: Case, + theCase: CaseUI, createAttachments: UseCreateAttachments['createAttachments'] ) => Promise; children?: JSX.Element | JSX.Element[]; - onSuccess?: (theCase: Case) => void; + onSuccess?: (theCase: CaseUI) => void; attachments?: CaseAttachmentsWithoutOwner; initialValue?: Pick; } diff --git a/x-pack/plugins/cases/public/components/description/index.tsx b/x-pack/plugins/cases/public/components/description/index.tsx index 6ebbf8edd6f45..6373f1fb7ec6e 100644 --- a/x-pack/plugins/cases/public/components/description/index.tsx +++ b/x-pack/plugins/cases/public/components/description/index.tsx @@ -22,13 +22,13 @@ import * as i18n from '../user_actions/translations'; import { useCasesContext } from '../cases_context/use_cases_context'; import { useLensDraftComment } from '../markdown_editor/plugins/lens/use_lens_draft_comment'; import { EditableMarkdown, ScrollableMarkdown } from '../markdown_editor'; -import type { Case } from '../../containers/types'; +import type { CaseUI } from '../../containers/types'; import type { OnUpdateFields } from '../case_view/types'; import { schema } from './schema'; const DESCRIPTION_ID = 'description'; export interface DescriptionProps { - caseData: Case; + caseData: CaseUI; isLoadingDescription: boolean; onUpdateField: ({ key, value, onSuccess, onError }: OnUpdateFields) => void; } diff --git a/x-pack/plugins/cases/public/components/edit_connector/index.tsx b/x-pack/plugins/cases/public/components/edit_connector/index.tsx index 8a63c9d02ad26..fd2ca685b8854 100644 --- a/x-pack/plugins/cases/public/components/edit_connector/index.tsx +++ b/x-pack/plugins/cases/public/components/edit_connector/index.tsx @@ -22,7 +22,7 @@ import { isEmpty, noop } from 'lodash/fp'; import type { FieldConfig } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { Form, UseField, useForm } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import type { Case, CaseConnectors } from '../../../common/ui/types'; +import type { CaseUI, CaseConnectors } from '../../../common/ui/types'; import type { ActionConnector, CaseConnector, ConnectorTypeFields } from '../../../common/api'; import { NONE_CONNECTOR_ID } from '../../../common/api'; import { ConnectorSelector } from '../connector_selector/form'; @@ -37,7 +37,7 @@ import { PushCallouts } from './push_callouts'; import { normalizeActionConnector, getNoneConnector } from '../configure_cases/utils'; export interface EditConnectorProps { - caseData: Case; + caseData: CaseUI; caseConnectors: CaseConnectors; supportedActionConnectors: ActionConnector[]; isLoading: boolean; diff --git a/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.tsx b/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.tsx index 0418746eff912..482c198d15d63 100644 --- a/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.tsx +++ b/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.tsx @@ -8,14 +8,14 @@ import React, { memo } from 'react'; import { EuiModal, EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; -import type { Case } from '../../containers/types'; +import type { CaseUI } from '../../containers/types'; import * as i18n from '../../common/translations'; import { CreateCase } from '../create'; export interface CreateCaseModalProps { isModalOpen: boolean; onCloseCaseModal: () => void; - onSuccess: (theCase: Case) => Promise; + onSuccess: (theCase: CaseUI) => Promise; } const CreateModalComponent: React.FC = ({ diff --git a/x-pack/plugins/cases/public/components/use_create_case_modal/index.tsx b/x-pack/plugins/cases/public/components/use_create_case_modal/index.tsx index f640fd2b3df7c..92a24b615e383 100644 --- a/x-pack/plugins/cases/public/components/use_create_case_modal/index.tsx +++ b/x-pack/plugins/cases/public/components/use_create_case_modal/index.tsx @@ -6,11 +6,11 @@ */ import React, { useState, useCallback, useMemo } from 'react'; -import type { Case } from '../../../common/ui/types'; +import type { CaseUI } from '../../../common/ui/types'; import { CreateCaseModal } from './create_case_modal'; export interface UseCreateCaseModalProps { - onCaseCreated: (theCase: Case) => void; + onCaseCreated: (theCase: CaseUI) => void; } export interface UseCreateCaseModalReturnedValues { modal: JSX.Element; diff --git a/x-pack/plugins/cases/public/components/user_actions/types.ts b/x-pack/plugins/cases/public/components/user_actions/types.ts index 5146a97aba65b..f8ff85e05bf18 100644 --- a/x-pack/plugins/cases/public/components/user_actions/types.ts +++ b/x-pack/plugins/cases/public/components/user_actions/types.ts @@ -10,7 +10,7 @@ import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; import type { SnakeToCamelCase } from '../../../common/types'; import type { ActionTypes, UserActionWithResponse } from '../../../common/api'; import type { - Case, + CaseUI, CaseConnectors, CaseUserActions, Comment, @@ -31,7 +31,7 @@ export interface UserActionTreeProps { caseConnectors: CaseConnectors; userProfiles: Map; currentUserProfile: CurrentUserProfile; - data: Case; + data: CaseUI; getRuleDetailsHref?: RuleDetailsNavigation['href']; actionsNavigation?: ActionsNavigation; onRuleDetailsClick?: RuleDetailsNavigation['onClick']; @@ -48,7 +48,7 @@ export type SupportedUserActionTypes = keyof Omit; currentUserProfile: CurrentUserProfile; externalReferenceAttachmentTypeRegistry: ExternalReferenceAttachmentTypeRegistry; diff --git a/x-pack/plugins/cases/public/components/user_actions/use_user_actions_handler.tsx b/x-pack/plugins/cases/public/components/user_actions/use_user_actions_handler.tsx index e19dbea584fc8..5c9bb98ccb2a2 100644 --- a/x-pack/plugins/cases/public/components/user_actions/use_user_actions_handler.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/use_user_actions_handler.tsx @@ -7,7 +7,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'; import { useCaseViewParams } from '../../common/navigation'; -import type { Case } from '../../containers/types'; +import type { CaseUI } from '../../containers/types'; import { useLensDraftComment } from '../markdown_editor/plugins/lens/use_lens_draft_comment'; import { useUpdateComment } from '../../containers/use_update_comment'; import type { AddCommentRefObject } from '../add_comment'; @@ -28,7 +28,7 @@ export type UseUserActionsHandler = Pick< | 'handleSaveComment' | 'handleManageQuote' | 'handleDeleteComment' -> & { handleUpdate: (updatedCase: Case) => void }; +> & { handleUpdate: (updatedCase: CaseUI) => void }; const isAddCommentRef = ( ref: AddCommentRefObject | UserActionMarkdownRefObject | null | undefined diff --git a/x-pack/plugins/cases/public/containers/__mocks__/api.ts b/x-pack/plugins/cases/public/containers/__mocks__/api.ts index b29e45f6f101e..19aea63bdb0bf 100644 --- a/x-pack/plugins/cases/public/containers/__mocks__/api.ts +++ b/x-pack/plugins/cases/public/containers/__mocks__/api.ts @@ -7,8 +7,8 @@ import type { ActionLicense, - Cases, - Case, + CasesUI, + CaseUI, CasesStatus, FetchCasesProps, FindCaseUserActions, @@ -53,7 +53,7 @@ export const getCase = async ( caseId: string, includeComments: boolean = true, signal: AbortSignal -): Promise => Promise.resolve(basicCase); +): Promise => Promise.resolve(basicCase); export const resolveCase = async ( caseId: string, @@ -101,9 +101,9 @@ export const getCases = async ({ sortOrder: 'desc', }, signal, -}: FetchCasesProps): Promise => Promise.resolve(allCases); +}: FetchCasesProps): Promise => Promise.resolve(allCases); -export const postCase = async (newCase: CasePostRequest, signal: AbortSignal): Promise => +export const postCase = async (newCase: CasePostRequest, signal: AbortSignal): Promise => Promise.resolve(basicCasePost); export const patchCase = async ( @@ -111,18 +111,18 @@ export const patchCase = async ( updatedCase: Pick, version: string, signal: AbortSignal -): Promise => Promise.resolve([basicCase]); +): Promise => Promise.resolve([basicCase]); export const updateCases = async ( cases: CaseUpdateRequest[], signal: AbortSignal -): Promise => Promise.resolve(allCases.cases); +): Promise => Promise.resolve(allCases.cases); export const createAttachments = async ( newComment: CommentRequest, caseId: string, signal: AbortSignal -): Promise => Promise.resolve(basicCase); +): Promise => Promise.resolve(basicCase); export const deleteComment = async ( caseId: string, @@ -136,7 +136,7 @@ export const patchComment = async ( commentUpdate: string, version: string, signal: AbortSignal -): Promise => Promise.resolve(basicCaseCommentPatch); +): Promise => Promise.resolve(basicCaseCommentPatch); export const deleteCases = async (caseIds: string[], signal: AbortSignal): Promise => Promise.resolve(true); @@ -145,7 +145,7 @@ export const pushCase = async ( caseId: string, connectorId: string, signal: AbortSignal -): Promise => Promise.resolve(pushedCase); +): Promise => Promise.resolve(pushedCase); export const getActionLicense = async (signal: AbortSignal): Promise => Promise.resolve(actionLicenses); diff --git a/x-pack/plugins/cases/public/containers/api.ts b/x-pack/plugins/cases/public/containers/api.ts index a45bfa3752c91..2d9e17658d156 100644 --- a/x-pack/plugins/cases/public/containers/api.ts +++ b/x-pack/plugins/cases/public/containers/api.ts @@ -9,7 +9,6 @@ import type { ValidFeatureId } from '@kbn/rule-data-utils'; import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common/constants'; import type { CaseConnectors, - Cases, CaseUpdateRequest, FetchCasesProps, ResolvedCase, @@ -17,15 +16,14 @@ import type { CaseUserActionTypeWithAll, CaseUserActionsStats, CaseUsers, + CasesUI, } from '../../common/ui/types'; import { SeverityAll, SortFieldCase, StatusAll } from '../../common/ui/types'; import type { BulkCreateCommentRequest, CasePatchRequest, CasePostRequest, - CaseResponse, CaseResolveResponse, - CasesResponse, UserActionFindResponse, CommentRequest, User, @@ -33,6 +31,8 @@ import type { CasesFindResponse, GetCaseConnectorsResponse, CaseUserActionStatsResponse, + Case, + Cases, } from '../../common/api'; import { CommentType, @@ -69,7 +69,7 @@ import { import type { ActionLicense, - Case, + CaseUI, SingleCaseMetrics, SingleCaseMetricsFeature, CaseUserActions, @@ -91,8 +91,8 @@ export const getCase = async ( caseId: string, includeComments: boolean = true, signal: AbortSignal -): Promise => { - const response = await KibanaServices.get().http.fetch(getCaseDetailsUrl(caseId), { +): Promise => { + const response = await KibanaServices.get().http.fetch(getCaseDetailsUrl(caseId), { method: 'GET', query: { includeComments, @@ -223,7 +223,7 @@ export const getCases = async ({ sortOrder: 'desc', }, signal, -}: FetchCasesProps): Promise => { +}: FetchCasesProps): Promise => { const query = { ...(filterOptions.status !== StatusAll ? { status: filterOptions.status } : {}), ...(filterOptions.severity !== SeverityAll ? { severity: filterOptions.severity } : {}), @@ -245,8 +245,8 @@ export const getCases = async ({ return convertAllCasesToCamel(decodeCasesFindResponse(response)); }; -export const postCase = async (newCase: CasePostRequest, signal: AbortSignal): Promise => { - const response = await KibanaServices.get().http.fetch(CASES_URL, { +export const postCase = async (newCase: CasePostRequest, signal: AbortSignal): Promise => { + const response = await KibanaServices.get().http.fetch(CASES_URL, { method: 'POST', body: JSON.stringify(newCase), signal, @@ -262,8 +262,8 @@ export const patchCase = async ( >, version: string, signal: AbortSignal -): Promise => { - const response = await KibanaServices.get().http.fetch(CASES_URL, { +): Promise => { + const response = await KibanaServices.get().http.fetch(CASES_URL, { method: 'PATCH', body: JSON.stringify({ cases: [{ ...updatedCase, id: caseId, version }] }), signal, @@ -274,12 +274,12 @@ export const patchCase = async ( export const updateCases = async ( cases: CaseUpdateRequest[], signal: AbortSignal -): Promise => { +): Promise => { if (cases.length === 0) { return []; } - const response = await KibanaServices.get().http.fetch(CASES_URL, { + const response = await KibanaServices.get().http.fetch(CASES_URL, { method: 'PATCH', body: JSON.stringify({ cases }), signal, @@ -292,15 +292,12 @@ export const postComment = async ( newComment: CommentRequest, caseId: string, signal: AbortSignal -): Promise => { - const response = await KibanaServices.get().http.fetch( - `${CASES_URL}/${caseId}/comments`, - { - method: 'POST', - body: JSON.stringify(newComment), - signal, - } - ); +): Promise => { + const response = await KibanaServices.get().http.fetch(`${CASES_URL}/${caseId}/comments`, { + method: 'POST', + body: JSON.stringify(newComment), + signal, + }); return convertCaseToCamelCase(decodeCaseResponse(response)); }; @@ -318,8 +315,8 @@ export const patchComment = async ({ version: string; signal: AbortSignal; owner: string; -}): Promise => { - const response = await KibanaServices.get().http.fetch(getCaseCommentsUrl(caseId), { +}): Promise => { + const response = await KibanaServices.get().http.fetch(getCaseCommentsUrl(caseId), { method: 'PATCH', body: JSON.stringify({ comment: commentUpdate, @@ -342,7 +339,7 @@ export const deleteComment = async ({ commentId: string; signal: AbortSignal; }): Promise => { - await KibanaServices.get().http.fetch(getCaseCommentDeleteUrl(caseId, commentId), { + await KibanaServices.get().http.fetch(getCaseCommentDeleteUrl(caseId, commentId), { method: 'DELETE', signal, }); @@ -361,8 +358,8 @@ export const pushCase = async ( caseId: string, connectorId: string, signal: AbortSignal -): Promise => { - const response = await KibanaServices.get().http.fetch( +): Promise => { + const response = await KibanaServices.get().http.fetch( getCasePushUrl(caseId, connectorId), { method: 'POST', @@ -390,8 +387,8 @@ export const createAttachments = async ( attachments: BulkCreateCommentRequest, caseId: string, signal: AbortSignal -): Promise => { - const response = await KibanaServices.get().http.fetch( +): Promise => { + const response = await KibanaServices.get().http.fetch( INTERNAL_BULK_CREATE_ATTACHMENTS_URL.replace('{case_id}', caseId), { method: 'POST', diff --git a/x-pack/plugins/cases/public/containers/mock.ts b/x-pack/plugins/cases/public/containers/mock.ts index a4192513d7bec..d2ff6a1c0de6f 100644 --- a/x-pack/plugins/cases/public/containers/mock.ts +++ b/x-pack/plugins/cases/public/containers/mock.ts @@ -6,7 +6,14 @@ */ import type { FileJSON } from '@kbn/shared-ux-file-types'; -import type { ActionLicense, Cases, Case, CasesStatus, CaseUserActions, Comment } from './types'; +import type { + ActionLicense, + CasesUI, + CaseUI, + CasesStatus, + CaseUserActions, + Comment, +} from './types'; import type { ResolvedCase, @@ -22,9 +29,9 @@ import type { } from '../../common/ui/types'; import type { CaseConnector, - CaseResponse, + Case, CasesFindResponse, - CasesResponse, + Cases, CasesStatusResponse, CaseUserActionResponse, CaseUserActionsResponse, @@ -208,7 +215,7 @@ export const persistableStateAttachment: PersistableComment = { version: 'WzQ3LDFc', }; -export const basicCase: Case = { +export const basicCase: CaseUI = { owner: SECURITY_SOLUTION_OWNER, closedAt: null, closedBy: null, @@ -325,7 +332,7 @@ export const basicCaseMetrics: SingleCaseMetrics = { }, }; -export const mockCase: Case = { +export const mockCase: CaseUI = { owner: SECURITY_SOLUTION_OWNER, closedAt: null, closedBy: null, @@ -357,7 +364,7 @@ export const mockCase: Case = { assignees: [], }; -export const basicCasePost: Case = { +export const basicCasePost: CaseUI = { ...basicCase, updatedAt: null, updatedBy: null, @@ -398,7 +405,7 @@ export const basicPush = { pushedBy: elasticUser, }; -export const pushedCase: Case = { +export const pushedCase: CaseUI = { ...basicCase, connector: { id: pushConnectorId, @@ -419,7 +426,7 @@ const basicAction = { type: 'title', }; -export const cases: Case[] = [ +export const cases: CaseUI[] = [ basicCase, { ...pushedCase, @@ -437,7 +444,7 @@ export const cases: Case[] = [ caseWithRegisteredAttachments, ]; -export const allCases: Cases = { +export const allCases: CasesUI = { cases, page: 1, perPage: 5, @@ -515,7 +522,7 @@ export const persistableStateAttachmentSnake: CommentResponse = { version: 'WzQ3LDFc', }; -export const basicCaseSnake: CaseResponse = { +export const basicCaseSnake: Case = { ...basicCase, status: CaseStatuses.open, closed_at: null, @@ -529,7 +536,7 @@ export const basicCaseSnake: CaseResponse = { updated_at: basicUpdatedAt, updated_by: elasticUserSnake, owner: SECURITY_SOLUTION_OWNER, -} as CaseResponse; +} as Case; export const caseWithAlertsSnake = { ...basicCaseSnake, @@ -583,7 +590,7 @@ export const pushedCaseSnake = { external_service: { ...basicPushSnake, connector_id: pushConnectorId }, }; -export const casesSnake: CasesResponse = [ +export const casesSnake: Cases = [ basicCaseSnake, { ...pushedCaseSnake, @@ -910,7 +917,7 @@ export const useGetCasesMockState = { isError: false, }; -export const basicCaseClosed: Case = { +export const basicCaseClosed: CaseUI = { ...basicCase, closedAt: '2020-02-25T23:06:33.798Z', closedBy: elasticUser, diff --git a/x-pack/plugins/cases/public/containers/use_create_attachments.tsx b/x-pack/plugins/cases/public/containers/use_create_attachments.tsx index 074b85839c4d9..38cb5de7ee513 100644 --- a/x-pack/plugins/cases/public/containers/use_create_attachments.tsx +++ b/x-pack/plugins/cases/public/containers/use_create_attachments.tsx @@ -9,7 +9,7 @@ import { useReducer, useCallback, useRef, useEffect } from 'react'; import { createAttachments } from './api'; import * as i18n from './translations'; -import type { Case } from './types'; +import type { CaseUI } from './types'; import { useToasts } from '../common/lib/kibana'; import type { CaseAttachmentsWithoutOwner } from '../types'; @@ -45,7 +45,7 @@ export interface PostComment { caseId: string; caseOwner: string; data: CaseAttachmentsWithoutOwner; - updateCase?: (newCase: Case) => void; + updateCase?: (newCase: CaseUI) => void; throwOnError?: boolean; } export interface UseCreateAttachments extends NewCommentState { diff --git a/x-pack/plugins/cases/public/containers/use_get_cases.tsx b/x-pack/plugins/cases/public/containers/use_get_cases.tsx index b9f55cc77682f..356534d60cc06 100644 --- a/x-pack/plugins/cases/public/containers/use_get_cases.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_cases.tsx @@ -8,7 +8,7 @@ import type { UseQueryResult } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query'; import { casesQueriesKeys, DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from './constants'; -import type { Cases, FilterOptions, QueryParams } from './types'; +import type { CasesUI, FilterOptions, QueryParams } from './types'; import { SortFieldCase, StatusAll, SeverityAll } from './types'; import { useToasts } from '../common/lib/kibana'; import * as i18n from './translations'; @@ -35,7 +35,7 @@ export const DEFAULT_QUERY_PARAMS: QueryParams = { sortOrder: 'desc', }; -export const initialData: Cases = { +export const initialData: CasesUI = { cases: [], countClosedCases: 0, countInProgressCases: 0, @@ -50,7 +50,7 @@ export const useGetCases = ( queryParams?: Partial; filterOptions?: Partial; } = {} -): UseQueryResult => { +): UseQueryResult => { const toasts = useToasts(); return useQuery( casesQueriesKeys.cases(params), diff --git a/x-pack/plugins/cases/public/containers/use_post_push_to_service.tsx b/x-pack/plugins/cases/public/containers/use_post_push_to_service.tsx index d13500dcbc5fa..bda1c3bc37d54 100644 --- a/x-pack/plugins/cases/public/containers/use_post_push_to_service.tsx +++ b/x-pack/plugins/cases/public/containers/use_post_push_to_service.tsx @@ -10,7 +10,7 @@ import type { CaseConnector } from '../../common/api'; import { pushCase } from './api'; import * as i18n from './translations'; -import type { Case } from './types'; +import type { CaseUI } from './types'; import { useToasts } from '../common/lib/kibana'; interface PushToServiceState { @@ -53,7 +53,7 @@ export interface UsePostPushToService extends PushToServiceState { pushCaseToExternalService: ({ caseId, connector, - }: PushToServiceRequest) => Promise; + }: PushToServiceRequest) => Promise; } export const usePostPushToService = (): UsePostPushToService => { diff --git a/x-pack/plugins/cases/public/containers/utils.test.ts b/x-pack/plugins/cases/public/containers/utils.test.ts index c87c81a02f818..b7a0b17ec5ff0 100644 --- a/x-pack/plugins/cases/public/containers/utils.test.ts +++ b/x-pack/plugins/cases/public/containers/utils.test.ts @@ -13,7 +13,7 @@ import { constructReportersFilter, } from './utils'; -import type { Case } from './types'; +import type { CaseUI } from './types'; const caseBeforeUpdate = { comments: [ @@ -24,9 +24,9 @@ const caseBeforeUpdate = { settings: { syncAlerts: true, }, -} as Case; +} as CaseUI; -const caseAfterUpdate = { title: 'My case' } as Case; +const caseAfterUpdate = { title: 'My case' } as CaseUI; describe('utils', () => { describe('valueToUpdateIsSettings', () => { diff --git a/x-pack/plugins/cases/public/containers/utils.ts b/x-pack/plugins/cases/public/containers/utils.ts index 733e5bd08de7a..66b540040415f 100644 --- a/x-pack/plugins/cases/public/containers/utils.ts +++ b/x-pack/plugins/cases/public/containers/utils.ts @@ -13,8 +13,6 @@ import { pipe } from 'fp-ts/lib/pipeable'; import type { ToastInputFields } from '@kbn/core/public'; import { NO_ASSIGNEES_FILTERING_KEYWORD } from '../../common/constants'; import type { - CaseResponse, - CasesResponse, CasesConfigurationsResponse, CasesConfigureResponse, CaseUserActionsResponse, @@ -23,10 +21,12 @@ import type { SingleCaseMetricsResponse, User, CaseUserActionStatsResponse, + Case, + Cases, } from '../../common/api'; import { - CaseResponseRt, - CasesResponseRt, + CaseRt, + CasesRt, throwErrors, CaseConfigurationsResponseRt, CaseConfigureResponseRt, @@ -36,7 +36,7 @@ import { SingleCaseMetricsResponseRt, CaseUserActionStatsResponseRt, } from '../../common/api'; -import type { Case, FilterOptions, UpdateByKey } from './types'; +import type { CaseUI, FilterOptions, UpdateByKey } from './types'; import * as i18n from './translations'; export const getTypedPayload = (a: unknown): T => a as T; @@ -49,8 +49,8 @@ export const covertToSnakeCase = (obj: Record) => export const createToasterPlainError = (message: string) => new ToasterError([message]); -export const decodeCaseResponse = (respCase?: CaseResponse) => - pipe(CaseResponseRt.decode(respCase), fold(throwErrors(createToasterPlainError), identity)); +export const decodeCaseResponse = (respCase?: Case) => + pipe(CaseRt.decode(respCase), fold(throwErrors(createToasterPlainError), identity)); export const decodeCaseResolveResponse = (respCase?: CaseResolveResponse) => pipe( @@ -64,8 +64,8 @@ export const decodeSingleCaseMetricsResponse = (respCase?: SingleCaseMetricsResp fold(throwErrors(createToasterPlainError), identity) ); -export const decodeCasesResponse = (respCase?: CasesResponse) => - pipe(CasesResponseRt.decode(respCase), fold(throwErrors(createToasterPlainError), identity)); +export const decodeCasesResponse = (respCase?: Cases) => + pipe(CasesRt.decode(respCase), fold(throwErrors(createToasterPlainError), identity)); export const decodeCaseConfigurationsResponse = (respCase?: CasesConfigurationsResponse) => { return pipe( @@ -114,8 +114,8 @@ export class ToasterError extends Error { } } export const createUpdateSuccessToaster = ( - caseBeforeUpdate: Case, - caseAfterUpdate: Case, + caseBeforeUpdate: CaseUI, + caseAfterUpdate: CaseUI, key: UpdateByKey['updateKey'], value: UpdateByKey['updateValue'] ): ToastInputFields => { diff --git a/x-pack/plugins/cases/public/types.ts b/x-pack/plugins/cases/public/types.ts index 6b88c79abb6a3..be2275c8c0980 100644 --- a/x-pack/plugins/cases/public/types.ts +++ b/x-pack/plugins/cases/public/types.ts @@ -25,7 +25,7 @@ import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { FilesSetup, FilesStart } from '@kbn/files-plugin/public'; import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import type { - CaseResponse, + Case, CasesBulkGetRequestCertainFields, CasesBulkGetResponseCertainFields, CasesByAlertId, @@ -48,7 +48,7 @@ import type { GetCasesProps } from './client/ui/get_cases'; import type { GetAllCasesSelectorModalProps } from './client/ui/get_all_cases_selector_modal'; import type { GetCreateCaseFlyoutProps } from './client/ui/get_create_case_flyout'; import type { GetRecentCasesProps } from './client/ui/get_recent_cases'; -import type { Cases, CasesStatus, CasesMetrics } from '../common/ui'; +import type { CasesUI, CasesStatus, CasesMetrics } from '../common/ui'; import type { GroupAlertsByRule } from './client/helpers/group_alerts_by_rule'; import type { getUICapabilities } from './client/helpers/capabilities'; import type { AttachmentFramework } from './client/attachment_framework/types'; @@ -103,10 +103,10 @@ export interface CasesUiStart { api: { getRelatedCases: (alertId: string, query: CasesByAlertIDRequest) => Promise; cases: { - find: (query: CasesFindRequest, signal?: AbortSignal) => Promise; + find: (query: CasesFindRequest, signal?: AbortSignal) => Promise; getCasesStatus: (query: CasesStatusRequest, signal?: AbortSignal) => Promise; getCasesMetrics: (query: CasesMetricsRequest, signal?: AbortSignal) => Promise; - bulkGet: ( + bulkGet: ( params: CasesBulkGetRequestCertainFields, signal?: AbortSignal ) => Promise>; diff --git a/x-pack/plugins/cases/server/client/attachments/add.ts b/x-pack/plugins/cases/server/client/attachments/add.ts index 920adca9dc1bf..ae4d4aab68e1d 100644 --- a/x-pack/plugins/cases/server/client/attachments/add.ts +++ b/x-pack/plugins/cases/server/client/attachments/add.ts @@ -12,7 +12,7 @@ import { identity } from 'fp-ts/lib/function'; import { SavedObjectsUtils } from '@kbn/core/server'; -import type { CaseResponse } from '../../../common/api'; +import type { Case } from '../../../common/api'; import { CommentRequestRt, throwErrors } from '../../../common/api'; import { CaseCommentModel } from '../../common/models'; @@ -29,10 +29,7 @@ import { validateRegisteredAttachments } from './validators'; * * @ignore */ -export const addComment = async ( - addArgs: AddArgs, - clientArgs: CasesClientArgs -): Promise => { +export const addComment = async (addArgs: AddArgs, clientArgs: CasesClientArgs): Promise => { const { comment, caseId } = addArgs; const query = pipe( CommentRequestRt.decode(comment), diff --git a/x-pack/plugins/cases/server/client/attachments/bulk_create.ts b/x-pack/plugins/cases/server/client/attachments/bulk_create.ts index 1213f9a373b7c..e989410a7a389 100644 --- a/x-pack/plugins/cases/server/client/attachments/bulk_create.ts +++ b/x-pack/plugins/cases/server/client/attachments/bulk_create.ts @@ -12,7 +12,7 @@ import { identity } from 'fp-ts/lib/function'; import { SavedObjectsUtils } from '@kbn/core/server'; -import type { CaseResponse, CommentRequest } from '../../../common/api'; +import type { Case, CommentRequest } from '../../../common/api'; import { BulkCreateCommentRequestRt, throwErrors } from '../../../common/api'; import { CaseCommentModel } from '../../common/models'; @@ -33,7 +33,7 @@ import { validateRegisteredAttachments } from './validators'; export const bulkCreate = async ( args: BulkCreateArgs, clientArgs: CasesClientArgs -): Promise => { +): Promise => { const { attachments, caseId } = args; pipe( diff --git a/x-pack/plugins/cases/server/client/attachments/client.ts b/x-pack/plugins/cases/server/client/attachments/client.ts index 5b204a21929c2..e4244b32d1e7d 100644 --- a/x-pack/plugins/cases/server/client/attachments/client.ts +++ b/x-pack/plugins/cases/server/client/attachments/client.ts @@ -9,7 +9,7 @@ import type { AlertResponse, AllCommentsResponse, BulkGetAttachmentsResponse, - CaseResponse, + Case, CommentResponse, CommentsResponse, } from '../../../common/api'; @@ -45,8 +45,8 @@ export interface AttachmentsSubClient { /** * Adds an attachment to a case. */ - add(params: AddArgs): Promise; - bulkCreate(params: BulkCreateArgs): Promise; + add(params: AddArgs): Promise; + bulkCreate(params: BulkCreateArgs): Promise; bulkGet(params: BulkGetArgs): Promise; /** * Deletes all attachments associated with a single case. @@ -78,7 +78,7 @@ export interface AttachmentsSubClient { * * The request must include all fields for the attachment. Even the fields that are not changing. */ - update(updateArgs: UpdateArgs): Promise; + update(updateArgs: UpdateArgs): Promise; } /** diff --git a/x-pack/plugins/cases/server/client/attachments/update.ts b/x-pack/plugins/cases/server/client/attachments/update.ts index 692e2f6b15204..213d4a86ea242 100644 --- a/x-pack/plugins/cases/server/client/attachments/update.ts +++ b/x-pack/plugins/cases/server/client/attachments/update.ts @@ -10,7 +10,7 @@ import Boom from '@hapi/boom'; import { CaseCommentModel } from '../../common/models'; import { createCaseError } from '../../common/error'; import { isCommentRequestTypeExternalReference } from '../../../common/utils/attachments'; -import type { CaseResponse } from '../../../common/api'; +import type { Case } from '../../../common/api'; import { CASE_SAVED_OBJECT } from '../../../common/constants'; import type { CasesClientArgs } from '..'; import { decodeCommentRequest } from '../utils'; @@ -25,7 +25,7 @@ import type { UpdateArgs } from './types'; export async function update( { caseID, updateRequest: queryParams }: UpdateArgs, clientArgs: CasesClientArgs -): Promise { +): Promise { const { services: { attachmentService }, logger, diff --git a/x-pack/plugins/cases/server/client/cases/bulk_get.test.ts b/x-pack/plugins/cases/server/client/cases/bulk_get.test.ts index 8628fa64056ad..fd68bd7e8d36d 100644 --- a/x-pack/plugins/cases/server/client/cases/bulk_get.test.ts +++ b/x-pack/plugins/cases/server/client/cases/bulk_get.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import type { CaseResponse } from '../../../common/api'; -import { getTypeProps, CaseResponseRt } from '../../../common/api'; +import type { Case } from '../../../common/api'; +import { getTypeProps, CaseRt } from '../../../common/api'; import { mockCases } from '../../mocks'; import { createCasesClientMockArgs } from '../mocks'; import { bulkGet } from './bulk_get'; @@ -39,8 +39,8 @@ describe('bulkGet', () => { unauthorized: [], }); - const typeProps = getTypeProps(CaseResponseRt) ?? {}; - const validFields = Object.keys(typeProps) as Array; + const typeProps = getTypeProps(CaseRt) ?? {}; + const validFields = Object.keys(typeProps) as Array; beforeEach(() => { jest.clearAllMocks(); diff --git a/x-pack/plugins/cases/server/client/cases/bulk_get.ts b/x-pack/plugins/cases/server/client/cases/bulk_get.ts index 85952b84bef91..3c2542c244874 100644 --- a/x-pack/plugins/cases/server/client/cases/bulk_get.ts +++ b/x-pack/plugins/cases/server/client/cases/bulk_get.ts @@ -16,31 +16,31 @@ import type { CasesBulkGetResponse, CasesBulkGetResponseCertainFields, CasesBulkGetRequestCertainFields, - CaseResponse, + Case, CaseAttributes, } from '../../../common/api'; import { CasesBulkGetRequestRt, - CasesResponseRt, + CasesRt, excess, throwErrors, getTypeForCertainFieldsFromArray, - CaseResponseRt, + CaseRt, } from '../../../common/api'; import { getTypeProps } from '../../../common/api/runtime_types'; import { createCaseError } from '../../common/error'; import { asArray, flattenCaseSavedObject } from '../../common/utils'; import type { CasesClientArgs, SOWithErrors } from '../types'; import { includeFieldsRequiredForAuthentication } from '../../authorization/utils'; -import type { CaseSavedObject } from '../../common/types'; import { Operations } from '../../authorization'; +import type { CaseSavedObjectTransformed } from '../../common/types/case'; type CaseSavedObjectWithErrors = SOWithErrors; /** * Retrieves multiple cases by ids. */ -export const bulkGet = async ( +export const bulkGet = async ( params: CasesBulkGetRequestCertainFields, clientArgs: CasesClientArgs ): Promise> => { @@ -66,7 +66,7 @@ export const bulkGet = async caseInfo.error === undefined - ) as [CaseSavedObject[], CaseSavedObjectWithErrors]; + ) as [CaseSavedObjectTransformed[], CaseSavedObjectWithErrors]; const { authorized: authorizedCases, unauthorized: unauthorizedCases } = await authorization.getAndEnsureAuthorizedEntities({ @@ -103,7 +103,7 @@ export const bulkGet = async { return; } - const typeProps = getTypeProps(CaseResponseRt) ?? {}; + const typeProps = getTypeProps(CaseRt) ?? {}; const validFields = Object.keys(typeProps); for (const field of fields) { @@ -142,7 +142,7 @@ const throwErrorIfCaseIdsReachTheLimit = (ids: string[]) => { const constructErrors = ( soBulkGetErrors: CaseSavedObjectWithErrors, - unauthorizedCases: CaseSavedObject[] + unauthorizedCases: CaseSavedObjectTransformed[] ): CasesBulkGetResponse['errors'] => { const errors: CasesBulkGetResponse['errors'] = []; diff --git a/x-pack/plugins/cases/server/client/cases/client.ts b/x-pack/plugins/cases/server/client/cases/client.ts index bf3253fda6558..a014eeec56a6c 100644 --- a/x-pack/plugins/cases/server/client/cases/client.ts +++ b/x-pack/plugins/cases/server/client/cases/client.ts @@ -13,7 +13,7 @@ import type { AllTagsFindRequest, AllReportersFindRequest, CasesByAlertId, - CaseResponse, + Case, CasesBulkGetRequestCertainFields, CasesBulkGetResponseCertainFields, } from '../../../common/api'; @@ -65,7 +65,7 @@ export interface CasesSubClient { /** * Retrieves multiple cases with the specified IDs. */ - bulkGet( + bulkGet( params: CasesBulkGetRequestCertainFields ): Promise>; /** diff --git a/x-pack/plugins/cases/server/client/cases/create.ts b/x-pack/plugins/cases/server/client/cases/create.ts index a8f9975fee39f..1d1a687ee9998 100644 --- a/x-pack/plugins/cases/server/client/cases/create.ts +++ b/x-pack/plugins/cases/server/client/cases/create.ts @@ -12,10 +12,10 @@ import { identity } from 'fp-ts/lib/function'; import { SavedObjectsUtils } from '@kbn/core/server'; -import type { CaseResponse, CasePostRequest } from '../../../common/api'; +import type { Case, CasePostRequest } from '../../../common/api'; import { throwErrors, - CaseResponseRt, + CaseRt, ActionTypes, CasePostRequestRt, excess, @@ -35,10 +35,7 @@ import { LICENSING_CASE_ASSIGNMENT_FEATURE } from '../../common/constants'; * * @ignore */ -export const create = async ( - data: CasePostRequest, - clientArgs: CasesClientArgs -): Promise => { +export const create = async (data: CasePostRequest, clientArgs: CasesClientArgs): Promise => { const { services: { caseService, userActionService, licensingService, notificationService }, user, @@ -129,7 +126,7 @@ export const create = async ( }); } - return CaseResponseRt.encode(flattenedCase); + return CaseRt.encode(flattenedCase); } catch (error) { throw createCaseError({ message: `Failed to create case: ${error}`, error, logger }); } diff --git a/x-pack/plugins/cases/server/client/cases/find.test.ts b/x-pack/plugins/cases/server/client/cases/find.test.ts index f23ad82df1fcf..bb0701647d8af 100644 --- a/x-pack/plugins/cases/server/client/cases/find.test.ts +++ b/x-pack/plugins/cases/server/client/cases/find.test.ts @@ -6,7 +6,7 @@ */ import { v1 as uuidv1 } from 'uuid'; -import type { CaseResponse } from '../../../common/api'; +import type { Case } from '../../../common/api'; import { flattenCaseSavedObject } from '../../common/utils'; import { mockCases } from '../../mocks'; @@ -16,7 +16,7 @@ import { find } from './find'; describe('find', () => { describe('constructSearch', () => { const clientArgs = createCasesClientMockArgs(); - const casesMap = new Map( + const casesMap = new Map( mockCases.map((obj) => { return [obj.id, flattenCaseSavedObject({ savedObject: obj, totalComment: 2 })]; }) diff --git a/x-pack/plugins/cases/server/client/cases/get.ts b/x-pack/plugins/cases/server/client/cases/get.ts index 669efc96c960c..88668f04f7f36 100644 --- a/x-pack/plugins/cases/server/client/cases/get.ts +++ b/x-pack/plugins/cases/server/client/cases/get.ts @@ -11,7 +11,7 @@ import { identity } from 'fp-ts/lib/function'; import type { SavedObjectsResolveResponse } from '@kbn/core/server'; import type { - CaseResponse, + Case, CaseResolveResponse, User, AllTagsFindRequest, @@ -22,7 +22,7 @@ import type { AttachmentTotals, } from '../../../common/api'; import { - CaseResponseRt, + CaseRt, CaseResolveResponseRt, AllTagsFindRequestRt, excess, @@ -37,7 +37,7 @@ import type { CasesClientArgs } from '..'; import { Operations } from '../../authorization'; import { combineAuthorizedAndOwnerFilter } from '../utils'; import { CasesService } from '../../services'; -import type { CaseSavedObject } from '../../common/types'; +import type { CaseSavedObjectTransformed } from '../../common/types/case'; /** * Parameters for finding cases IDs using an alert ID @@ -173,7 +173,7 @@ export interface GetParams { export const get = async ( { id, includeComments }: GetParams, clientArgs: CasesClientArgs -): Promise => { +): Promise => { const { services: { caseService }, logger, @@ -181,7 +181,7 @@ export const get = async ( } = clientArgs; try { - const theCase: CaseSavedObject = await caseService.getCase({ + const theCase: CaseSavedObjectTransformed = await caseService.getCase({ id, }); @@ -191,7 +191,7 @@ export const get = async ( }); if (!includeComments) { - return CaseResponseRt.encode( + return CaseRt.encode( flattenCaseSavedObject({ savedObject: theCase, }) @@ -206,7 +206,7 @@ export const get = async ( }, }); - return CaseResponseRt.encode( + return CaseRt.encode( flattenCaseSavedObject({ savedObject: theCase, comments: theComments.saved_objects, diff --git a/x-pack/plugins/cases/server/client/cases/push.ts b/x-pack/plugins/cases/server/client/cases/push.ts index 4f3ab74557278..da30764c45e4b 100644 --- a/x-pack/plugins/cases/server/client/cases/push.ts +++ b/x-pack/plugins/cases/server/client/cases/push.ts @@ -14,19 +14,13 @@ import type { SecurityPluginStart } from '@kbn/security-plugin/server'; import { asSavedObjectExecutionSource } from '@kbn/actions-plugin/server'; import type { ActionConnector, - CaseResponse, + Case, ExternalServiceResponse, CasesConfigureAttributes, CommentRequestAlertType, CommentAttributes, } from '../../../common/api'; -import { - CaseResponseRt, - CaseStatuses, - ActionTypes, - OWNER_FIELD, - CommentType, -} from '../../../common/api'; +import { CaseRt, CaseStatuses, ActionTypes, OWNER_FIELD, CommentType } from '../../../common/api'; import { CASE_COMMENT_SAVED_OBJECT, CASE_SAVED_OBJECT } from '../../../common/constants'; import { createIncident, getDurationInSeconds, getUserProfiles } from './utils'; @@ -103,7 +97,7 @@ export const push = async ( clientArgs: CasesClientArgs, casesClient: CasesClient, casesClientInternal: CasesClientInternal -): Promise => { +): Promise => { const { unsecuredSavedObjectsClient, services: { @@ -282,7 +276,7 @@ export const push = async ( /* End of update case with push information */ - return CaseResponseRt.encode( + return CaseRt.encode( flattenCaseSavedObject({ savedObject: { ...myCase, diff --git a/x-pack/plugins/cases/server/client/cases/update.ts b/x-pack/plugins/cases/server/client/cases/update.ts index f1f13c6ed362a..07423b4904685 100644 --- a/x-pack/plugins/cases/server/client/cases/update.ts +++ b/x-pack/plugins/cases/server/client/cases/update.ts @@ -25,15 +25,15 @@ import type { CaseAssignees, CaseAttributes, CasePatchRequest, - CaseResponse, + Case, CasesPatchRequest, - CasesResponse, + Cases, CommentAttributes, User, } from '../../../common/api'; import { CasesPatchRequestRt, - CasesResponseRt, + CasesRt, CaseStatuses, CommentType, excess, @@ -62,7 +62,7 @@ import { Operations } from '../../authorization'; import { dedupAssignees, getClosedInfoForUpdate, getDurationForUpdate } from './utils'; import { LICENSING_CASE_ASSIGNMENT_FEATURE } from '../../common/constants'; import type { LicensingService } from '../../services/licensing'; -import type { CaseSavedObject } from '../../common/types'; +import type { CaseSavedObjectTransformed } from '../../common/types/case'; /** * Throws an error if any of the requests attempt to update the owner of a case. @@ -257,7 +257,7 @@ async function updateAlerts({ } function partitionPatchRequest( - casesMap: Map, + casesMap: Map, patchReqCases: CasePatchRequest[] ): { nonExistingCases: CasePatchRequest[]; @@ -292,7 +292,7 @@ function partitionPatchRequest( interface UpdateRequestWithOriginalCase { updateReq: CasePatchRequest; - originalCase: CaseSavedObject; + originalCase: CaseSavedObjectTransformed; } /** @@ -303,7 +303,7 @@ interface UpdateRequestWithOriginalCase { export const update = async ( cases: CasesPatchRequest, clientArgs: CasesClientArgs -): Promise => { +): Promise => { const { services: { caseService, @@ -335,7 +335,7 @@ export const update = async ( const casesMap = myCases.saved_objects.reduce((acc, so) => { acc.set(so.id, so); return acc; - }, new Map()); + }, new Map()); const { nonExistingCases, conflictedCases, casesToAuthorize } = partitionPatchRequest( casesMap, @@ -442,7 +442,7 @@ export const update = async ( savedObject: mergeOriginalSOWithUpdatedSO(originalCase, updatedCase), }), ]; - }, [] as CaseResponse[]); + }, [] as Case[]); await userActionService.creator.bulkCreateUpdateCase({ originalCases: myCases.saved_objects, @@ -458,7 +458,7 @@ export const update = async ( await notificationService.bulkNotifyAssignees(casesAndAssigneesToNotifyForAssignment); - return CasesResponseRt.encode(returnUpdatedCase); + return CasesRt.encode(returnUpdatedCase); } catch (error) { const idVersions = cases.cases.map((caseInfo) => ({ id: caseInfo.id, @@ -521,11 +521,11 @@ const patchCases = async ({ const getCasesAndAssigneesToNotifyForAssignment = ( updatedCases: SavedObjectsBulkUpdateResponse, - casesMap: Map, + casesMap: Map, user: CasesClientArgs['user'] ) => { return updatedCases.saved_objects.reduce< - Array<{ assignees: CaseAssignees; theCase: CaseSavedObject }> + Array<{ assignees: CaseAssignees; theCase: CaseSavedObjectTransformed }> >((acc, updatedCase) => { const originalCaseSO = casesMap.get(updatedCase.id); @@ -554,9 +554,9 @@ const getCasesAndAssigneesToNotifyForAssignment = ( }; const mergeOriginalSOWithUpdatedSO = ( - originalSO: CaseSavedObject, + originalSO: CaseSavedObjectTransformed, updatedSO: SavedObjectsUpdateResponse -): CaseSavedObject => { +): CaseSavedObjectTransformed => { return { ...originalSO, ...updatedSO, diff --git a/x-pack/plugins/cases/server/client/cases/utils.ts b/x-pack/plugins/cases/server/client/cases/utils.ts index 1288c2ecc48d7..ecf5aaf441447 100644 --- a/x-pack/plugins/cases/server/client/cases/utils.ts +++ b/x-pack/plugins/cases/server/client/cases/utils.ts @@ -15,7 +15,7 @@ import { isPushedUserAction } from '../../../common/utils/user_actions'; import type { ActionConnector, CaseFullExternalService, - CaseResponse, + Case, CommentResponse, User, CaseAttributes, @@ -34,7 +34,7 @@ import { getCaseViewPath } from '../../common/utils'; import * as i18n from './translations'; interface CreateIncidentArgs { - theCase: CaseResponse; + theCase: Case; userActions: CaseUserActionsDeprecatedResponse; connector: ActionConnector; alerts: CasesClientGetAlertsResponse; @@ -106,7 +106,7 @@ interface CountAlertsInfo { } const getAlertsInfo = ( - comments: CaseResponse['comments'] + comments: Case['comments'] ): { totalAlerts: number; hasUnpushedAlertComments: boolean } => { const countingInfo = { totalComments: 0, pushed: 0, totalAlerts: 0 }; @@ -129,7 +129,7 @@ const getAlertsInfo = ( }; const addAlertMessage = (params: { - theCase: CaseResponse; + theCase: Case; externalServiceComments: ExternalServiceComment[]; spaceId: string; publicBaseUrl?: IBasePath['publicBaseUrl']; @@ -238,7 +238,7 @@ export const formatComments = ({ userProfiles, publicBaseUrl, }: { - theCase: CaseResponse; + theCase: Case; latestPushInfo: LatestPushInfo; userActions: CaseUserActionsDeprecatedResponse; spaceId: string; @@ -275,7 +275,7 @@ export const formatComments = ({ }; export const addKibanaInformationToDescription = ( - theCase: CaseResponse, + theCase: Case, spaceId: string, userProfiles?: Map, publicBaseUrl?: IBasePath['publicBaseUrl'] @@ -307,7 +307,7 @@ export const addKibanaInformationToDescription = ( }; const addKibanaInformationToComments = ( - comments: CaseResponse['comments'] = [], + comments: Case['comments'] = [], userProfiles?: Map ): ExternalServiceComment[] => comments.map((theComment) => { @@ -328,7 +328,7 @@ const addKibanaInformationToComments = ( }); export const getEntity = ( - entity: { createdBy: CaseResponse['created_by']; updatedBy: CaseResponse['updated_by'] }, + entity: { createdBy: Case['created_by']; updatedBy: Case['updated_by'] }, userProfiles?: Map ): string => { return ( diff --git a/x-pack/plugins/cases/server/client/metrics/actions/actions.test.ts b/x-pack/plugins/cases/server/client/metrics/actions/actions.test.ts index e8211662c1820..56c81a9a41d59 100644 --- a/x-pack/plugins/cases/server/client/metrics/actions/actions.test.ts +++ b/x-pack/plugins/cases/server/client/metrics/actions/actions.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { CaseResponse } from '../../../../common/api'; +import type { Case } from '../../../../common/api'; import { createCasesClientMock } from '../../mocks'; import type { CasesClientArgs } from '../../types'; import { loggingSystemMock } from '@kbn/core/server/mocks'; @@ -30,7 +30,7 @@ const constructorOptions = { caseId: 'test-id', casesClient: clientMock, clientA describe('Actions', () => { beforeAll(() => { getAuthorizationFilter.mockResolvedValue({}); - clientMock.cases.get.mockResolvedValue({ id: '' } as unknown as CaseResponse); + clientMock.cases.get.mockResolvedValue({ id: '' } as unknown as Case); }); beforeEach(() => { diff --git a/x-pack/plugins/cases/server/client/metrics/alerts/count.test.ts b/x-pack/plugins/cases/server/client/metrics/alerts/count.test.ts index 15209b1608194..9fa308f93049e 100644 --- a/x-pack/plugins/cases/server/client/metrics/alerts/count.test.ts +++ b/x-pack/plugins/cases/server/client/metrics/alerts/count.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { CaseResponse } from '../../../../common/api'; +import type { Case } from '../../../../common/api'; import { createCasesClientMock } from '../../mocks'; import type { CasesClientArgs } from '../../types'; import { loggingSystemMock } from '@kbn/core/server/mocks'; @@ -32,7 +32,7 @@ const constructorOptions = { caseId: 'test-id', casesClient: clientMock, clientA describe('AlertsCount', () => { beforeAll(() => { getAuthorizationFilter.mockResolvedValue({}); - clientMock.cases.get.mockResolvedValue({ id: 'test-id' } as unknown as CaseResponse); + clientMock.cases.get.mockResolvedValue({ id: 'test-id' } as unknown as Case); }); beforeEach(() => { diff --git a/x-pack/plugins/cases/server/client/metrics/all_cases/mttr.test.ts b/x-pack/plugins/cases/server/client/metrics/all_cases/mttr.test.ts index a13346d2ecfab..bff57ce82a176 100644 --- a/x-pack/plugins/cases/server/client/metrics/all_cases/mttr.test.ts +++ b/x-pack/plugins/cases/server/client/metrics/all_cases/mttr.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { CaseResponse } from '../../../../common/api'; +import type { Case } from '../../../../common/api'; import { createCasesClientMock } from '../../mocks'; import type { CasesClientArgs } from '../../types'; import { loggingSystemMock } from '@kbn/core/server/mocks'; @@ -32,7 +32,7 @@ const constructorOptions = { casesClient: clientMock, clientArgs }; describe('MTTR', () => { beforeAll(() => { getAuthorizationFilter.mockResolvedValue({}); - clientMock.cases.get.mockResolvedValue({ id: '' } as unknown as CaseResponse); + clientMock.cases.get.mockResolvedValue({ id: '' } as unknown as Case); }); beforeEach(() => { diff --git a/x-pack/plugins/cases/server/client/metrics/get_case_metrics.test.ts b/x-pack/plugins/cases/server/client/metrics/get_case_metrics.test.ts index 1fabee2893e06..023b951dcbf98 100644 --- a/x-pack/plugins/cases/server/client/metrics/get_case_metrics.test.ts +++ b/x-pack/plugins/cases/server/client/metrics/get_case_metrics.test.ts @@ -8,7 +8,7 @@ import { loggingSystemMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; import { getCaseMetrics } from './get_case_metrics'; -import type { CaseResponse } from '../../../common/api'; +import type { Case } from '../../../common/api'; import { CaseStatuses } from '../../../common/api'; import type { CasesClientMock } from '../mocks'; import { createCasesClientMock } from '../mocks'; @@ -21,7 +21,7 @@ import { } from '../../services/mocks'; import { mockAlertsService } from './test_utils/alerts'; import { createStatusChangeSavedObject } from './test_utils/lifespan'; -import type { CaseSavedObject } from '../../common/types'; +import type { CaseSavedObjectTransformed } from '../../common/types/case'; describe('getCaseMetrics', () => { const inProgressStatusChangeTimestamp = new Date('2021-11-23T20:00:43Z'); @@ -164,7 +164,7 @@ function createMockClient() { return { created_at: '2021-11-23T19:59:43Z', closed_at: '2021-11-23T19:59:44Z', - } as unknown as CaseResponse; + } as unknown as Case; }); client.attachments.getAllAlertsAttachToCase.mockImplementation(async () => { @@ -191,7 +191,7 @@ function createMockClientArgs() { attributes: { owner: 'security', }, - } as unknown as CaseSavedObject; + } as unknown as CaseSavedObjectTransformed; }); const alertsService = mockAlertsService(); diff --git a/x-pack/plugins/cases/server/client/typedoc_interfaces.ts b/x-pack/plugins/cases/server/client/typedoc_interfaces.ts index 7234efdf5d355..f67a1eff4631e 100644 --- a/x-pack/plugins/cases/server/client/typedoc_interfaces.ts +++ b/x-pack/plugins/cases/server/client/typedoc_interfaces.ts @@ -17,14 +17,14 @@ import type { AllCommentsResponse, CasePostRequest, CaseResolveResponse, - CaseResponse, + Case, CasesConfigurePatch, CasesConfigureRequest, CasesConfigureResponse, CasesFindRequest, CasesFindResponse, CasesPatchRequest, - CasesResponse, + Cases, CaseUserActionsResponse, CommentsResponse, CasesBulkGetResponse, @@ -38,9 +38,9 @@ import type { export interface ICasePostRequest extends CasePostRequest {} export interface ICasesFindRequest extends CasesFindRequest {} export interface ICasesPatchRequest extends CasesPatchRequest {} -export interface ICaseResponse extends CaseResponse {} +export interface ICaseResponse extends Case {} export interface ICaseResolveResponse extends CaseResolveResponse {} -export interface ICasesResponse extends CasesResponse {} +export interface ICasesResponse extends Cases {} export interface ICasesFindResponse extends CasesFindResponse {} export interface ICasesBulkGetResponse extends CasesBulkGetResponse {} diff --git a/x-pack/plugins/cases/server/client/utils.test.ts b/x-pack/plugins/cases/server/client/utils.test.ts index fb3e89b598b03..2b63f9c732105 100644 --- a/x-pack/plugins/cases/server/client/utils.test.ts +++ b/x-pack/plugins/cases/server/client/utils.test.ts @@ -12,7 +12,6 @@ import { toElasticsearchQuery } from '@kbn/es-query'; import { CaseStatuses } from '../../common'; import { CaseSeverity } from '../../common/api'; -import { ESCaseSeverity, ESCaseStatus } from '../services/cases/types'; import { createSavedObjectsSerializerMock } from './mocks'; import { arraysDifference, @@ -22,6 +21,7 @@ import { constructSearch, convertSortField, } from './utils'; +import { CasePersistedSeverity, CasePersistedStatus } from '../common/types/case'; describe('utils', () => { describe('convertSortField', () => { @@ -401,9 +401,9 @@ describe('utils', () => { }); it.each([ - [CaseStatuses.open, ESCaseStatus.OPEN], - [CaseStatuses['in-progress'], ESCaseStatus.IN_PROGRESS], - [CaseStatuses.closed, ESCaseStatus.CLOSED], + [CaseStatuses.open, CasePersistedStatus.OPEN], + [CaseStatuses['in-progress'], CasePersistedStatus.IN_PROGRESS], + [CaseStatuses.closed, CasePersistedStatus.CLOSED], ])('creates a filter for status "%s"', (status, expectedStatus) => { expect(constructQueryOptions({ status }).filter).toMatchInlineSnapshot(` Object { @@ -426,10 +426,10 @@ describe('utils', () => { }); it.each([ - [CaseSeverity.LOW, ESCaseSeverity.LOW], - [CaseSeverity.MEDIUM, ESCaseSeverity.MEDIUM], - [CaseSeverity.HIGH, ESCaseSeverity.HIGH], - [CaseSeverity.CRITICAL, ESCaseSeverity.CRITICAL], + [CaseSeverity.LOW, CasePersistedSeverity.LOW], + [CaseSeverity.MEDIUM, CasePersistedSeverity.MEDIUM], + [CaseSeverity.HIGH, CasePersistedSeverity.HIGH], + [CaseSeverity.CRITICAL, CasePersistedSeverity.CRITICAL], ])('creates a filter for severity "%s"', (severity, expectedSeverity) => { expect(constructQueryOptions({ severity }).filter).toMatchInlineSnapshot(` Object { diff --git a/x-pack/plugins/cases/server/common/constants.ts b/x-pack/plugins/cases/server/common/constants.ts index 822907b83be39..69c1f3e619c97 100644 --- a/x-pack/plugins/cases/server/common/constants.ts +++ b/x-pack/plugins/cases/server/common/constants.ts @@ -7,7 +7,7 @@ import { CaseSeverity, CaseStatuses } from '../../common/api'; import { CASE_COMMENT_SAVED_OBJECT, CASE_SAVED_OBJECT } from '../../common/constants'; -import { ESCaseSeverity, ESCaseStatus } from '../services/cases/types'; +import { CasePersistedSeverity, CasePersistedStatus } from './types/case'; /** * The name of the saved object reference indicating the action connector ID. This is stored in the Saved Object reference @@ -40,28 +40,28 @@ export const EXTERNAL_REFERENCE_REF_NAME = 'externalReferenceId'; */ export const LICENSING_CASE_ASSIGNMENT_FEATURE = 'Cases user assignment'; -export const SEVERITY_EXTERNAL_TO_ESMODEL: Record = { - [CaseSeverity.LOW]: ESCaseSeverity.LOW, - [CaseSeverity.MEDIUM]: ESCaseSeverity.MEDIUM, - [CaseSeverity.HIGH]: ESCaseSeverity.HIGH, - [CaseSeverity.CRITICAL]: ESCaseSeverity.CRITICAL, +export const SEVERITY_EXTERNAL_TO_ESMODEL: Record = { + [CaseSeverity.LOW]: CasePersistedSeverity.LOW, + [CaseSeverity.MEDIUM]: CasePersistedSeverity.MEDIUM, + [CaseSeverity.HIGH]: CasePersistedSeverity.HIGH, + [CaseSeverity.CRITICAL]: CasePersistedSeverity.CRITICAL, }; -export const SEVERITY_ESMODEL_TO_EXTERNAL: Record = { - [ESCaseSeverity.LOW]: CaseSeverity.LOW, - [ESCaseSeverity.MEDIUM]: CaseSeverity.MEDIUM, - [ESCaseSeverity.HIGH]: CaseSeverity.HIGH, - [ESCaseSeverity.CRITICAL]: CaseSeverity.CRITICAL, +export const SEVERITY_ESMODEL_TO_EXTERNAL: Record = { + [CasePersistedSeverity.LOW]: CaseSeverity.LOW, + [CasePersistedSeverity.MEDIUM]: CaseSeverity.MEDIUM, + [CasePersistedSeverity.HIGH]: CaseSeverity.HIGH, + [CasePersistedSeverity.CRITICAL]: CaseSeverity.CRITICAL, }; -export const STATUS_EXTERNAL_TO_ESMODEL: Record = { - [CaseStatuses.open]: ESCaseStatus.OPEN, - [CaseStatuses['in-progress']]: ESCaseStatus.IN_PROGRESS, - [CaseStatuses.closed]: ESCaseStatus.CLOSED, +export const STATUS_EXTERNAL_TO_ESMODEL: Record = { + [CaseStatuses.open]: CasePersistedStatus.OPEN, + [CaseStatuses['in-progress']]: CasePersistedStatus.IN_PROGRESS, + [CaseStatuses.closed]: CasePersistedStatus.CLOSED, }; -export const STATUS_ESMODEL_TO_EXTERNAL: Record = { - [ESCaseStatus.OPEN]: CaseStatuses.open, - [ESCaseStatus.IN_PROGRESS]: CaseStatuses['in-progress'], - [ESCaseStatus.CLOSED]: CaseStatuses.closed, +export const STATUS_ESMODEL_TO_EXTERNAL: Record = { + [CasePersistedStatus.OPEN]: CaseStatuses.open, + [CasePersistedStatus.IN_PROGRESS]: CaseStatuses['in-progress'], + [CasePersistedStatus.CLOSED]: CaseStatuses.closed, }; diff --git a/x-pack/plugins/cases/server/common/models/case_with_comments.ts b/x-pack/plugins/cases/server/common/models/case_with_comments.ts index 2febbd22da77f..93d4c04261f52 100644 --- a/x-pack/plugins/cases/server/common/models/case_with_comments.ts +++ b/x-pack/plugins/cases/server/common/models/case_with_comments.ts @@ -13,26 +13,21 @@ import type { SavedObjectsUpdateResponse, } from '@kbn/core/server'; import type { - CaseResponse, + Case, CommentAttributes, CommentPatchRequest, CommentRequest, CommentRequestUserType, CommentRequestAlertType, } from '../../../common/api'; -import { - CaseResponseRt, - CaseStatuses, - CommentType, - ActionTypes, - Actions, -} from '../../../common/api'; +import { CaseRt, CaseStatuses, CommentType, ActionTypes, Actions } from '../../../common/api'; import { CASE_SAVED_OBJECT, MAX_DOCS_PER_PAGE } from '../../../common/constants'; import type { CasesClientArgs } from '../../client'; import type { RefreshSetting } from '../../services/types'; import { createCaseError } from '../error'; import { AttachmentLimitChecker } from '../limiter_checker'; -import type { AlertInfo, CaseSavedObject } from '../types'; +import type { AlertInfo } from '../types'; +import type { CaseSavedObjectTransformed } from '../types/case'; import { countAlertsForID, flattenCommentSavedObjects, @@ -51,9 +46,9 @@ type CommentRequestWithId = Array<{ id: string } & CommentRequest>; */ export class CaseCommentModel { private readonly params: CaseCommentModelParams; - private readonly caseInfo: CaseSavedObject; + private readonly caseInfo: CaseSavedObjectTransformed; - private constructor(caseInfo: CaseSavedObject, params: CaseCommentModelParams) { + private constructor(caseInfo: CaseSavedObjectTransformed, params: CaseCommentModelParams) { this.caseInfo = caseInfo; this.params = params; } @@ -69,7 +64,7 @@ export class CaseCommentModel { return new CaseCommentModel(savedObject, options); } - public get savedObject(): CaseSavedObject { + public get savedObject(): CaseSavedObjectTransformed { return this.caseInfo; } @@ -179,7 +174,7 @@ export class CaseCommentModel { } } - private newObjectWithInfo(caseInfo: CaseSavedObject): CaseCommentModel { + private newObjectWithInfo(caseInfo: CaseSavedObjectTransformed): CaseCommentModel { return new CaseCommentModel(caseInfo, this.params); } @@ -434,7 +429,7 @@ export class CaseCommentModel { }; } - public async encodeWithComments(): Promise { + public async encodeWithComments(): Promise { try { const comments = await this.params.services.caseService.getAllCaseComments({ id: this.caseInfo.id, @@ -453,7 +448,7 @@ export class CaseCommentModel { ...this.formatForEncoding(comments.total), }; - return CaseResponseRt.encode(caseResponse); + return CaseRt.encode(caseResponse); } catch (error) { throw createCaseError({ message: `Failed encoding the commentable case, case id: ${this.caseInfo.id}: ${error}`, diff --git a/x-pack/plugins/cases/server/common/types.ts b/x-pack/plugins/cases/server/common/types.ts index 0f4d64f60dfa6..a622126f0b305 100644 --- a/x-pack/plugins/cases/server/common/types.ts +++ b/x-pack/plugins/cases/server/common/types.ts @@ -5,14 +5,13 @@ * 2.0. */ +import type { SavedObjectsFindOptions } from '@kbn/core-saved-objects-api-server'; import type { SavedObject } from '@kbn/core-saved-objects-server'; import type { KueryNode } from '@kbn/es-query'; import type { - CaseAttributes, CommentAttributes, CommentRequestExternalReferenceSOType, FileAttachmentMetadata, - SavedObjectFindOptions, } from '../../common/api'; /** @@ -23,12 +22,25 @@ export interface AlertInfo { index: string; } -export type SavedObjectFindOptionsKueryNode = Omit & { +type FindOptions = Pick< + SavedObjectsFindOptions, + | 'defaultSearchOperator' + | 'hasReferenceOperator' + | 'perPage' + | 'hasReference' + | 'fields' + | 'page' + | 'search' + | 'searchFields' + | 'sortField' + | 'sortOrder' + | 'rootSearchFields' +>; + +export type SavedObjectFindOptionsKueryNode = FindOptions & { filter?: KueryNode; }; -export type CaseSavedObject = SavedObject; - export type FileAttachmentRequest = Omit< CommentRequestExternalReferenceSOType, 'externalReferenceMetadata' diff --git a/x-pack/plugins/cases/server/common/types/attachments.ts b/x-pack/plugins/cases/server/common/types/attachments.ts new file mode 100644 index 0000000000000..55b9990c5fb12 --- /dev/null +++ b/x-pack/plugins/cases/server/common/types/attachments.ts @@ -0,0 +1,48 @@ +/* + * 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 { JsonValue } from '@kbn/utility-types'; +import type { User } from './user'; + +interface AttachmentCommonPersistedAttributes { + created_at: string; + created_by: User; + owner: string; + pushed_at: string | null; + pushed_by: User | null; + updated_at: string | null; + updated_by: User | null; +} + +export interface AttachmentRequestAttributes { + type: string; + alertId?: string | string[]; + index?: string | string[]; + rule?: { + id: string | null; + name: string | null; + }; + comment?: string; + actions?: { + targets: Array<{ + hostname: string; + endpointId: string; + }>; + type: string; + }; + externalReferenceMetadata?: Record | null; + externalReferenceAttachmentTypeId?: string; + externalReferenceStorage?: { + type: string; + soType?: string; + }; + persistableStateAttachmentState?: Record; + persistableStateAttachmentTypeId?: string; +} + +export type AttachmentPersistedAttributes = AttachmentRequestAttributes & + AttachmentCommonPersistedAttributes; diff --git a/x-pack/plugins/cases/server/common/types/case.ts b/x-pack/plugins/cases/server/common/types/case.ts new file mode 100644 index 0000000000000..8e425853964c0 --- /dev/null +++ b/x-pack/plugins/cases/server/common/types/case.ts @@ -0,0 +1,52 @@ +/* + * 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 { SavedObject } from '@kbn/core-saved-objects-server'; +import type { CaseAttributes } from '../../../common/api'; +import type { ConnectorPersisted } from './connectors'; +import type { ExternalServicePersisted } from './external_service'; +import type { User, UserProfile } from './user'; + +export enum CasePersistedSeverity { + LOW = 0, + MEDIUM = 10, + HIGH = 20, + CRITICAL = 30, +} + +export enum CasePersistedStatus { + OPEN = 0, + IN_PROGRESS = 10, + CLOSED = 20, +} + +export interface CasePersistedAttributes { + assignees: UserProfile[]; + closed_at: string | null; + closed_by: User | null; + created_at: string; + created_by: User; + connector: ConnectorPersisted; + description: string; + duration: number | null; + external_service: ExternalServicePersisted | null; + owner: string; + settings: { syncAlerts: boolean }; + severity: CasePersistedSeverity; + status: CasePersistedStatus; + tags: string[]; + title: string; + total_alerts: number; + total_comments: number; + updated_at: string | null; + updated_by: User | null; +} + +export type CaseTransformedAttributes = CaseAttributes; + +export type CaseSavedObject = SavedObject; +export type CaseSavedObjectTransformed = SavedObject; diff --git a/x-pack/plugins/cases/server/common/types/configure.ts b/x-pack/plugins/cases/server/common/types/configure.ts new file mode 100644 index 0000000000000..0018d50b702b5 --- /dev/null +++ b/x-pack/plugins/cases/server/common/types/configure.ts @@ -0,0 +1,19 @@ +/* + * 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 { ConnectorPersisted } from './connectors'; +import type { User } from './user'; + +export interface ConfigurePersistedAttributes { + connector: ConnectorPersisted; + closure_type: string; + owner: string; + created_at: string; + created_by: User; + updated_at: string | null; + updated_by: User | null; +} diff --git a/x-pack/plugins/cases/server/common/types/connector_mappings.ts b/x-pack/plugins/cases/server/common/types/connector_mappings.ts new file mode 100644 index 0000000000000..d4f20075745f2 --- /dev/null +++ b/x-pack/plugins/cases/server/common/types/connector_mappings.ts @@ -0,0 +1,15 @@ +/* + * 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. + */ + +export interface ConnectorMappingsPersistedAttributes { + mappings: Array<{ + action_type: string; + source: string; + target: string; + }>; + owner: string; +} diff --git a/x-pack/plugins/cases/server/common/types/connectors.ts b/x-pack/plugins/cases/server/common/types/connectors.ts new file mode 100644 index 0000000000000..995130260f8cd --- /dev/null +++ b/x-pack/plugins/cases/server/common/types/connectors.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export type ConnectorPersistedFields = Array<{ + key: string; + value: unknown; +}>; + +export interface ConnectorPersisted { + name: string; + type: string; + fields: ConnectorPersistedFields | null; +} diff --git a/x-pack/plugins/cases/server/common/types/external_service.ts b/x-pack/plugins/cases/server/common/types/external_service.ts new file mode 100644 index 0000000000000..187e088114eed --- /dev/null +++ b/x-pack/plugins/cases/server/common/types/external_service.ts @@ -0,0 +1,17 @@ +/* + * 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'; + +export interface ExternalServicePersisted { + connector_name: string; + external_id: string; + external_title: string; + external_url: string; + pushed_at: string; + pushed_by: User; +} diff --git a/x-pack/plugins/cases/server/common/types/user.ts b/x-pack/plugins/cases/server/common/types/user.ts new file mode 100644 index 0000000000000..fa32986ef8d97 --- /dev/null +++ b/x-pack/plugins/cases/server/common/types/user.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export interface User { + email: string | null | undefined; + full_name: string | null | undefined; + username: string | null | undefined; + profile_uid?: string; +} + +export interface UserProfile { + uid: string; +} 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 0000000000000..bc5366a2adaa8 --- /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/common/utils.test.ts b/x-pack/plugins/cases/server/common/utils.test.ts index 684fe426d7dc5..c2ef8281a5887 100644 --- a/x-pack/plugins/cases/server/common/utils.test.ts +++ b/x-pack/plugins/cases/server/common/utils.test.ts @@ -10,7 +10,7 @@ import { makeLensEmbeddableFactory } from '@kbn/lens-plugin/server/embeddable/ma import { OWNER_INFO, SECURITY_SOLUTION_OWNER } from '../../common/constants'; import type { CaseConnector, - CaseResponse, + Case, CommentAttributes, CommentRequest, CommentRequestUserType, @@ -256,7 +256,7 @@ describe('common utils', () => { describe('transformCases', () => { it('transforms correctly', () => { - const casesMap = new Map( + const casesMap = new Map( mockCases.map((obj) => { return [obj.id, flattenCaseSavedObject({ savedObject: obj, totalComment: 2 })]; }) diff --git a/x-pack/plugins/cases/server/common/utils.ts b/x-pack/plugins/cases/server/common/utils.ts index 8949e01aceca7..b04c9fd596503 100644 --- a/x-pack/plugins/cases/server/common/utils.ts +++ b/x-pack/plugins/cases/server/common/utils.ts @@ -24,18 +24,16 @@ import { OWNER_INFO, } from '../../common/constants'; import type { CASE_VIEW_PAGE_TABS } from '../../common/types'; -import type { AlertInfo, CaseSavedObject, FileAttachmentRequest } from './types'; +import type { AlertInfo, FileAttachmentRequest } from './types'; import type { - CaseAttributes, CasePostRequest, - CaseResponse, + Case, CasesFindResponse, CommentAttributes, CommentRequest, CommentRequestActionsType, CommentRequestAlertType, - CommentRequestExternalReferenceSOType, CommentRequestUserType, CommentResponse, CommentsResponse, @@ -46,7 +44,6 @@ import { CaseStatuses, CommentType, ConnectorTypes, - ExternalReferenceStorageType, ExternalReferenceSORt, FileAttachmentMetadataRt, } from '../../common/api'; @@ -56,6 +53,7 @@ import { getLensVisualizations, } from '../../common/utils/markdown_plugins/utils'; import { dedupAssignees } from '../client/cases/utils'; +import type { CaseSavedObjectTransformed, CaseTransformedAttributes } from './types/case'; /** * Default sort field for querying saved objects. @@ -73,7 +71,7 @@ export const transformNewCase = ({ }: { user: User; newCase: CasePostRequest; -}): CaseAttributes => ({ +}): CaseTransformedAttributes => ({ ...newCase, duration: null, severity: newCase.severity ?? CaseSeverity.LOW, @@ -97,7 +95,7 @@ export const transformCases = ({ perPage, total, }: { - casesMap: Map; + casesMap: Map; countOpenCases: number; countInProgressCases: number; countClosedCases: number; @@ -120,11 +118,11 @@ export const flattenCaseSavedObject = ({ totalComment = comments.length, totalAlerts = 0, }: { - savedObject: CaseSavedObject; + savedObject: CaseSavedObjectTransformed; comments?: Array>; totalComment?: number; totalAlerts?: number; -}): CaseResponse => ({ +}): Case => ({ id: savedObject.id, version: savedObject.version ?? '0', comments: flattenCommentSavedObjects(comments), @@ -254,18 +252,6 @@ export const isCommentRequestTypeAlert = ( return context.type === CommentType.alert; }; -/** - * A type narrowing function for external reference so attachments. - */ -export const isCommentRequestTypeExternalReferenceSO = ( - context: Partial -): context is CommentRequestExternalReferenceSOType => { - return ( - context.type === CommentType.externalReference && - context.externalReferenceStorage?.type === ExternalReferenceStorageType.savedObject - ); -}; - /** * A type narrowing function for file attachments. */ diff --git a/x-pack/plugins/cases/server/connectors/jira/format.test.ts b/x-pack/plugins/cases/server/connectors/jira/format.test.ts index 7ddabdf5e2ff1..acca9c7886ec2 100644 --- a/x-pack/plugins/cases/server/connectors/jira/format.test.ts +++ b/x-pack/plugins/cases/server/connectors/jira/format.test.ts @@ -5,14 +5,14 @@ * 2.0. */ -import type { CaseResponse } from '../../../common/api'; +import type { Case } from '../../../common/api'; import { format } from './format'; describe('Jira formatter', () => { const theCase = { tags: ['tag'], connector: { fields: { priority: 'High', issueType: 'Task', parent: null } }, - } as CaseResponse; + } as Case; it('it formats correctly', async () => { const res = await format(theCase, []); @@ -20,7 +20,7 @@ describe('Jira formatter', () => { }); it('it formats correctly when fields do not exist ', async () => { - const invalidFields = { tags: ['tag'], connector: { fields: null } } as CaseResponse; + const invalidFields = { tags: ['tag'], connector: { fields: null } } as Case; const res = await format(invalidFields, []); expect(res).toEqual({ priority: null, issueType: null, parent: null, labels: theCase.tags }); }); diff --git a/x-pack/plugins/cases/server/connectors/resilient/format.test.ts b/x-pack/plugins/cases/server/connectors/resilient/format.test.ts index cd850bd28fe37..29ab88e09c388 100644 --- a/x-pack/plugins/cases/server/connectors/resilient/format.test.ts +++ b/x-pack/plugins/cases/server/connectors/resilient/format.test.ts @@ -5,13 +5,13 @@ * 2.0. */ -import type { CaseResponse } from '../../../common/api'; +import type { Case } from '../../../common/api'; import { format } from './format'; describe('IBM Resilient formatter', () => { const theCase = { connector: { fields: { incidentTypes: ['2'], severityCode: '2' } }, - } as CaseResponse; + } as Case; it('it formats correctly', async () => { const res = await format(theCase, []); @@ -19,7 +19,7 @@ describe('IBM Resilient formatter', () => { }); it('it formats correctly when fields do not exist ', async () => { - const invalidFields = { tags: ['a tag'], connector: { fields: null } } as CaseResponse; + const invalidFields = { tags: ['a tag'], connector: { fields: null } } as Case; const res = await format(invalidFields, []); expect(res).toEqual({ incidentTypes: null, severityCode: null }); }); diff --git a/x-pack/plugins/cases/server/connectors/servicenow/itsm_format.test.ts b/x-pack/plugins/cases/server/connectors/servicenow/itsm_format.test.ts index 8db9ba7df4859..0edec51ce4f48 100644 --- a/x-pack/plugins/cases/server/connectors/servicenow/itsm_format.test.ts +++ b/x-pack/plugins/cases/server/connectors/servicenow/itsm_format.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { CaseResponse } from '../../../common/api'; +import type { Case } from '../../../common/api'; import { format } from './itsm_format'; describe('ITSM formatter', () => { @@ -14,7 +14,7 @@ describe('ITSM formatter', () => { connector: { fields: { severity: '2', urgency: '2', impact: '2', category: 'software', subcategory: 'os' }, }, - } as CaseResponse; + } as Case; it('it formats correctly', async () => { const res = await format(theCase, []); @@ -26,7 +26,7 @@ describe('ITSM formatter', () => { }); it('it formats correctly when fields do not exist ', async () => { - const invalidFields = { connector: { fields: null } } as CaseResponse; + const invalidFields = { connector: { fields: null } } as Case; const res = await format(invalidFields, []); expect(res).toEqual({ severity: null, diff --git a/x-pack/plugins/cases/server/connectors/servicenow/sir_format.test.ts b/x-pack/plugins/cases/server/connectors/servicenow/sir_format.test.ts index 6697aad205b92..23d14ec6b2d75 100644 --- a/x-pack/plugins/cases/server/connectors/servicenow/sir_format.test.ts +++ b/x-pack/plugins/cases/server/connectors/servicenow/sir_format.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { CaseResponse } from '../../../common/api'; +import type { Case } from '../../../common/api'; import { format } from './sir_format'; describe('SIR formatter', () => { @@ -22,7 +22,7 @@ describe('SIR formatter', () => { priority: '2 - High', }, }, - } as CaseResponse; + } as Case; it('it formats correctly without alerts', async () => { const res = await format(theCase, []); @@ -40,7 +40,7 @@ describe('SIR formatter', () => { }); it('it formats correctly when fields do not exist ', async () => { - const invalidFields = { connector: { fields: null } } as CaseResponse; + const invalidFields = { connector: { fields: null } } as Case; const res = await format(invalidFields, []); expect(res).toEqual({ dest_ip: [], @@ -159,7 +159,7 @@ describe('SIR formatter', () => { const newCase = { ...theCase, connector: { fields: { ...theCase.connector.fields, destIp: false, malwareHash: false } }, - } as CaseResponse; + } as Case; const res = await format(newCase, alerts); expect(res).toEqual({ diff --git a/x-pack/plugins/cases/server/connectors/swimlane/format.test.ts b/x-pack/plugins/cases/server/connectors/swimlane/format.test.ts index d3500c5f9e18e..116b0eef1027c 100644 --- a/x-pack/plugins/cases/server/connectors/swimlane/format.test.ts +++ b/x-pack/plugins/cases/server/connectors/swimlane/format.test.ts @@ -5,14 +5,14 @@ * 2.0. */ -import type { CaseResponse } from '../../../common/api'; +import type { Case } from '../../../common/api'; import { format } from './format'; describe('Swimlane formatter', () => { const theCase = { id: 'case-id', connector: { fields: null }, - } as CaseResponse; + } as Case; it('it formats correctly', async () => { const res = await format(theCase, []); diff --git a/x-pack/plugins/cases/server/connectors/types.ts b/x-pack/plugins/cases/server/connectors/types.ts index b4cb6af0ddde9..c1f1480d359b1 100644 --- a/x-pack/plugins/cases/server/connectors/types.ts +++ b/x-pack/plugins/cases/server/connectors/types.ts @@ -6,7 +6,7 @@ */ import type { Logger } from '@kbn/core/server'; -import type { CaseResponse, ConnectorMappingsAttributes } from '../../common/api'; +import type { Case, ConnectorMappingsAttributes } from '../../common/api'; import type { CasesClientGetAlertsResponse } from '../client/alerts/types'; import type { CasesClientFactory } from '../client/factory'; import type { RegisterActionType } from '../types'; @@ -21,7 +21,7 @@ export interface RegisterConnectorsArgs extends GetActionTypeParams { } export interface ICasesConnector { - format: (theCase: CaseResponse, alerts: CasesClientGetAlertsResponse) => TExternalServiceParams; + format: (theCase: Case, alerts: CasesClientGetAlertsResponse) => TExternalServiceParams; getMapping: () => ConnectorMappingsAttributes[]; } diff --git a/x-pack/plugins/cases/server/mocks.ts b/x-pack/plugins/cases/server/mocks.ts index 823acef076fe3..8cef503691bcb 100644 --- a/x-pack/plugins/cases/server/mocks.ts +++ b/x-pack/plugins/cases/server/mocks.ts @@ -6,14 +6,14 @@ */ import type { SavedObject } from '@kbn/core/server'; -import type { CaseSavedObject } from './common/types'; import type { CasePostRequest, CommentAttributes } from '../common/api'; import { CaseSeverity, CaseStatuses, CommentType, ConnectorTypes } from '../common/api'; import { SECURITY_SOLUTION_OWNER } from '../common/constants'; import type { CasesStart } from './types'; import { createCasesClientMock } from './client/mocks'; +import type { CaseSavedObjectTransformed } from './common/types/case'; -export const mockCases: CaseSavedObject[] = [ +export const mockCases: CaseSavedObjectTransformed[] = [ { type: 'cases', id: 'mock-id-1', diff --git a/x-pack/plugins/cases/server/saved_object_types/cases.ts b/x-pack/plugins/cases/server/saved_object_types/cases.ts index 2a9492b6c755f..a4f0cdc7b02de 100644 --- a/x-pack/plugins/cases/server/saved_object_types/cases.ts +++ b/x-pack/plugins/cases/server/saved_object_types/cases.ts @@ -14,7 +14,7 @@ import type { SavedObjectsType, } from '@kbn/core/server'; import { CASE_SAVED_OBJECT } from '../../common/constants'; -import type { ESCaseAttributes } from '../services/cases/types'; +import type { CasePersistedAttributes } from '../common/types/case'; import { handleExport } from './import_export/export'; import { caseMigrations } from './migrations'; @@ -195,10 +195,10 @@ export const createCaseSavedObjectType = ( importableAndExportable: true, defaultSearchField: 'title', icon: 'casesApp', - getTitle: (savedObject: SavedObject) => savedObject.attributes.title, + getTitle: (savedObject: SavedObject) => savedObject.attributes.title, onExport: async ( context: SavedObjectsExportTransformContext, - objects: Array> + objects: Array> ) => handleExport({ context, objects, coreSetup, logger }), }, }); diff --git a/x-pack/plugins/cases/server/saved_object_types/import_export/export.ts b/x-pack/plugins/cases/server/saved_object_types/import_export/export.ts index 0fe7b51385981..703036c216058 100644 --- a/x-pack/plugins/cases/server/saved_object_types/import_export/export.ts +++ b/x-pack/plugins/cases/server/saved_object_types/import_export/export.ts @@ -25,7 +25,7 @@ import { } from '../../../common/constants'; import { defaultSortField } from '../../common/utils'; import { createCaseError } from '../../common/error'; -import type { ESCaseAttributes } from '../../services/cases/types'; +import type { CasePersistedAttributes } from '../../common/types/case'; export async function handleExport({ context, @@ -34,13 +34,15 @@ export async function handleExport({ logger, }: { context: SavedObjectsExportTransformContext; - objects: Array>; + objects: Array>; coreSetup: CoreSetup; logger: Logger; }): Promise< Array< SavedObject< - ESCaseAttributes | CommentAttributesWithoutRefs | CaseUserActionAttributesWithoutConnectorId + | CasePersistedAttributes + | CommentAttributesWithoutRefs + | CaseUserActionAttributesWithoutConnectorId > > > { diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/cases.test.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/cases.test.ts index 5b2eb65080682..bb6c5f1130bda 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/cases.test.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/cases.test.ts @@ -9,8 +9,8 @@ import type { SavedObjectSanitizedDoc, SavedObjectUnsanitizedDoc } from '@kbn/co import type { CaseAttributes, CaseFullExternalService } from '../../../common/api'; import { CaseSeverity, CaseStatuses, ConnectorTypes, NONE_CONNECTOR_ID } from '../../../common/api'; import { CASE_SAVED_OBJECT } from '../../../common/constants'; +import { CasePersistedSeverity, CasePersistedStatus } from '../../common/types/case'; import { getNoneCaseConnector } from '../../common/utils'; -import { ESCaseSeverity, ESCaseStatus } from '../../services/cases/types'; import type { ESCaseConnectorWithId } from '../../services/test_utils'; import { createExternalService } from '../../services/test_utils'; import { @@ -585,10 +585,10 @@ describe('case migrations', () => { describe('update severity', () => { it.each([ - [CaseSeverity.LOW, ESCaseSeverity.LOW], - [CaseSeverity.MEDIUM, ESCaseSeverity.MEDIUM], - [CaseSeverity.HIGH, ESCaseSeverity.HIGH], - [CaseSeverity.CRITICAL, ESCaseSeverity.CRITICAL], + [CaseSeverity.LOW, CasePersistedSeverity.LOW], + [CaseSeverity.MEDIUM, CasePersistedSeverity.MEDIUM], + [CaseSeverity.HIGH, CasePersistedSeverity.HIGH], + [CaseSeverity.CRITICAL, CasePersistedSeverity.CRITICAL], ])( 'migrates "%s" severity keyword value to matching short', (oldSeverityValue, expectedSeverityValue) => { @@ -624,7 +624,7 @@ describe('case migrations', () => { ...doc, attributes: { ...doc.attributes, - severity: ESCaseSeverity.LOW, + severity: CasePersistedSeverity.LOW, }, references: [], }); @@ -633,9 +633,9 @@ describe('case migrations', () => { describe('update status', () => { it.each([ - [CaseStatuses.open, ESCaseStatus.OPEN], - [CaseStatuses['in-progress'], ESCaseStatus.IN_PROGRESS], - [CaseStatuses.closed, ESCaseStatus.CLOSED], + [CaseStatuses.open, CasePersistedStatus.OPEN], + [CaseStatuses['in-progress'], CasePersistedStatus.IN_PROGRESS], + [CaseStatuses.closed, CasePersistedStatus.CLOSED], ])( 'migrates "%s" status keyword value to matching short', (oldStatusValue, expectedStatusValue) => { @@ -671,7 +671,7 @@ describe('case migrations', () => { ...doc, attributes: { ...doc.attributes, - status: ESCaseStatus.OPEN, + status: CasePersistedStatus.OPEN, }, references: [], }); diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/cases.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/cases.ts index 38f91952f1469..6b78ab04d90ed 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/cases.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/cases.ts @@ -11,7 +11,6 @@ import { cloneDeep, unset, flow } from 'lodash'; import type { SavedObjectUnsanitizedDoc, SavedObjectSanitizedDoc } from '@kbn/core/server'; import type { SanitizedCaseOwner } from '.'; import { addOwnerToSO } from '.'; -import type { ESConnectorFields } from '../../services'; import type { CaseAttributes } from '../../../common/api'; import { CaseSeverity, ConnectorTypes } from '../../../common/api'; @@ -27,7 +26,8 @@ import { } from './user_actions/connector_id'; import { CASE_TYPE_INDIVIDUAL } from './constants'; import { pipeMigrations } from './utils'; -import { ESCaseSeverity, ESCaseStatus } from '../../services/cases/types'; +import type { ConnectorPersistedFields } from '../../common/types/connectors'; +import { CasePersistedSeverity, CasePersistedStatus } from '../../common/types/case'; interface UnsanitizedCaseConnector { connector_id: string; @@ -38,7 +38,7 @@ interface SanitizedCaseConnector { id: string; name: string | null; type: string | null; - fields: null | ESConnectorFields; + fields: null | ConnectorPersistedFields; }; } @@ -137,8 +137,11 @@ export const addAssignees = ( export const convertSeverity = ( doc: SavedObjectUnsanitizedDoc -): SavedObjectSanitizedDoc & { severity: ESCaseSeverity }> => { - const severity = SEVERITY_EXTERNAL_TO_ESMODEL[doc.attributes.severity] ?? ESCaseSeverity.LOW; +): SavedObjectSanitizedDoc< + Omit & { severity: CasePersistedSeverity } +> => { + const severity = + SEVERITY_EXTERNAL_TO_ESMODEL[doc.attributes.severity] ?? CasePersistedSeverity.LOW; return { ...doc, attributes: { ...doc.attributes, severity }, @@ -148,8 +151,8 @@ export const convertSeverity = ( export const convertStatus = ( doc: SavedObjectUnsanitizedDoc -): SavedObjectSanitizedDoc & { status: ESCaseStatus }> => { - const status = STATUS_EXTERNAL_TO_ESMODEL[doc.attributes?.status] ?? ESCaseStatus.OPEN; +): SavedObjectSanitizedDoc & { status: CasePersistedStatus }> => { + const status = STATUS_EXTERNAL_TO_ESMODEL[doc.attributes?.status] ?? CasePersistedStatus.OPEN; return { ...doc, attributes: { ...doc.attributes, status }, diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/comments.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/comments.ts index b3978b6e12ef6..02afa01bf49c3 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/comments.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/comments.ts @@ -17,7 +17,6 @@ import type { } from '@kbn/core/server'; import { mergeSavedObjectMigrationMaps } from '@kbn/core/server'; import type { LensServerPluginSetup } from '@kbn/lens-plugin/server'; -import type { CommentAttributes } from '../../../common/api'; import { CommentType } from '../../../common/api'; import type { LensMarkdownNode, MarkdownNode } from '../../../common/utils/markdown_plugins/utils'; import { @@ -32,6 +31,7 @@ import { GENERATED_ALERT, SUB_CASE_SAVED_OBJECT } from './constants'; import type { PersistableStateAttachmentTypeRegistry } from '../../attachment_framework/persistable_state_registry'; import { getAllPersistableAttachmentMigrations } from './get_all_persistable_attachment_migrations'; import type { PersistableStateAttachmentState } from '../../attachment_framework/types'; +import type { AttachmentPersistedAttributes } from '../../common/types/attachments'; interface UnsanitizedComment { comment: string; @@ -71,7 +71,7 @@ export const createCommentsMigrations = ( const persistableStateAttachmentMigrations = mapValues< MigrateFunctionsObject, - SavedObjectMigrationFn + SavedObjectMigrationFn >( getAllPersistableAttachmentMigrations(migrationDeps.persistableStateAttachmentTypeRegistry), migratePersistableStateAttachments @@ -134,8 +134,10 @@ export const createCommentsMigrations = ( }; export const migratePersistableStateAttachments = - (migrate: MigrateFunction): SavedObjectMigrationFn => - (doc: SavedObjectUnsanitizedDoc) => { + ( + migrate: MigrateFunction + ): SavedObjectMigrationFn => + (doc: SavedObjectUnsanitizedDoc) => { if (doc.attributes.type !== CommentType.persistableState) { return doc; } diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/configuration.test.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/configuration.test.ts index 9d46e90bca17f..b4a3c962dabad 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/configuration.test.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/configuration.test.ts @@ -13,9 +13,9 @@ import { CASE_CONFIGURE_SAVED_OBJECT, SECURITY_SOLUTION_OWNER } from '../../../c import { CONNECTOR_ID_REFERENCE_NAME } from '../../common/constants'; import { getNoneCaseConnector } from '../../common/utils'; import type { ESCaseConnectorWithId } from '../../services/test_utils'; -import type { ESCasesConfigureAttributes } from '../../services/configure/types'; import type { UnsanitizedConfigureConnector } from './configuration'; import { createConnectorAttributeMigration, configureConnectorIdMigration } from './configuration'; +import type { ConfigurePersistedAttributes } from '../../common/types/configure'; // eslint-disable-next-line @typescript-eslint/naming-convention const create_7_14_0_configSchema = (connector?: ESCaseConnectorWithId) => ({ @@ -135,7 +135,7 @@ describe('configuration migrations', () => { const migratedConnector = configureConnectorIdMigration( configureSavedObject - ) as SavedObjectSanitizedDoc; + ) as SavedObjectSanitizedDoc; expect(migratedConnector.references.length).toBe(0); expect(migratedConnector.attributes.connector).not.toHaveProperty('id'); @@ -146,7 +146,7 @@ describe('configuration migrations', () => { const migratedConnector = configureConnectorIdMigration( configureSavedObject - ) as SavedObjectSanitizedDoc; + ) as SavedObjectSanitizedDoc; expect(migratedConnector.references.length).toBe(0); expect(migratedConnector.attributes.connector).toMatchInlineSnapshot(` @@ -168,7 +168,7 @@ describe('configuration migrations', () => { const migratedConnector = configureConnectorIdMigration( configureSavedObject - ) as SavedObjectSanitizedDoc; + ) as SavedObjectSanitizedDoc; expect(migratedConnector.references).toEqual([ { id: '123', type: ACTION_SAVED_OBJECT_TYPE, name: CONNECTOR_ID_REFERENCE_NAME }, @@ -181,7 +181,7 @@ describe('configuration migrations', () => { const migratedConnector = configureConnectorIdMigration( configureSavedObject - ) as SavedObjectSanitizedDoc; + ) as SavedObjectSanitizedDoc; expect(migratedConnector).toMatchInlineSnapshot(` Object { diff --git a/x-pack/plugins/cases/server/services/attachments/index.ts b/x-pack/plugins/cases/server/services/attachments/index.ts index bde31a375ec72..e76b93ce0e5b9 100644 --- a/x-pack/plugins/cases/server/services/attachments/index.ts +++ b/x-pack/plugins/cases/server/services/attachments/index.ts @@ -7,20 +7,14 @@ import type { SavedObject, - SavedObjectReference, SavedObjectsBulkResponse, SavedObjectsBulkUpdateResponse, SavedObjectsFindResponse, - SavedObjectsUpdateOptions, SavedObjectsUpdateResponse, } from '@kbn/core/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import type { - CommentAttributes as AttachmentAttributes, - CommentAttributesWithoutRefs as AttachmentAttributesWithoutRefs, - CommentPatchAttributes as AttachmentPatchAttributes, -} from '../../../common/api'; +import type { CommentAttributes as AttachmentAttributes } from '../../../common/api'; import { CommentType } from '../../../common/api'; import { CASE_COMMENT_SAVED_OBJECT, CASE_SAVED_OBJECT } from '../../../common/constants'; import { buildFilter, combineFilters } from '../../client/utils'; @@ -32,50 +26,19 @@ import { injectAttachmentSOAttributesFromRefsForPatch, } from '../so_references'; import type { SavedObjectFindOptionsKueryNode } from '../../common/types'; -import type { IndexRefresh } from '../types'; -import type { AttachedToCaseArgs, ServiceContext } from './types'; +import type { + AlertsAttachedToCaseArgs, + AttachmentsAttachedToCaseArgs, + BulkCreateAttachments, + BulkUpdateAttachmentArgs, + CountActionsAttachedToCaseArgs, + CreateAttachmentArgs, + DeleteAttachmentArgs, + ServiceContext, + UpdateAttachmentArgs, +} from './types'; import { AttachmentGetter } from './operations/get'; - -type AlertsAttachedToCaseArgs = AttachedToCaseArgs; - -interface AttachmentsAttachedToCaseArgs extends AttachedToCaseArgs { - attachmentType: CommentType; - aggregations: Record; -} - -interface CountActionsAttachedToCaseArgs extends AttachedToCaseArgs { - aggregations: Record; -} - -interface DeleteAttachmentArgs extends IndexRefresh { - attachmentIds: string[]; -} - -interface CreateAttachmentArgs extends IndexRefresh { - attributes: AttachmentAttributes; - references: SavedObjectReference[]; - id: string; -} - -interface BulkCreateAttachments extends IndexRefresh { - attachments: Array<{ - attributes: AttachmentAttributes; - references: SavedObjectReference[]; - id: string; - }>; -} - -interface UpdateArgs { - attachmentId: string; - updatedAttributes: AttachmentPatchAttributes; - options?: Omit, 'upsert'>; -} - -export type UpdateAttachmentArgs = UpdateArgs; - -interface BulkUpdateAttachmentArgs extends IndexRefresh { - comments: UpdateArgs[]; -} +import type { AttachmentPersistedAttributes } from '../../common/types/attachments'; export class AttachmentService { private readonly _getter: AttachmentGetter; @@ -136,10 +99,7 @@ export class AttachmentService { const combinedFilter = combineFilters([attachmentFilter, filter]); - const response = await this.context.unsecuredSavedObjectsClient.find< - AttachmentAttributes, - Agg - >({ + const response = await this.context.unsecuredSavedObjectsClient.find({ type: CASE_COMMENT_SAVED_OBJECT, hasReference: { type: CASE_SAVED_OBJECT, id: caseId }, page: 1, @@ -207,7 +167,7 @@ export class AttachmentService { ); const attachment = - await this.context.unsecuredSavedObjectsClient.create( + await this.context.unsecuredSavedObjectsClient.create( CASE_COMMENT_SAVED_OBJECT, extractedAttributes, { @@ -234,7 +194,7 @@ export class AttachmentService { try { this.context.log.debug(`Attempting to bulk create attachments`); const res = - await this.context.unsecuredSavedObjectsClient.bulkCreate( + await this.context.unsecuredSavedObjectsClient.bulkCreate( attachments.map((attachment) => { const { attributes: extractedAttributes, references: extractedReferences } = extractAttachmentSORefsFromAttributes( @@ -288,7 +248,7 @@ export class AttachmentService { const shouldUpdateRefs = extractedReferences.length > 0 || didDeleteOperation; const res = - await this.context.unsecuredSavedObjectsClient.update( + await this.context.unsecuredSavedObjectsClient.update( CASE_COMMENT_SAVED_OBJECT, attachmentId, extractedAttributes, @@ -325,7 +285,7 @@ export class AttachmentService { ); const res = - await this.context.unsecuredSavedObjectsClient.bulkUpdate( + await this.context.unsecuredSavedObjectsClient.bulkUpdate( comments.map((c) => { const { attributes: extractedAttributes, @@ -380,7 +340,7 @@ export class AttachmentService { try { this.context.log.debug(`Attempting to find comments`); const res = - await this.context.unsecuredSavedObjectsClient.find({ + await this.context.unsecuredSavedObjectsClient.find({ sortField: defaultSortField, ...options, type: CASE_COMMENT_SAVED_OBJECT, diff --git a/x-pack/plugins/cases/server/services/attachments/operations/get.ts b/x-pack/plugins/cases/server/services/attachments/operations/get.ts index 3db7059b3977b..4aa5c65ebdcc1 100644 --- a/x-pack/plugins/cases/server/services/attachments/operations/get.ts +++ b/x-pack/plugins/cases/server/services/attachments/operations/get.ts @@ -8,6 +8,7 @@ import type { SavedObject } from '@kbn/core/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { FILE_SO_TYPE } from '@kbn/files-plugin/common'; +import type { AttachmentPersistedAttributes } from '../../../common/types/attachments'; import { CASE_COMMENT_SAVED_OBJECT, CASE_SAVED_OBJECT, @@ -19,13 +20,12 @@ import type { AttachmentTotals, AttributesTypeAlerts, CommentAttributes as AttachmentAttributes, - CommentAttributesWithoutRefs as AttachmentAttributesWithoutRefs, - CommentAttributes, } from '../../../../common/api'; import { CommentType } from '../../../../common/api'; import type { - AttachedToCaseArgs, + AlertIdsAggsResult, BulkOptionalAttributes, + GetAllAlertsAttachToCaseArgs, GetAttachmentArgs, ServiceContext, } from '../types'; @@ -37,29 +37,19 @@ import { partitionByCaseAssociation } from '../../../common/partitioning'; import type { AttachmentSavedObject } from '../../../common/types'; import { getCaseReferenceId } from '../../../common/references'; -type GetAllAlertsAttachToCaseArgs = AttachedToCaseArgs; - -interface AlertIdsAggsResult { - alertIds: { - buckets: Array<{ - key: string; - }>; - }; -} - export class AttachmentGetter { constructor(private readonly context: ServiceContext) {} public async bulkGet( attachmentIds: string[] - ): Promise> { + ): Promise> { try { this.context.log.debug( `Attempting to retrieve attachments with ids: ${attachmentIds.join()}` ); const response = - await this.context.unsecuredSavedObjectsClient.bulkGet( + await this.context.unsecuredSavedObjectsClient.bulkGet( attachmentIds.map((id) => ({ id, type: CASE_COMMENT_SAVED_OBJECT })) ); @@ -85,7 +75,9 @@ export class AttachmentGetter { `Attempting to retrieve attachments associated with cases: [${caseIds}]` ); - const finder = this.context.unsecuredSavedObjectsClient.createPointInTimeFinder({ + // 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_COMMENT_SAVED_OBJECT, hasReference: caseIds.map((id) => ({ id, type: CASE_SAVED_OBJECT })), sortField: 'created_at', @@ -133,18 +125,24 @@ export class AttachmentGetter { const combinedFilter = combineFilters([alertsFilter, filter]); const finder = - this.context.unsecuredSavedObjectsClient.createPointInTimeFinder({ - type: CASE_COMMENT_SAVED_OBJECT, - hasReference: { type: CASE_SAVED_OBJECT, id: caseId }, - sortField: 'created_at', - sortOrder: 'asc', - filter: combinedFilter, - perPage: MAX_DOCS_PER_PAGE, - }); + this.context.unsecuredSavedObjectsClient.createPointInTimeFinder( + { + type: CASE_COMMENT_SAVED_OBJECT, + hasReference: { type: CASE_SAVED_OBJECT, id: caseId }, + sortField: 'created_at', + sortOrder: 'asc', + filter: combinedFilter, + perPage: MAX_DOCS_PER_PAGE, + } + ); let result: Array> = []; for await (const userActionSavedObject of finder.find()) { - result = result.concat(userActionSavedObject.saved_objects); + result = result.concat( + // We need a cast here because to limited attachment type conflicts with the expected result even though they + // should be the same + userActionSavedObject.saved_objects as unknown as Array> + ); } return result; @@ -197,11 +195,10 @@ export class AttachmentGetter { }: GetAttachmentArgs): Promise> { try { this.context.log.debug(`Attempting to GET attachment ${attachmentId}`); - const res = - await this.context.unsecuredSavedObjectsClient.get( - CASE_COMMENT_SAVED_OBJECT, - attachmentId - ); + const res = await this.context.unsecuredSavedObjectsClient.get( + CASE_COMMENT_SAVED_OBJECT, + attachmentId + ); return injectAttachmentSOAttributesFromRefs( res, @@ -305,7 +302,7 @@ export class AttachmentGetter { }: { caseId: string; fileIds: string[]; - }): Promise>> { + }): Promise>> { try { this.context.log.debug('Attempting to find file attachments'); @@ -324,7 +321,7 @@ export class AttachmentGetter { * to retrieve them all. */ const finder = - this.context.unsecuredSavedObjectsClient.createPointInTimeFinder( + this.context.unsecuredSavedObjectsClient.createPointInTimeFinder( { type: CASE_COMMENT_SAVED_OBJECT, hasReference: references, @@ -334,7 +331,7 @@ export class AttachmentGetter { } ); - const foundAttachments: Array> = []; + const foundAttachments: Array> = []; for await (const attachmentSavedObjects of finder.find()) { foundAttachments.push( diff --git a/x-pack/plugins/cases/server/services/attachments/types.ts b/x-pack/plugins/cases/server/services/attachments/types.ts index 554ba8afb049b..dbf9075031d83 100644 --- a/x-pack/plugins/cases/server/services/attachments/types.ts +++ b/x-pack/plugins/cases/server/services/attachments/types.ts @@ -5,15 +5,24 @@ * 2.0. */ +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { Logger, SavedObject, + SavedObjectReference, SavedObjectsBulkResponse, SavedObjectsClientContract, + SavedObjectsUpdateOptions, } from '@kbn/core/server'; import type { KueryNode } from '@kbn/es-query'; +import type { CommentType } from '../../../common'; +import type { + CommentAttributes as AttachmentAttributes, + CommentPatchAttributes as AttachmentPatchAttributes, +} from '../../../common/api'; import type { PersistableStateAttachmentTypeRegistry } from '../../attachment_framework/persistable_state_registry'; import type { PartialField } from '../../types'; +import type { IndexRefresh } from '../types'; export interface ServiceContext { log: Logger; @@ -36,3 +45,54 @@ export interface BulkOptionalAttributes extends Omit, 'saved_objects'> { saved_objects: Array>; } + +export type GetAllAlertsAttachToCaseArgs = AttachedToCaseArgs; + +export interface AlertIdsAggsResult { + alertIds: { + buckets: Array<{ + key: string; + }>; + }; +} + +export type AlertsAttachedToCaseArgs = AttachedToCaseArgs; + +export interface AttachmentsAttachedToCaseArgs extends AttachedToCaseArgs { + attachmentType: CommentType; + aggregations: Record; +} + +export interface CountActionsAttachedToCaseArgs extends AttachedToCaseArgs { + aggregations: Record; +} + +export interface DeleteAttachmentArgs extends IndexRefresh { + attachmentIds: string[]; +} + +export interface CreateAttachmentArgs extends IndexRefresh { + attributes: AttachmentAttributes; + references: SavedObjectReference[]; + id: string; +} + +export interface BulkCreateAttachments extends IndexRefresh { + attachments: Array<{ + attributes: AttachmentAttributes; + references: SavedObjectReference[]; + id: string; + }>; +} + +export interface UpdateArgs { + attachmentId: string; + updatedAttributes: AttachmentPatchAttributes; + options?: Omit, 'upsert'>; +} + +export type UpdateAttachmentArgs = UpdateArgs; + +export interface BulkUpdateAttachmentArgs extends IndexRefresh { + comments: UpdateArgs[]; +} diff --git a/x-pack/plugins/cases/server/services/cases/index.test.ts b/x-pack/plugins/cases/server/services/cases/index.test.ts index c84d4df964157..c0039529ffc91 100644 --- a/x-pack/plugins/cases/server/services/cases/index.test.ts +++ b/x-pack/plugins/cases/server/services/cases/index.test.ts @@ -41,11 +41,10 @@ import { basicCaseFields, createSOFindResponse, } from '../test_utils'; -import type { ESCaseAttributes } from './types'; -import { ESCaseSeverity, ESCaseStatus } from './types'; import { AttachmentService } from '../attachments'; import { PersistableStateAttachmentTypeRegistry } from '../../attachment_framework/persistable_state_registry'; -import type { CaseSavedObject } from '../../common/types'; +import type { CaseSavedObjectTransformed, CasePersistedAttributes } from '../../common/types/case'; +import { CasePersistedSeverity, CasePersistedStatus } from '../../common/types/case'; const createUpdateSOResponse = ({ connector, @@ -55,15 +54,15 @@ const createUpdateSOResponse = ({ }: { connector?: ESCaseConnectorWithId; externalService?: CaseFullExternalService; - severity?: ESCaseSeverity; - status?: ESCaseStatus; -} = {}): SavedObjectsUpdateResponse => { + severity?: CasePersistedSeverity; + status?: CasePersistedStatus; +} = {}): SavedObjectsUpdateResponse => { const references: SavedObjectReference[] = createSavedObjectReferences({ connector, externalService, }); - let attributes: Partial = { total_alerts: -1, total_comments: -1 }; + let attributes: Partial = { total_alerts: -1, total_comments: -1 }; if (connector) { const { id, ...restConnector } = connector; @@ -95,9 +94,9 @@ const createFindSO = ( params: { connector?: ESCaseConnectorWithId; externalService?: CaseFullExternalService; - overrides?: Partial; + overrides?: Partial; } = {} -): SavedObjectsFindResult => ({ +): SavedObjectsFindResult => ({ ...createCaseSavedObjectResponse(params), score: 0, }); @@ -174,7 +173,7 @@ describe('CasesService', () => { describe('patch', () => { it('includes the passed in fields', async () => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); await service.patchCase({ @@ -185,14 +184,14 @@ describe('CasesService', () => { severity: CaseSeverity.CRITICAL, status: CaseStatuses['in-progress'], }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); const { connector: ignoreConnector, external_service: ignoreExternalService, ...restUpdateAttributes - } = unsecuredSavedObjectsClient.update.mock.calls[0][2] as Partial; + } = unsecuredSavedObjectsClient.update.mock.calls[0][2] as Partial; expect(restUpdateAttributes).toMatchInlineSnapshot(` Object { "assignees": Array [], @@ -228,7 +227,7 @@ describe('CasesService', () => { it('transforms the connector.fields to an array of key/value pairs', async () => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); await service.patchCase({ @@ -237,11 +236,11 @@ describe('CasesService', () => { connector: createJiraConnector(), externalService: createExternalService(), }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); const { connector } = unsecuredSavedObjectsClient.update.mock - .calls[0][2] as Partial; + .calls[0][2] as Partial; expect(connector?.fields).toMatchInlineSnapshot(` Array [ Object { @@ -262,7 +261,7 @@ describe('CasesService', () => { it('preserves the connector fields but does not have the id', async () => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); await service.patchCase({ @@ -271,11 +270,11 @@ describe('CasesService', () => { connector: createJiraConnector(), externalService: createExternalService(), }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); const { connector } = unsecuredSavedObjectsClient.update.mock - .calls[0][2] as Partial; + .calls[0][2] as Partial; expect(connector).toMatchInlineSnapshot(` Object { "fields": Array [ @@ -300,17 +299,17 @@ describe('CasesService', () => { it('removes the connector id and adds it to the references', async () => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({ connector: createJiraConnector() }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); const updateAttributes = unsecuredSavedObjectsClient.update.mock - .calls[0][2] as Partial; + .calls[0][2] as Partial; expect(updateAttributes.connector).not.toHaveProperty('id'); const updateOptions = unsecuredSavedObjectsClient.update.mock @@ -328,7 +327,7 @@ describe('CasesService', () => { it('removes the external_service connector_id and adds it to the references', async () => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); await service.patchCase({ @@ -337,11 +336,11 @@ describe('CasesService', () => { connector: getNoneCaseConnector(), externalService: createExternalService(), }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); const updateAttributes = unsecuredSavedObjectsClient.update.mock - .calls[0][2] as Partial; + .calls[0][2] as Partial; expect(updateAttributes.external_service).not.toHaveProperty('connector_id'); const updateOptions = unsecuredSavedObjectsClient.update.mock @@ -359,7 +358,7 @@ describe('CasesService', () => { it('builds references for external service connector id, case connector id, and includes the existing references', async () => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); await service.patchCase({ @@ -370,7 +369,7 @@ describe('CasesService', () => { }), originalCase: { references: [{ id: 'a', name: 'awesome', type: 'hello' }], - } as CaseSavedObject, + } as CaseSavedObjectTransformed, }); const updateOptions = unsecuredSavedObjectsClient.update.mock @@ -398,7 +397,7 @@ describe('CasesService', () => { it('builds references for connector_id and preserves the existing connector.id reference', async () => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); await service.patchCase({ @@ -408,7 +407,7 @@ describe('CasesService', () => { references: [ { id: '1', name: CONNECTOR_ID_REFERENCE_NAME, type: ACTION_SAVED_OBJECT_TYPE }, ], - } as CaseSavedObject, + } as CaseSavedObjectTransformed, }); const updateOptions = unsecuredSavedObjectsClient.update.mock @@ -431,7 +430,7 @@ describe('CasesService', () => { it('preserves the external_service fields except for the connector_id', async () => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); await service.patchCase({ @@ -440,11 +439,11 @@ describe('CasesService', () => { connector: getNoneCaseConnector(), externalService: createExternalService(), }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); const updateAttributes = unsecuredSavedObjectsClient.update.mock - .calls[0][2] as Partial; + .calls[0][2] as Partial; expect(updateAttributes.external_service).toMatchInlineSnapshot(` Object { "connector_name": ".jira", @@ -463,13 +462,13 @@ describe('CasesService', () => { it('creates an empty updatedAttributes when there is no connector or external_service as input', async () => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(unsecuredSavedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot( @@ -482,13 +481,13 @@ describe('CasesService', () => { it('creates a updatedAttributes field with the none connector', async () => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({ connector: getNoneCaseConnector() }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(unsecuredSavedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` @@ -503,49 +502,49 @@ describe('CasesService', () => { }); it.each([ - [CaseSeverity.LOW, ESCaseSeverity.LOW], - [CaseSeverity.MEDIUM, ESCaseSeverity.MEDIUM], - [CaseSeverity.HIGH, ESCaseSeverity.HIGH], - [CaseSeverity.CRITICAL, ESCaseSeverity.CRITICAL], + [CaseSeverity.LOW, CasePersistedSeverity.LOW], + [CaseSeverity.MEDIUM, CasePersistedSeverity.MEDIUM], + [CaseSeverity.HIGH, CasePersistedSeverity.HIGH], + [CaseSeverity.CRITICAL, CasePersistedSeverity.CRITICAL], ])( 'properly converts "%s" severity to corresponding ES value on updating SO', async (patchParamsSeverity, expectedSeverity) => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({ severity: patchParamsSeverity }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); const patchAttributes = unsecuredSavedObjectsClient.update.mock - .calls[0][2] as ESCaseAttributes; + .calls[0][2] as CasePersistedAttributes; expect(patchAttributes.severity).toEqual(expectedSeverity); } ); it.each([ - [CaseStatuses.open, ESCaseStatus.OPEN], - [CaseStatuses['in-progress'], ESCaseStatus.IN_PROGRESS], - [CaseStatuses.closed, ESCaseStatus.CLOSED], + [CaseStatuses.open, CasePersistedStatus.OPEN], + [CaseStatuses['in-progress'], CasePersistedStatus.IN_PROGRESS], + [CaseStatuses.closed, CasePersistedStatus.CLOSED], ])( 'properly converts "%s" status to corresponding ES value on updating SO', async (patchParamsStatus, expectedStatus) => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({ status: patchParamsStatus }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); const patchAttributes = unsecuredSavedObjectsClient.update.mock - .calls[0][2] as ESCaseAttributes; + .calls[0][2] as CasePersistedAttributes; expect(patchAttributes.status).toEqual(expectedStatus); } @@ -571,7 +570,7 @@ describe('CasesService', () => { connector: getNoneCaseConnector(), severity: CaseSeverity.LOW, }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }, { caseId: '2', @@ -579,7 +578,7 @@ describe('CasesService', () => { connector: getNoneCaseConnector(), severity: CaseSeverity.MEDIUM, }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }, { caseId: '3', @@ -587,7 +586,7 @@ describe('CasesService', () => { connector: getNoneCaseConnector(), severity: CaseSeverity.HIGH, }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }, { caseId: '4', @@ -595,18 +594,18 @@ describe('CasesService', () => { connector: getNoneCaseConnector(), severity: CaseSeverity.CRITICAL, }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }, ], }); const patchResults = unsecuredSavedObjectsClient.bulkUpdate.mock - .calls[0][0] as unknown as Array>; + .calls[0][0] as unknown as Array>; - expect(patchResults[0].attributes.severity).toEqual(ESCaseSeverity.LOW); - expect(patchResults[1].attributes.severity).toEqual(ESCaseSeverity.MEDIUM); - expect(patchResults[2].attributes.severity).toEqual(ESCaseSeverity.HIGH); - expect(patchResults[3].attributes.severity).toEqual(ESCaseSeverity.CRITICAL); + expect(patchResults[0].attributes.severity).toEqual(CasePersistedSeverity.LOW); + expect(patchResults[1].attributes.severity).toEqual(CasePersistedSeverity.MEDIUM); + expect(patchResults[2].attributes.severity).toEqual(CasePersistedSeverity.HIGH); + expect(patchResults[3].attributes.severity).toEqual(CasePersistedSeverity.CRITICAL); }); it('properly converts status to corresponding ES value on bulk updating SO', async () => { @@ -626,7 +625,7 @@ describe('CasesService', () => { connector: getNoneCaseConnector(), status: CaseStatuses.open, }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }, { caseId: '2', @@ -634,7 +633,7 @@ describe('CasesService', () => { connector: getNoneCaseConnector(), status: CaseStatuses['in-progress'], }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }, { caseId: '3', @@ -642,23 +641,25 @@ describe('CasesService', () => { connector: getNoneCaseConnector(), status: CaseStatuses.closed, }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }, ], }); const patchResults = unsecuredSavedObjectsClient.bulkUpdate.mock - .calls[0][0] as unknown as Array>; + .calls[0][0] as unknown as Array>; - expect(patchResults[0].attributes.status).toEqual(ESCaseStatus.OPEN); - expect(patchResults[1].attributes.status).toEqual(ESCaseStatus.IN_PROGRESS); - expect(patchResults[2].attributes.status).toEqual(ESCaseStatus.CLOSED); + expect(patchResults[0].attributes.status).toEqual(CasePersistedStatus.OPEN); + expect(patchResults[1].attributes.status).toEqual(CasePersistedStatus.IN_PROGRESS); + expect(patchResults[2].attributes.status).toEqual(CasePersistedStatus.CLOSED); }); }); describe('post', () => { it('creates a null external_service field when the attribute was null in the creation parameters', async () => { - unsecuredSavedObjectsClient.create.mockResolvedValue({} as SavedObject); + unsecuredSavedObjectsClient.create.mockResolvedValue( + {} as SavedObject + ); await service.postNewCase({ attributes: createCasePostParams({ connector: createJiraConnector() }), @@ -671,7 +672,9 @@ describe('CasesService', () => { }); it('includes the creation attributes excluding the connector.id and connector_id', async () => { - unsecuredSavedObjectsClient.create.mockResolvedValue({} as SavedObject); + unsecuredSavedObjectsClient.create.mockResolvedValue( + {} as SavedObject + ); await service.postNewCase({ attributes: createCasePostParams({ @@ -682,7 +685,7 @@ describe('CasesService', () => { }); const creationAttributes = unsecuredSavedObjectsClient.create.mock - .calls[0][1] as ESCaseAttributes; + .calls[0][1] as CasePersistedAttributes; expect(creationAttributes.connector).not.toHaveProperty('id'); expect(creationAttributes.external_service).not.toHaveProperty('connector_id'); expect(creationAttributes).toMatchInlineSnapshot(` @@ -769,7 +772,9 @@ describe('CasesService', () => { }); it('includes default values for total_alerts and total_comments', async () => { - unsecuredSavedObjectsClient.create.mockResolvedValue({} as SavedObject); + unsecuredSavedObjectsClient.create.mockResolvedValue( + {} as SavedObject + ); await service.postNewCase({ attributes: createCasePostParams({ @@ -779,14 +784,16 @@ describe('CasesService', () => { }); const postAttributes = unsecuredSavedObjectsClient.create.mock - .calls[0][1] as ESCaseAttributes; + .calls[0][1] as CasePersistedAttributes; expect(postAttributes.total_alerts).toEqual(-1); expect(postAttributes.total_comments).toEqual(-1); }); it('moves the connector.id and connector_id to the references', async () => { - unsecuredSavedObjectsClient.create.mockResolvedValue({} as SavedObject); + unsecuredSavedObjectsClient.create.mockResolvedValue( + {} as SavedObject + ); await service.postNewCase({ attributes: createCasePostParams({ @@ -815,7 +822,9 @@ describe('CasesService', () => { }); it('sets fields to an empty array when it is not included with the connector', async () => { - unsecuredSavedObjectsClient.create.mockResolvedValue({} as SavedObject); + unsecuredSavedObjectsClient.create.mockResolvedValue( + {} as SavedObject + ); await service.postNewCase({ attributes: createCasePostParams({ @@ -831,7 +840,9 @@ describe('CasesService', () => { }); it('does not create a reference for a none connector', async () => { - unsecuredSavedObjectsClient.create.mockResolvedValue({} as SavedObject); + unsecuredSavedObjectsClient.create.mockResolvedValue( + {} as SavedObject + ); await service.postNewCase({ attributes: createCasePostParams({ connector: getNoneCaseConnector() }), @@ -844,7 +855,9 @@ describe('CasesService', () => { }); it('does not create a reference for an external_service field that is null', async () => { - unsecuredSavedObjectsClient.create.mockResolvedValue({} as SavedObject); + unsecuredSavedObjectsClient.create.mockResolvedValue( + {} as SavedObject + ); await service.postNewCase({ attributes: createCasePostParams({ connector: getNoneCaseConnector() }), @@ -857,14 +870,16 @@ describe('CasesService', () => { }); it.each([ - [CaseSeverity.LOW, ESCaseSeverity.LOW], - [CaseSeverity.MEDIUM, ESCaseSeverity.MEDIUM], - [CaseSeverity.HIGH, ESCaseSeverity.HIGH], - [CaseSeverity.CRITICAL, ESCaseSeverity.CRITICAL], + [CaseSeverity.LOW, CasePersistedSeverity.LOW], + [CaseSeverity.MEDIUM, CasePersistedSeverity.MEDIUM], + [CaseSeverity.HIGH, CasePersistedSeverity.HIGH], + [CaseSeverity.CRITICAL, CasePersistedSeverity.CRITICAL], ])( 'properly converts "%s" severity to corresponding ES value on creating SO', async (postParamsSeverity, expectedSeverity) => { - unsecuredSavedObjectsClient.create.mockResolvedValue({} as SavedObject); + unsecuredSavedObjectsClient.create.mockResolvedValue( + {} as SavedObject + ); await service.postNewCase({ attributes: createCasePostParams({ @@ -875,19 +890,21 @@ describe('CasesService', () => { }); const postAttributes = unsecuredSavedObjectsClient.create.mock - .calls[0][1] as ESCaseAttributes; + .calls[0][1] as CasePersistedAttributes; expect(postAttributes.severity).toEqual(expectedSeverity); } ); it.each([ - [CaseStatuses.open, ESCaseStatus.OPEN], - [CaseStatuses['in-progress'], ESCaseStatus.IN_PROGRESS], - [CaseStatuses.closed, ESCaseStatus.CLOSED], + [CaseStatuses.open, CasePersistedStatus.OPEN], + [CaseStatuses['in-progress'], CasePersistedStatus.IN_PROGRESS], + [CaseStatuses.closed, CasePersistedStatus.CLOSED], ])( 'properly converts "%s" status to corresponding ES value on creating SO', async (postParamsStatus, expectedStatus) => { - unsecuredSavedObjectsClient.create.mockResolvedValue({} as SavedObject); + unsecuredSavedObjectsClient.create.mockResolvedValue( + {} as SavedObject + ); await service.postNewCase({ attributes: createCasePostParams({ @@ -898,7 +915,7 @@ describe('CasesService', () => { }); const postAttributes = unsecuredSavedObjectsClient.create.mock - .calls[0][1] as ESCaseAttributes; + .calls[0][1] as CasePersistedAttributes; expect(postAttributes.status).toEqual(expectedStatus); } ); @@ -929,7 +946,7 @@ describe('CasesService', () => { connector: createJiraConnector(), externalService: createExternalService(), }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }, ], }); @@ -970,10 +987,16 @@ describe('CasesService', () => { it('properly converts the severity field to the corresponding external value in the bulkPatch response', async () => { unsecuredSavedObjectsClient.bulkUpdate.mockResolvedValue({ saved_objects: [ - createCaseSavedObjectResponse({ overrides: { severity: ESCaseSeverity.LOW } }), - createCaseSavedObjectResponse({ overrides: { severity: ESCaseSeverity.MEDIUM } }), - createCaseSavedObjectResponse({ overrides: { severity: ESCaseSeverity.HIGH } }), - createCaseSavedObjectResponse({ overrides: { severity: ESCaseSeverity.CRITICAL } }), + createCaseSavedObjectResponse({ overrides: { severity: CasePersistedSeverity.LOW } }), + createCaseSavedObjectResponse({ + overrides: { severity: CasePersistedSeverity.MEDIUM }, + }), + createCaseSavedObjectResponse({ + overrides: { severity: CasePersistedSeverity.HIGH }, + }), + createCaseSavedObjectResponse({ + overrides: { severity: CasePersistedSeverity.CRITICAL }, + }), ], }); @@ -982,7 +1005,7 @@ describe('CasesService', () => { { caseId: '1', updatedAttributes: createCasePostParams({ connector: getNoneCaseConnector() }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }, ], }); @@ -995,9 +1018,11 @@ describe('CasesService', () => { it('properly converts the status field to the corresponding external value in the bulkPatch response', async () => { unsecuredSavedObjectsClient.bulkUpdate.mockResolvedValue({ saved_objects: [ - createCaseSavedObjectResponse({ overrides: { status: ESCaseStatus.OPEN } }), - createCaseSavedObjectResponse({ overrides: { status: ESCaseStatus.IN_PROGRESS } }), - createCaseSavedObjectResponse({ overrides: { status: ESCaseStatus.CLOSED } }), + createCaseSavedObjectResponse({ overrides: { status: CasePersistedStatus.OPEN } }), + createCaseSavedObjectResponse({ + overrides: { status: CasePersistedStatus.IN_PROGRESS }, + }), + createCaseSavedObjectResponse({ overrides: { status: CasePersistedStatus.CLOSED } }), ], }); @@ -1006,7 +1031,7 @@ describe('CasesService', () => { { caseId: '1', updatedAttributes: createCasePostParams({ connector: getNoneCaseConnector() }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }, ], }); @@ -1029,7 +1054,7 @@ describe('CasesService', () => { { caseId: '1', updatedAttributes: createCasePostParams({ connector: getNoneCaseConnector() }), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }, ], }); @@ -1052,7 +1077,7 @@ describe('CasesService', () => { const res = await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(res.attributes).toMatchInlineSnapshot(` @@ -1076,7 +1101,7 @@ describe('CasesService', () => { const res = await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(res.attributes).toMatchInlineSnapshot(` @@ -1093,7 +1118,7 @@ describe('CasesService', () => { const res = await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(res.attributes).toMatchInlineSnapshot(`Object {}`); @@ -1102,13 +1127,13 @@ describe('CasesService', () => { it('returns an undefined connector if it is not returned by the update', async () => { unsecuredSavedObjectsClient.update.mockResolvedValue( - {} as SavedObjectsUpdateResponse + {} as SavedObjectsUpdateResponse ); const res = await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(res).toMatchInlineSnapshot(` @@ -1120,7 +1145,7 @@ describe('CasesService', () => { it('returns the default none connector when it cannot find the reference', async () => { const { name, type, fields } = createESJiraConnector(); - const returnValue: SavedObjectsUpdateResponse = { + const returnValue: SavedObjectsUpdateResponse = { type: CASE_SAVED_OBJECT, id: '1', attributes: { @@ -1139,7 +1164,7 @@ describe('CasesService', () => { const res = await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(res.attributes.connector).toMatchInlineSnapshot(` @@ -1154,7 +1179,7 @@ describe('CasesService', () => { it('returns none external service connector when it cannot find the reference', async () => { const { connector_id: id, ...restExternalConnector } = createExternalService()!; - const returnValue: SavedObjectsUpdateResponse = { + const returnValue: SavedObjectsUpdateResponse = { type: CASE_SAVED_OBJECT, id: '1', attributes: { @@ -1169,7 +1194,7 @@ describe('CasesService', () => { const res = await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(res.attributes.external_service?.connector_id).toBe('none'); @@ -1177,7 +1202,7 @@ describe('CasesService', () => { it('returns the saved object fields when it cannot find the reference for connector_id', async () => { const { connector_id: id, ...restExternalConnector } = createExternalService()!; - const returnValue: SavedObjectsUpdateResponse = { + const returnValue: SavedObjectsUpdateResponse = { type: CASE_SAVED_OBJECT, id: '1', attributes: { @@ -1192,7 +1217,7 @@ describe('CasesService', () => { const res = await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(res).toMatchInlineSnapshot(` @@ -1228,7 +1253,7 @@ describe('CasesService', () => { const res = await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(res.attributes.connector).toMatchInlineSnapshot(` @@ -1254,7 +1279,7 @@ describe('CasesService', () => { const res = await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(res.attributes.external_service).toMatchInlineSnapshot(` @@ -1276,10 +1301,10 @@ describe('CasesService', () => { }); it.each([ - [ESCaseSeverity.LOW, CaseSeverity.LOW], - [ESCaseSeverity.MEDIUM, CaseSeverity.MEDIUM], - [ESCaseSeverity.HIGH, CaseSeverity.HIGH], - [ESCaseSeverity.CRITICAL, CaseSeverity.CRITICAL], + [CasePersistedSeverity.LOW, CaseSeverity.LOW], + [CasePersistedSeverity.MEDIUM, CaseSeverity.MEDIUM], + [CasePersistedSeverity.HIGH, CaseSeverity.HIGH], + [CasePersistedSeverity.CRITICAL, CaseSeverity.CRITICAL], ])( 'properly converts "%s" severity to corresponding external value in the patch response', async (internalSeverityValue, expectedSeverity) => { @@ -1290,7 +1315,7 @@ describe('CasesService', () => { const res = await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(res.attributes.severity).toEqual(expectedSeverity); @@ -1298,9 +1323,9 @@ describe('CasesService', () => { ); it.each([ - [ESCaseStatus.OPEN, CaseStatuses.open], - [ESCaseStatus.IN_PROGRESS, CaseStatuses['in-progress']], - [ESCaseStatus.CLOSED, CaseStatuses.closed], + [CasePersistedStatus.OPEN, CaseStatuses.open], + [CasePersistedStatus.IN_PROGRESS, CaseStatuses['in-progress']], + [CasePersistedStatus.CLOSED, CaseStatuses.closed], ])( 'properly converts "%s" status to corresponding external value in the patch response', async (internalStatusValue, expectedStatus) => { @@ -1311,7 +1336,7 @@ describe('CasesService', () => { const res = await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(res.attributes.status).toEqual(expectedStatus); @@ -1324,7 +1349,7 @@ describe('CasesService', () => { const res = await service.patchCase({ caseId: '1', updatedAttributes: createCaseUpdateParams({}), - originalCase: {} as CaseSavedObject, + originalCase: {} as CaseSavedObjectTransformed, }); expect(res.attributes).not.toHaveProperty('total_alerts'); @@ -1351,10 +1376,10 @@ describe('CasesService', () => { }); it.each([ - [ESCaseSeverity.LOW, CaseSeverity.LOW], - [ESCaseSeverity.MEDIUM, CaseSeverity.MEDIUM], - [ESCaseSeverity.HIGH, CaseSeverity.HIGH], - [ESCaseSeverity.CRITICAL, CaseSeverity.CRITICAL], + [CasePersistedSeverity.LOW, CaseSeverity.LOW], + [CasePersistedSeverity.MEDIUM, CaseSeverity.MEDIUM], + [CasePersistedSeverity.HIGH, CaseSeverity.HIGH], + [CasePersistedSeverity.CRITICAL, CaseSeverity.CRITICAL], ])( 'properly converts "%s" severity to corresponding external value in the post response', async (internalSeverityValue, expectedSeverity) => { @@ -1372,9 +1397,9 @@ describe('CasesService', () => { ); it.each([ - [ESCaseStatus.OPEN, CaseStatuses.open], - [ESCaseStatus.IN_PROGRESS, CaseStatuses['in-progress']], - [ESCaseStatus.CLOSED, CaseStatuses.closed], + [CasePersistedStatus.OPEN, CaseStatuses.open], + [CasePersistedStatus.IN_PROGRESS, CaseStatuses['in-progress']], + [CasePersistedStatus.CLOSED, CaseStatuses.closed], ])( 'properly converts "%s" status to corresponding external value in the post response', async (internalStatusValue, expectedStatus) => { @@ -1444,10 +1469,10 @@ describe('CasesService', () => { }); it.each([ - [ESCaseSeverity.LOW, CaseSeverity.LOW], - [ESCaseSeverity.MEDIUM, CaseSeverity.MEDIUM], - [ESCaseSeverity.HIGH, CaseSeverity.HIGH], - [ESCaseSeverity.CRITICAL, CaseSeverity.CRITICAL], + [CasePersistedSeverity.LOW, CaseSeverity.LOW], + [CasePersistedSeverity.MEDIUM, CaseSeverity.MEDIUM], + [CasePersistedSeverity.HIGH, CaseSeverity.HIGH], + [CasePersistedSeverity.CRITICAL, CaseSeverity.CRITICAL], ])( 'includes the properly converted "%s" severity field in the result', async (severity, expectedSeverity) => { @@ -1463,9 +1488,9 @@ describe('CasesService', () => { ); it.each([ - [ESCaseStatus.OPEN, CaseStatuses.open], - [ESCaseStatus.IN_PROGRESS, CaseStatuses['in-progress']], - [ESCaseStatus.CLOSED, CaseStatuses.closed], + [CasePersistedStatus.OPEN, CaseStatuses.open], + [CasePersistedStatus.IN_PROGRESS, CaseStatuses['in-progress']], + [CasePersistedStatus.CLOSED, CaseStatuses.closed], ])( 'includes the properly converted "%s" status field in the result', async (status, expectedStatus) => { @@ -1523,16 +1548,16 @@ describe('CasesService', () => { unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ saved_objects: [ createCaseSavedObjectResponse({ - overrides: { severity: ESCaseSeverity.LOW }, + overrides: { severity: CasePersistedSeverity.LOW }, }), createCaseSavedObjectResponse({ - overrides: { severity: ESCaseSeverity.MEDIUM }, + overrides: { severity: CasePersistedSeverity.MEDIUM }, }), createCaseSavedObjectResponse({ - overrides: { severity: ESCaseSeverity.HIGH }, + overrides: { severity: CasePersistedSeverity.HIGH }, }), createCaseSavedObjectResponse({ - overrides: { severity: ESCaseSeverity.CRITICAL }, + overrides: { severity: CasePersistedSeverity.CRITICAL }, }), ], }); @@ -1548,13 +1573,13 @@ describe('CasesService', () => { unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ saved_objects: [ createCaseSavedObjectResponse({ - overrides: { status: ESCaseStatus.OPEN }, + overrides: { status: CasePersistedStatus.OPEN }, }), createCaseSavedObjectResponse({ - overrides: { status: ESCaseStatus.IN_PROGRESS }, + overrides: { status: CasePersistedStatus.IN_PROGRESS }, }), createCaseSavedObjectResponse({ - overrides: { status: ESCaseStatus.CLOSED }, + overrides: { status: CasePersistedStatus.CLOSED }, }), ], }); @@ -1652,7 +1677,7 @@ describe('CasesService', () => { type: ACTION_SAVED_OBJECT_TYPE, }, ], - } as unknown as SavedObject); + } as unknown as SavedObject); const res = await service.getCase({ id: 'a' }); expect(res.attributes.connector).toMatchInlineSnapshot(` @@ -1670,7 +1695,7 @@ describe('CasesService', () => { it('returns a null external_services when it is already null', async () => { unsecuredSavedObjectsClient.get.mockResolvedValue({ attributes: { external_service: null }, - } as SavedObject); + } as SavedObject); const res = await service.getCase({ id: 'a' }); expect(res.attributes.connector).toMatchInlineSnapshot(` @@ -1686,16 +1711,16 @@ describe('CasesService', () => { }); it.each([ - [ESCaseSeverity.LOW, CaseSeverity.LOW], - [ESCaseSeverity.MEDIUM, CaseSeverity.MEDIUM], - [ESCaseSeverity.HIGH, CaseSeverity.HIGH], - [ESCaseSeverity.CRITICAL, CaseSeverity.CRITICAL], + [CasePersistedSeverity.LOW, CaseSeverity.LOW], + [CasePersistedSeverity.MEDIUM, CaseSeverity.MEDIUM], + [CasePersistedSeverity.HIGH, CaseSeverity.HIGH], + [CasePersistedSeverity.CRITICAL, CaseSeverity.CRITICAL], ])( 'includes the properly converted "%s" severity field in the result', async (internalSeverityValue, expectedSeverity) => { unsecuredSavedObjectsClient.get.mockResolvedValue({ attributes: { severity: internalSeverityValue }, - } as SavedObject); + } as SavedObject); const res = await service.getCase({ id: 'a' }); @@ -1704,15 +1729,15 @@ describe('CasesService', () => { ); it.each([ - [ESCaseStatus.OPEN, CaseStatuses.open], - [ESCaseStatus.IN_PROGRESS, CaseStatuses['in-progress']], - [ESCaseStatus.CLOSED, CaseStatuses.closed], + [CasePersistedStatus.OPEN, CaseStatuses.open], + [CasePersistedStatus.IN_PROGRESS, CaseStatuses['in-progress']], + [CasePersistedStatus.CLOSED, CaseStatuses.closed], ])( 'includes the properly converted "%s" status field in the result', async (internalStatusValue, expectedStatus) => { unsecuredSavedObjectsClient.get.mockResolvedValue({ attributes: { status: internalStatusValue }, - } as SavedObject); + } as SavedObject); const res = await service.getCase({ id: 'a' }); @@ -1726,7 +1751,7 @@ describe('CasesService', () => { total_alerts: -1, total_comments: -1, }, - } as unknown as SavedObject); + } as unknown as SavedObject); const res = await service.getCase({ id: 'a' }); expect(res.attributes).not.toHaveProperty('total_alerts'); @@ -1760,7 +1785,7 @@ describe('CasesService', () => { page: 1, per_page: 1, aggregations: { myAggregation: { value: 0 } }, - } as SavedObjectsFindResponse); + } as SavedObjectsFindResponse); const res = await service.executeAggregations({ aggregationBuilders }); expect(res).toEqual({ myAggregation: { value: 0 } }); @@ -1773,7 +1798,7 @@ describe('CasesService', () => { page: 1, per_page: 1, aggregations: { myAggregation: { value: 0 } }, - } as SavedObjectsFindResponse); + } as SavedObjectsFindResponse); await service.executeAggregations({ aggregationBuilders, options: { perPage: 20 } }); expect(unsecuredSavedObjectsClient.find.mock.calls[0][0]).toMatchInlineSnapshot(` diff --git a/x-pack/plugins/cases/server/services/cases/index.ts b/x-pack/plugins/cases/server/services/cases/index.ts index bc694a44d93eb..93c6d610d5539 100644 --- a/x-pack/plugins/cases/server/services/cases/index.ts +++ b/x-pack/plugins/cases/server/services/cases/index.ts @@ -20,7 +20,6 @@ import type { } from '@kbn/core/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import type { KueryNode } from '@kbn/es-query'; import { nodeBuilder } from '@kbn/es-query'; import { @@ -28,16 +27,9 @@ import { CASE_SAVED_OBJECT, MAX_DOCS_PER_PAGE, } from '../../../common/constants'; -import type { - CaseResponse, - CasesFindRequest, - CommentAttributes, - User, - CaseAttributes, - CaseStatuses, -} from '../../../common/api'; +import type { Case, CommentAttributes, User, CaseStatuses } from '../../../common/api'; import { caseStatuses } from '../../../common/api'; -import type { CaseSavedObject, SavedObjectFindOptionsKueryNode } from '../../common/types'; +import type { SavedObjectFindOptionsKueryNode } from '../../common/types'; import { defaultSortField, flattenCaseSavedObject } from '../../common/utils'; import { DEFAULT_PAGE, DEFAULT_PER_PAGE } from '../../routes/api'; import { combineFilters } from '../../client/utils'; @@ -50,88 +42,30 @@ import { transformBulkResponseToExternalModel, transformFindResponseToExternalModel, } from './transform'; -import type { ESCaseAttributes } from './types'; -import { ESCaseStatus } from './types'; import type { AttachmentService } from '../attachments'; import type { AggregationBuilder, AggregationResponse } from '../../client/metrics/types'; import { createCaseError } from '../../common/error'; -import type { IndexRefresh } from '../types'; - -interface GetCaseIdsByAlertIdArgs { - alertId: string; - filter?: KueryNode; -} - -interface PushedArgs { - pushed_at: string; - pushed_by: User; -} - -interface GetCaseArgs { - id: string; -} - -interface DeleteCaseArgs extends GetCaseArgs, IndexRefresh {} - -interface GetCasesArgs { - caseIds: string[]; - fields?: string[]; -} - -interface FindCommentsArgs { - id: string | string[]; - options?: SavedObjectFindOptionsKueryNode; -} - -interface FindCaseCommentsArgs { - id: string | string[]; - options?: SavedObjectFindOptionsKueryNode; -} - -interface PostCaseArgs extends IndexRefresh { - attributes: CaseAttributes; - id: string; -} - -interface PatchCase extends IndexRefresh { - caseId: string; - updatedAttributes: Partial; - originalCase: CaseSavedObject; - version?: string; -} -type PatchCaseArgs = PatchCase; - -interface PatchCasesArgs extends IndexRefresh { - cases: Array>; -} - -interface CasesMapWithPageInfo { - casesMap: Map; - page: number; - perPage: number; - total: number; -} - -type FindCaseOptions = CasesFindRequest & SavedObjectFindOptionsKueryNode; - -interface GetTagsArgs { - unsecuredSavedObjectsClient: SavedObjectsClientContract; - filter?: KueryNode; -} - -interface GetReportersArgs { - unsecuredSavedObjectsClient: SavedObjectsClientContract; - filter?: KueryNode; -} - -interface GetCaseIdsByAlertIdAggs { - references: { - doc_count: number; - caseIds: { - buckets: Array<{ key: string }>; - }; - }; -} +import type { + CasePersistedAttributes, + CaseSavedObjectTransformed, + CaseTransformedAttributes, +} from '../../common/types/case'; +import { CasePersistedStatus } from '../../common/types/case'; +import type { + GetCaseIdsByAlertIdArgs, + GetCaseIdsByAlertIdAggs, + CasesMapWithPageInfo, + DeleteCaseArgs, + GetCaseArgs, + GetCasesArgs, + FindCommentsArgs, + FindCaseCommentsArgs, + GetReportersArgs, + GetTagsArgs, + PostCaseArgs, + PatchCaseArgs, + PatchCasesArgs, +} from './types'; export class CasesService { private readonly log: Logger; @@ -174,7 +108,7 @@ export class CasesService { alertId, filter, }: GetCaseIdsByAlertIdArgs): Promise< - SavedObjectsFindResponse + SavedObjectsFindResponse<{ owner: string }, GetCaseIdsByAlertIdAggs> > { try { this.log.debug(`Attempting to GET all cases for alert id ${alertId}`); @@ -184,7 +118,7 @@ export class CasesService { ]); const response = await this.unsecuredSavedObjectsClient.find< - CommentAttributes, + { owner: string }, GetCaseIdsByAlertIdAggs >({ type: CASE_COMMENT_SAVED_OBJECT, @@ -206,7 +140,7 @@ export class CasesService { * Extracts the case IDs from the alert aggregation */ public static getCaseIDsFromAlertAggs( - result: SavedObjectsFindResponse + result: SavedObjectsFindResponse ): string[] { return result.aggregations?.references.caseIds.buckets.map((b) => b.key) ?? []; } @@ -217,20 +151,20 @@ export class CasesService { public async findCasesGroupedByID({ caseOptions, }: { - caseOptions: FindCaseOptions; + caseOptions: SavedObjectFindOptionsKueryNode; }): Promise { const cases = await this.findCases(caseOptions); const casesMap = cases.saved_objects.reduce((accMap, caseInfo) => { accMap.set(caseInfo.id, caseInfo); return accMap; - }, new Map>()); + }, new Map>()); const commentTotals = await this.attachmentService.getter.getCaseCommentStats({ caseIds: Array.from(casesMap.keys()), }); - const casesWithComments = new Map(); + const casesWithComments = new Map(); for (const [id, caseInfo] of casesMap.entries()) { const { alerts, userComments } = commentTotals.get(id) ?? { alerts: 0, userComments: 0 }; @@ -260,7 +194,7 @@ export class CasesService { [status in CaseStatuses]: number; }> { const cases = await this.unsecuredSavedObjectsClient.find< - ESCaseAttributes, + CasePersistedAttributes, { statuses: { buckets: Array<{ @@ -286,9 +220,9 @@ export class CasesService { const statusBuckets = CasesService.getStatusBuckets(cases.aggregations?.statuses.buckets); return { - open: statusBuckets?.get(ESCaseStatus.OPEN) ?? 0, - 'in-progress': statusBuckets?.get(ESCaseStatus.IN_PROGRESS) ?? 0, - closed: statusBuckets?.get(ESCaseStatus.CLOSED) ?? 0, + open: statusBuckets?.get(CasePersistedStatus.OPEN) ?? 0, + 'in-progress': statusBuckets?.get(CasePersistedStatus.IN_PROGRESS) ?? 0, + closed: statusBuckets?.get(CasePersistedStatus.CLOSED) ?? 0, }; } @@ -326,10 +260,10 @@ export class CasesService { } } - public async getCase({ id: caseId }: GetCaseArgs): Promise { + public async getCase({ id: caseId }: GetCaseArgs): Promise { try { this.log.debug(`Attempting to GET case ${caseId}`); - const caseSavedObject = await this.unsecuredSavedObjectsClient.get( + const caseSavedObject = await this.unsecuredSavedObjectsClient.get( CASE_SAVED_OBJECT, caseId ); @@ -342,13 +276,14 @@ export class CasesService { public async getResolveCase({ id: caseId, - }: GetCaseArgs): Promise> { + }: GetCaseArgs): Promise> { try { this.log.debug(`Attempting to resolve case ${caseId}`); - const resolveCaseResult = await this.unsecuredSavedObjectsClient.resolve( - CASE_SAVED_OBJECT, - caseId - ); + const resolveCaseResult = + await this.unsecuredSavedObjectsClient.resolve( + CASE_SAVED_OBJECT, + caseId + ); return { ...resolveCaseResult, saved_object: transformSavedObjectToExternalModel(resolveCaseResult.saved_object), @@ -362,10 +297,10 @@ export class CasesService { public async getCases({ caseIds, fields, - }: GetCasesArgs): Promise> { + }: GetCasesArgs): Promise> { try { this.log.debug(`Attempting to GET cases ${caseIds.join(', ')}`); - const cases = await this.unsecuredSavedObjectsClient.bulkGet( + const cases = await this.unsecuredSavedObjectsClient.bulkGet( caseIds.map((caseId) => ({ type: CASE_SAVED_OBJECT, id: caseId, fields })) ); return transformBulkResponseToExternalModel(cases); @@ -377,14 +312,15 @@ export class CasesService { public async findCases( options?: SavedObjectFindOptionsKueryNode - ): Promise> { + ): Promise> { try { this.log.debug(`Attempting to find cases`); - const cases = await this.unsecuredSavedObjectsClient.find({ + const cases = await this.unsecuredSavedObjectsClient.find({ sortField: defaultSortField, ...options, type: CASE_SAVED_OBJECT, }); + return transformFindResponseToExternalModel(cases); } catch (error) { this.log.error(`Error on find cases: ${error}`); @@ -402,6 +338,8 @@ export class CasesService { } } + // TODO: This should probably be moved into the client since it is after the transform has + // occurred within the attachment service private async getAllComments({ id, options, @@ -431,6 +369,8 @@ export class CasesService { } } + // TODO: This should probably be moved into the client since it is after the transform has + // occurred within the attachment service /** * Default behavior is to retrieve all comments that adhere to a given filter (if one is included). * to override this pass in the either the page or perPage options. @@ -471,7 +411,7 @@ export class CasesService { this.log.debug(`Attempting to GET all reporters`); const results = await this.unsecuredSavedObjectsClient.find< - ESCaseAttributes, + CasePersistedAttributes, { reporters: { buckets: Array<{ @@ -533,7 +473,7 @@ export class CasesService { this.log.debug(`Attempting to GET all cases`); const results = await this.unsecuredSavedObjectsClient.find< - ESCaseAttributes, + CasePersistedAttributes, { tags: { buckets: Array<{ key: string }> } } >({ type: CASE_SAVED_OBJECT, @@ -558,7 +498,11 @@ export class CasesService { } } - public async postNewCase({ attributes, id, refresh }: PostCaseArgs): Promise { + public async postNewCase({ + attributes, + id, + refresh, + }: PostCaseArgs): Promise { try { this.log.debug(`Attempting to POST a new case`); const transformedAttributes = transformAttributesToESModel(attributes); @@ -566,7 +510,7 @@ export class CasesService { transformedAttributes.attributes.total_alerts = -1; transformedAttributes.attributes.total_comments = -1; - const createdCase = await this.unsecuredSavedObjectsClient.create( + const createdCase = await this.unsecuredSavedObjectsClient.create( CASE_SAVED_OBJECT, transformedAttributes.attributes, { id, references: transformedAttributes.referenceHandler.build(), refresh } @@ -585,12 +529,12 @@ export class CasesService { originalCase, version, refresh, - }: PatchCaseArgs): Promise> { + }: PatchCaseArgs): Promise> { try { this.log.debug(`Attempting to UPDATE case ${caseId}`); const transformedAttributes = transformAttributesToESModel(updatedAttributes); - const updatedCase = await this.unsecuredSavedObjectsClient.update( + const updatedCase = await this.unsecuredSavedObjectsClient.update( CASE_SAVED_OBJECT, caseId, transformedAttributes.attributes, @@ -611,7 +555,7 @@ export class CasesService { public async patchCases({ cases, refresh, - }: PatchCasesArgs): Promise> { + }: PatchCasesArgs): Promise> { try { this.log.debug(`Attempting to UPDATE case ${cases.map((c) => c.caseId).join(', ')}`); @@ -626,10 +570,10 @@ export class CasesService { }; }); - const updatedCases = await this.unsecuredSavedObjectsClient.bulkUpdate( - bulkUpdate, - { refresh } - ); + const updatedCases = + await this.unsecuredSavedObjectsClient.bulkUpdate(bulkUpdate, { + refresh, + }); return transformUpdateResponsesToExternalModels(updatedCases); } catch (error) { @@ -651,7 +595,7 @@ export class CasesService { }, {}); const res = await this.unsecuredSavedObjectsClient.find< - ESCaseAttributes, + CasePersistedAttributes, AggregationResponse >({ sortField: defaultSortField, diff --git a/x-pack/plugins/cases/server/services/cases/transform.test.ts b/x-pack/plugins/cases/server/services/cases/transform.test.ts index afd2de272bc42..1ba613e8c6d1e 100644 --- a/x-pack/plugins/cases/server/services/cases/transform.test.ts +++ b/x-pack/plugins/cases/server/services/cases/transform.test.ts @@ -23,7 +23,7 @@ import { PUSH_CONNECTOR_ID_REFERENCE_NAME, } from '../../common/constants'; import { getNoneCaseConnector } from '../../common/utils'; -import { ESCaseSeverity, ESCaseStatus } from './types'; +import { CasePersistedSeverity, CasePersistedStatus } from '../../common/types/case'; describe('case transforms', () => { describe('transformUpdateResponseToExternalModel', () => { @@ -200,10 +200,10 @@ describe('case transforms', () => { }); it.each([ - [ESCaseSeverity.LOW, CaseSeverity.LOW], - [ESCaseSeverity.MEDIUM, CaseSeverity.MEDIUM], - [ESCaseSeverity.HIGH, CaseSeverity.HIGH], - [ESCaseSeverity.CRITICAL, CaseSeverity.CRITICAL], + [CasePersistedSeverity.LOW, CaseSeverity.LOW], + [CasePersistedSeverity.MEDIUM, CaseSeverity.MEDIUM], + [CasePersistedSeverity.HIGH, CaseSeverity.HIGH], + [CasePersistedSeverity.CRITICAL, CaseSeverity.CRITICAL], ])( 'properly converts "%s" severity to corresponding external value "%s"', (internalSeverityValue, expectedSeverityValue) => { @@ -222,9 +222,9 @@ describe('case transforms', () => { ); it.each([ - [ESCaseStatus.OPEN, CaseStatuses.open], - [ESCaseStatus.IN_PROGRESS, CaseStatuses['in-progress']], - [ESCaseStatus.CLOSED, CaseStatuses.closed], + [CasePersistedStatus.OPEN, CaseStatuses.open], + [CasePersistedStatus.IN_PROGRESS, CaseStatuses['in-progress']], + [CasePersistedStatus.CLOSED, CaseStatuses.closed], ])( 'properly converts "%s" status to corresponding ES Value "%s"', (internalStatusValue, expectedStatusValue) => { @@ -387,10 +387,10 @@ describe('case transforms', () => { }); it.each([ - [CaseSeverity.LOW, ESCaseSeverity.LOW], - [CaseSeverity.MEDIUM, ESCaseSeverity.MEDIUM], - [CaseSeverity.HIGH, ESCaseSeverity.HIGH], - [CaseSeverity.CRITICAL, ESCaseSeverity.CRITICAL], + [CaseSeverity.LOW, CasePersistedSeverity.LOW], + [CaseSeverity.MEDIUM, CasePersistedSeverity.MEDIUM], + [CaseSeverity.HIGH, CasePersistedSeverity.HIGH], + [CaseSeverity.CRITICAL, CasePersistedSeverity.CRITICAL], ])( 'properly converts "%s" severity to corresponding ES Value "%s"', (externalSeverityValue, expectedSeverityValue) => { @@ -410,9 +410,9 @@ describe('case transforms', () => { }); it.each([ - [CaseStatuses.open, ESCaseStatus.OPEN], - [CaseStatuses['in-progress'], ESCaseStatus.IN_PROGRESS], - [CaseStatuses.closed, ESCaseStatus.CLOSED], + [CaseStatuses.open, CasePersistedStatus.OPEN], + [CaseStatuses['in-progress'], CasePersistedStatus.IN_PROGRESS], + [CaseStatuses.closed, CasePersistedStatus.CLOSED], ])( 'properly converts "%s" status to corresponding ES Value "%s"', (externalStatusValue, expectedStatusValue) => { @@ -501,10 +501,10 @@ describe('case transforms', () => { }); it.each([ - [ESCaseSeverity.LOW, CaseSeverity.LOW], - [ESCaseSeverity.MEDIUM, CaseSeverity.MEDIUM], - [ESCaseSeverity.HIGH, CaseSeverity.HIGH], - [ESCaseSeverity.CRITICAL, CaseSeverity.CRITICAL], + [CasePersistedSeverity.LOW, CaseSeverity.LOW], + [CasePersistedSeverity.MEDIUM, CaseSeverity.MEDIUM], + [CasePersistedSeverity.HIGH, CaseSeverity.HIGH], + [CasePersistedSeverity.CRITICAL, CaseSeverity.CRITICAL], ])( 'properly converts "%s" severity to corresponding external value "%s"', (internalSeverityValue, expectedSeverityValue) => { @@ -529,9 +529,9 @@ describe('case transforms', () => { }); it.each([ - [ESCaseStatus.OPEN, CaseStatuses.open], - [ESCaseStatus.IN_PROGRESS, CaseStatuses['in-progress']], - [ESCaseStatus.CLOSED, CaseStatuses.closed], + [CasePersistedStatus.OPEN, CaseStatuses.open], + [CasePersistedStatus.IN_PROGRESS, CaseStatuses['in-progress']], + [CasePersistedStatus.CLOSED, CaseStatuses.closed], ])( 'properly converts "%s" status to corresponding external value "%s"', (internalStatusValue, expectedStatusValue) => { diff --git a/x-pack/plugins/cases/server/services/cases/transform.ts b/x-pack/plugins/cases/server/services/cases/transform.ts index 6adacf41f526a..5b31bde8107c4 100644 --- a/x-pack/plugins/cases/server/services/cases/transform.ts +++ b/x-pack/plugins/cases/server/services/cases/transform.ts @@ -16,7 +16,6 @@ import type { SavedObjectsUpdateResponse, } from '@kbn/core/server'; import { ACTION_SAVED_OBJECT_TYPE } from '@kbn/actions-plugin/server'; -import type { ESCaseAttributes, ExternalServicesWithoutConnectorId } from './types'; import { CONNECTOR_ID_REFERENCE_NAME, PUSH_CONNECTOR_ID_REFERENCE_NAME, @@ -25,7 +24,7 @@ import { STATUS_ESMODEL_TO_EXTERNAL, STATUS_EXTERNAL_TO_ESMODEL, } from '../../common/constants'; -import type { CaseAttributes, CaseFullExternalService } from '../../../common/api'; +import type { CaseFullExternalService } from '../../../common/api'; import { CaseSeverity, CaseStatuses, NONE_CONNECTOR_ID } from '../../../common/api'; import { findConnectorIdReference, @@ -34,11 +33,12 @@ import { transformESConnectorToExternalModel, } from '../transform'; import { ConnectorReferenceHandler } from '../connector_reference_handler'; -import type { CaseSavedObject } from '../../common/types'; +import type { CasePersistedAttributes, CaseTransformedAttributes } from '../../common/types/case'; +import type { ExternalServicePersisted } from '../../common/types/external_service'; export function transformUpdateResponsesToExternalModels( - response: SavedObjectsBulkUpdateResponse -): SavedObjectsBulkUpdateResponse { + response: SavedObjectsBulkUpdateResponse +): SavedObjectsBulkUpdateResponse { return { ...response, saved_objects: response.saved_objects.map((so) => ({ @@ -49,8 +49,8 @@ export function transformUpdateResponsesToExternalModels( } export function transformUpdateResponseToExternalModel( - updatedCase: SavedObjectsUpdateResponse -): SavedObjectsUpdateResponse { + updatedCase: SavedObjectsUpdateResponse +): SavedObjectsUpdateResponse { const { connector, external_service, @@ -64,7 +64,7 @@ export function transformUpdateResponseToExternalModel( ({ total_alerts: -1, total_comments: -1, - } as ESCaseAttributes); + } as CasePersistedAttributes); const transformedConnector = transformESConnectorToExternalModel({ // if the saved object had an error the attributes field will not exist @@ -94,16 +94,16 @@ export function transformUpdateResponseToExternalModel( }; } -export function transformAttributesToESModel(caseAttributes: CaseAttributes): { - attributes: ESCaseAttributes; +export function transformAttributesToESModel(caseAttributes: CaseTransformedAttributes): { + attributes: CasePersistedAttributes; referenceHandler: ConnectorReferenceHandler; }; -export function transformAttributesToESModel(caseAttributes: Partial): { - attributes: Partial; +export function transformAttributesToESModel(caseAttributes: Partial): { + attributes: Partial; referenceHandler: ConnectorReferenceHandler; }; -export function transformAttributesToESModel(caseAttributes: Partial): { - attributes: Partial; +export function transformAttributesToESModel(caseAttributes: Partial): { + attributes: Partial; referenceHandler: ConnectorReferenceHandler; } { const { connector, external_service, severity, status, ...restAttributes } = caseAttributes; @@ -154,15 +154,15 @@ function buildReferenceHandler( * definition like this: * * export function transformArrayResponseToExternalModel( - * response: SavedObjectsBulkResponse | SavedObjectsFindResponse - * ): SavedObjectsBulkResponse | SavedObjectsFindResponse { + * response: SavedObjectsBulkResponse | SavedObjectsFindResponse + * ): SavedObjectsBulkResponse | SavedObjectsFindResponse { * * See this issue for more details: https://stackoverflow.com/questions/49510832/typescript-how-to-map-over-union-array-type */ export function transformBulkResponseToExternalModel( - response: SavedObjectsBulkResponse -): SavedObjectsBulkResponse { + response: SavedObjectsBulkResponse +): SavedObjectsBulkResponse { return { ...response, saved_objects: response.saved_objects.map((so) => ({ @@ -173,8 +173,8 @@ export function transformBulkResponseToExternalModel( } export function transformFindResponseToExternalModel( - response: SavedObjectsFindResponse -): SavedObjectsFindResponse { + response: SavedObjectsFindResponse +): SavedObjectsFindResponse { return { ...response, saved_objects: response.saved_objects.map((so) => ({ @@ -185,8 +185,8 @@ export function transformFindResponseToExternalModel( } export function transformSavedObjectToExternalModel( - caseSavedObject: SavedObject -): CaseSavedObject { + caseSavedObject: SavedObject +): SavedObject { const connector = transformESConnectorOrUseDefault({ // if the saved object had an error the attributes field will not exist connector: caseSavedObject.attributes?.connector, @@ -209,7 +209,7 @@ export function transformSavedObjectToExternalModel( ({ total_alerts: -1, total_comments: -1, - } as ESCaseAttributes); + } as CasePersistedAttributes); return { ...caseSavedObject, @@ -226,7 +226,7 @@ export function transformSavedObjectToExternalModel( function transformESExternalService( // this type needs to match that of CaseFullExternalService except that it does not include the connector_id, see: x-pack/plugins/cases/common/api/cases/case.ts // that's why it can be null here - externalService: ExternalServicesWithoutConnectorId | null | undefined, + externalService: ExternalServicePersisted | null | undefined, references: SavedObjectReference[] | undefined ): CaseFullExternalService | null { const connectorIdRef = findConnectorIdReference(PUSH_CONNECTOR_ID_REFERENCE_NAME, references); diff --git a/x-pack/plugins/cases/server/services/cases/types.ts b/x-pack/plugins/cases/server/services/cases/types.ts index 5e831b7fd058f..3a57fa3eea83a 100644 --- a/x-pack/plugins/cases/server/services/cases/types.ts +++ b/x-pack/plugins/cases/server/services/cases/types.ts @@ -5,49 +5,88 @@ * 2.0. */ -import type * as rt from 'io-ts'; -import type { CaseAttributes, CaseExternalServiceBasicRt } from '../../../common/api'; -import type { ESCaseConnector } from '..'; - -/** - * This type should only be used within the cases service and its helper functions (e.g. the transforms). - * - * The type represents how the external services portion of the object will be layed out when stored in ES. The external_service will have its - * connector_id field removed and placed within the references field. - */ -export type ExternalServicesWithoutConnectorId = Omit< - rt.TypeOf, - 'connector_id' ->; - -export enum ESCaseSeverity { - LOW = 0, - MEDIUM = 10, - HIGH = 20, - CRITICAL = 30, -} - -export enum ESCaseStatus { - OPEN = 0, - IN_PROGRESS = 10, - CLOSED = 20, -} - -/** - * This type should only be used within the cases service and its helper functions (e.g. the transforms). - * - * The type represents how the Cases object will be layed out in ES. - * 1 - It will not have connector.id or external_service.connector_id. Instead those fields will be transformed into the references field. - * 2 - The Severity type is internally a number. - */ -export type ESCaseAttributes = Omit< - CaseAttributes, - 'connector' | 'external_service' | 'severity' | 'status' -> & { - severity: ESCaseSeverity; - status: ESCaseStatus; - connector: ESCaseConnector; - external_service: ExternalServicesWithoutConnectorId | null; - total_alerts: number; - total_comments: number; -}; +import type { KueryNode } from '@kbn/es-query'; +import type { SavedObjectsClientContract } from '@kbn/core/server'; +import type { Case } from '../../../common/api'; +import type { IndexRefresh } from '../types'; +import type { User } from '../../common/types/user'; +import type { + CaseSavedObjectTransformed, + CaseTransformedAttributes, +} from '../../common/types/case'; +import type { SavedObjectFindOptionsKueryNode } from '../../common/types'; + +export interface GetCaseIdsByAlertIdArgs { + alertId: string; + filter?: KueryNode; +} + +export interface PushedArgs { + pushed_at: string; + pushed_by: User; +} + +export interface GetCaseArgs { + id: string; +} + +export interface DeleteCaseArgs extends GetCaseArgs, IndexRefresh {} + +export interface GetCasesArgs { + caseIds: string[]; + fields?: string[]; +} + +export interface FindCommentsArgs { + id: string | string[]; + options?: SavedObjectFindOptionsKueryNode; +} + +export interface FindCaseCommentsArgs { + id: string | string[]; + options?: SavedObjectFindOptionsKueryNode; +} + +export interface PostCaseArgs extends IndexRefresh { + attributes: CaseTransformedAttributes; + id: string; +} + +export interface PatchCase extends IndexRefresh { + caseId: string; + updatedAttributes: Partial; + originalCase: CaseSavedObjectTransformed; + version?: string; +} + +export type PatchCaseArgs = PatchCase; + +export interface PatchCasesArgs extends IndexRefresh { + cases: Array>; +} + +export interface CasesMapWithPageInfo { + casesMap: Map; + page: number; + perPage: number; + total: number; +} + +export interface GetTagsArgs { + unsecuredSavedObjectsClient: SavedObjectsClientContract; + filter?: KueryNode; +} + +export interface GetReportersArgs { + unsecuredSavedObjectsClient: SavedObjectsClientContract; + filter?: KueryNode; +} + +export interface GetCaseIdsByAlertIdAggs { + references: { + doc_count: number; + caseIds: { + buckets: Array<{ key: string }>; + }; + }; +} diff --git a/x-pack/plugins/cases/server/services/configure/index.test.ts b/x-pack/plugins/cases/server/services/configure/index.test.ts index 6c65aaab70828..3fb25e2ff115e 100644 --- a/x-pack/plugins/cases/server/services/configure/index.test.ts +++ b/x-pack/plugins/cases/server/services/configure/index.test.ts @@ -24,11 +24,11 @@ import type { import { ACTION_SAVED_OBJECT_TYPE } from '@kbn/actions-plugin/server'; import { loggerMock } from '@kbn/logging-mocks'; import { CaseConfigureService } from '.'; -import type { ESCasesConfigureAttributes } from './types'; import { CONNECTOR_ID_REFERENCE_NAME } from '../../common/constants'; import { getNoneCaseConnector } from '../../common/utils'; import type { ESCaseConnectorWithId } from '../test_utils'; import { createESJiraConnector, createJiraConnector } from '../test_utils'; +import type { ConfigurePersistedAttributes } from '../../common/types/configure'; const basicConfigFields = { closure_type: 'close-by-pushing' as const, @@ -60,7 +60,7 @@ const createConfigPostParams = (connector: CaseConnector): CasesConfigureAttribu const createUpdateConfigSO = ( connector?: ESCaseConnectorWithId -): SavedObjectsUpdateResponse => { +): SavedObjectsUpdateResponse => { const references: SavedObjectReference[] = connector && connector.id !== 'none' ? [ @@ -87,7 +87,7 @@ const createUpdateConfigSO = ( const createConfigSO = ( connector?: ESCaseConnectorWithId -): SavedObject => { +): SavedObject => { const references: SavedObjectReference[] = connector ? [ { @@ -119,17 +119,17 @@ const createConfigSO = ( const createConfigSOPromise = ( connector?: ESCaseConnectorWithId -): Promise> => Promise.resolve(createConfigSO(connector)); +): Promise> => Promise.resolve(createConfigSO(connector)); const createConfigFindSO = ( connector?: ESCaseConnectorWithId -): SavedObjectsFindResult => ({ +): SavedObjectsFindResult => ({ ...createConfigSO(connector), score: 0, }); const createSOFindResponse = ( - savedObjects: Array> + savedObjects: Array> ) => ({ saved_objects: savedObjects, total: savedObjects.length, @@ -163,7 +163,7 @@ describe('CaseConfigureService', () => { }); const { connector: ignoreConnector, ...restUpdateAttributes } = unsecuredSavedObjectsClient - .update.mock.calls[0][2] as Partial; + .update.mock.calls[0][2] as Partial; expect(restUpdateAttributes).toMatchInlineSnapshot(` Object { @@ -198,7 +198,7 @@ describe('CaseConfigureService', () => { }); const { connector } = unsecuredSavedObjectsClient.update.mock - .calls[0][2] as Partial; + .calls[0][2] as Partial; expect(connector?.fields).toMatchInlineSnapshot(` Array [ @@ -231,7 +231,7 @@ describe('CaseConfigureService', () => { }); const { connector } = unsecuredSavedObjectsClient.update.mock - .calls[0][2] as Partial; + .calls[0][2] as Partial; expect(connector).toMatchInlineSnapshot(` Object { @@ -269,7 +269,7 @@ describe('CaseConfigureService', () => { }); const updateAttributes = unsecuredSavedObjectsClient.update.mock - .calls[0][2] as Partial; + .calls[0][2] as Partial; expect(updateAttributes.connector).not.toHaveProperty('id'); @@ -400,7 +400,7 @@ describe('CaseConfigureService', () => { describe('post', () => { it('includes the creation attributes excluding the connector.id field', async () => { unsecuredSavedObjectsClient.create.mockReturnValue( - Promise.resolve({} as SavedObject) + Promise.resolve({} as SavedObject) ); await service.post({ @@ -410,7 +410,7 @@ describe('CaseConfigureService', () => { }); const creationAttributes = unsecuredSavedObjectsClient.create.mock - .calls[0][1] as ESCasesConfigureAttributes; + .calls[0][1] as ConfigurePersistedAttributes; expect(creationAttributes.connector).not.toHaveProperty('id'); expect(creationAttributes).toMatchInlineSnapshot(` Object { @@ -452,7 +452,7 @@ describe('CaseConfigureService', () => { it('moves the connector.id to the references', async () => { unsecuredSavedObjectsClient.create.mockReturnValue( - Promise.resolve({} as SavedObject) + Promise.resolve({} as SavedObject) ); await service.post({ @@ -478,7 +478,7 @@ describe('CaseConfigureService', () => { it('sets connector.fields to an empty array when it is not included', async () => { unsecuredSavedObjectsClient.create.mockReturnValue( - Promise.resolve({} as SavedObject) + Promise.resolve({} as SavedObject) ); await service.post({ @@ -500,7 +500,7 @@ describe('CaseConfigureService', () => { it('does not create a reference for a none connector', async () => { unsecuredSavedObjectsClient.create.mockReturnValue( - Promise.resolve({} as SavedObject) + Promise.resolve({} as SavedObject) ); await service.post({ @@ -545,7 +545,7 @@ describe('CaseConfigureService', () => { it('returns an undefined connector if it is not returned by the update', async () => { unsecuredSavedObjectsClient.update.mockReturnValue( - Promise.resolve({} as SavedObjectsUpdateResponse) + Promise.resolve({} as SavedObjectsUpdateResponse) ); const res = await service.patch({ @@ -564,7 +564,7 @@ describe('CaseConfigureService', () => { it('returns the default none connector when it cannot find the reference', async () => { const { name, type, fields } = createESJiraConnector(); - const returnValue: SavedObjectsUpdateResponse = { + const returnValue: SavedObjectsUpdateResponse = { type: CASE_CONFIGURE_SAVED_OBJECT, id: '1', attributes: { @@ -707,7 +707,7 @@ describe('CaseConfigureService', () => { type: ACTION_SAVED_OBJECT_TYPE, }, ], - } as unknown as SavedObject) + } as unknown as SavedObject) ); const res = await service.get({ unsecuredSavedObjectsClient, configurationId: '1' }); diff --git a/x-pack/plugins/cases/server/services/configure/index.ts b/x-pack/plugins/cases/server/services/configure/index.ts index 8a63f1fcfce2f..d424c96f006dc 100644 --- a/x-pack/plugins/cases/server/services/configure/index.ts +++ b/x-pack/plugins/cases/server/services/configure/index.ts @@ -8,13 +8,11 @@ import type { Logger, SavedObject, - SavedObjectsClientContract, SavedObjectsFindResponse, SavedObjectsUpdateResponse, } from '@kbn/core/server'; import { ACTION_SAVED_OBJECT_TYPE } from '@kbn/actions-plugin/server'; -import type { SavedObjectFindOptionsKueryNode } from '../../common/types'; import { CONNECTOR_ID_REFERENCE_NAME } from '../../common/constants'; import type { CasesConfigureAttributes, CasesConfigurePatch } from '../../../common/api'; import { CASE_CONFIGURE_SAVED_OBJECT } from '../../../common/constants'; @@ -24,33 +22,14 @@ import { transformESConnectorOrUseDefault, } from '../transform'; import { ConnectorReferenceHandler } from '../connector_reference_handler'; -import type { ESCasesConfigureAttributes } from './types'; -import type { IndexRefresh } from '../types'; - -interface ClientArgs { - unsecuredSavedObjectsClient: SavedObjectsClientContract; -} - -interface GetCaseConfigureArgs extends ClientArgs { - configurationId: string; -} - -interface DeleteCaseConfigureArgs extends GetCaseConfigureArgs, IndexRefresh {} - -interface FindCaseConfigureArgs extends ClientArgs { - options?: SavedObjectFindOptionsKueryNode; -} - -interface PostCaseConfigureArgs extends ClientArgs, IndexRefresh { - attributes: CasesConfigureAttributes; - id: string; -} - -interface PatchCaseConfigureArgs extends ClientArgs, IndexRefresh { - configurationId: string; - updatedAttributes: Partial; - originalConfiguration: SavedObject; -} +import type { + DeleteCaseConfigureArgs, + FindCaseConfigureArgs, + GetCaseConfigureArgs, + PatchCaseConfigureArgs, + PostCaseConfigureArgs, +} from './types'; +import type { ConfigurePersistedAttributes } from '../../common/types/configure'; export class CaseConfigureService { constructor(private readonly log: Logger) {} @@ -79,7 +58,7 @@ export class CaseConfigureService { }: GetCaseConfigureArgs): Promise> { try { this.log.debug(`Attempting to GET case configuration ${configurationId}`); - const configuration = await unsecuredSavedObjectsClient.get( + const configuration = await unsecuredSavedObjectsClient.get( CASE_CONFIGURE_SAVED_OBJECT, configurationId ); @@ -98,7 +77,7 @@ export class CaseConfigureService { try { this.log.debug(`Attempting to find all case configuration`); - const findResp = await unsecuredSavedObjectsClient.find({ + const findResp = await unsecuredSavedObjectsClient.find({ ...options, // Get the latest configuration sortField: 'created_at', @@ -122,7 +101,7 @@ export class CaseConfigureService { try { this.log.debug(`Attempting to POST a new case configuration`); const esConfigInfo = transformAttributesToESModel(attributes); - const createdConfig = await unsecuredSavedObjectsClient.create( + const createdConfig = await unsecuredSavedObjectsClient.create( CASE_CONFIGURE_SAVED_OBJECT, esConfigInfo.attributes, { id, references: esConfigInfo.referenceHandler.build(), refresh } @@ -147,7 +126,7 @@ export class CaseConfigureService { const esUpdateInfo = transformAttributesToESModel(updatedAttributes); const updatedConfiguration = - await unsecuredSavedObjectsClient.update( + await unsecuredSavedObjectsClient.update( CASE_CONFIGURE_SAVED_OBJECT, configurationId, { @@ -168,7 +147,7 @@ export class CaseConfigureService { } function transformUpdateResponseToExternalModel( - updatedConfiguration: SavedObjectsUpdateResponse + updatedConfiguration: SavedObjectsUpdateResponse ): SavedObjectsUpdateResponse { const { connector, ...restUpdatedAttributes } = updatedConfiguration.attributes ?? {}; @@ -178,10 +157,12 @@ function transformUpdateResponseToExternalModel( referenceName: CONNECTOR_ID_REFERENCE_NAME, }); + const castedAttributesWithoutConnector = restUpdatedAttributes as CasesConfigurePatch; + return { ...updatedConfiguration, attributes: { - ...restUpdatedAttributes, + ...castedAttributesWithoutConnector, // this will avoid setting connector to undefined, it won't include to field at all ...(transformedConnector && { connector: transformedConnector }), }, @@ -189,7 +170,7 @@ function transformUpdateResponseToExternalModel( } function transformToExternalModel( - configuration: SavedObject + configuration: SavedObject ): SavedObject { const connector = transformESConnectorOrUseDefault({ // if the saved object had an error the attributes field will not exist @@ -198,17 +179,19 @@ function transformToExternalModel( referenceName: CONNECTOR_ID_REFERENCE_NAME, }); + const castedAttributes = configuration.attributes as CasesConfigureAttributes; + return { ...configuration, attributes: { - ...configuration.attributes, + ...castedAttributes, connector, }, }; } function transformFindResponseToExternalModel( - configurations: SavedObjectsFindResponse + configurations: SavedObjectsFindResponse ): SavedObjectsFindResponse { return { ...configurations, @@ -220,15 +203,15 @@ function transformFindResponseToExternalModel( } function transformAttributesToESModel(configuration: CasesConfigureAttributes): { - attributes: ESCasesConfigureAttributes; + attributes: ConfigurePersistedAttributes; referenceHandler: ConnectorReferenceHandler; }; function transformAttributesToESModel(configuration: Partial): { - attributes: Partial; + attributes: Partial; referenceHandler: ConnectorReferenceHandler; }; function transformAttributesToESModel(configuration: Partial): { - attributes: Partial; + attributes: Partial; referenceHandler: ConnectorReferenceHandler; } { const { connector, ...restWithoutConnector } = configuration; diff --git a/x-pack/plugins/cases/server/services/configure/types.ts b/x-pack/plugins/cases/server/services/configure/types.ts index 4e6ecc03955ae..2d47e32387a5c 100644 --- a/x-pack/plugins/cases/server/services/configure/types.ts +++ b/x-pack/plugins/cases/server/services/configure/types.ts @@ -5,13 +5,32 @@ * 2.0. */ +import type { SavedObject, SavedObjectsClientContract } from '@kbn/core/server'; import type { CasesConfigureAttributes } from '../../../common/api'; -import type { ESCaseConnector } from '..'; +import type { IndexRefresh } from '../types'; +import type { SavedObjectFindOptionsKueryNode } from '../../common/types'; -/** - * This type should only be used within the configure service. It represents how the configure saved object will be layed - * out in ES. - */ -export type ESCasesConfigureAttributes = Omit & { - connector: ESCaseConnector; -}; +export interface ClientArgs { + unsecuredSavedObjectsClient: SavedObjectsClientContract; +} + +export interface GetCaseConfigureArgs extends ClientArgs { + configurationId: string; +} + +export interface DeleteCaseConfigureArgs extends GetCaseConfigureArgs, IndexRefresh {} + +export interface FindCaseConfigureArgs extends ClientArgs { + options?: SavedObjectFindOptionsKueryNode; +} + +export interface PostCaseConfigureArgs extends ClientArgs, IndexRefresh { + attributes: CasesConfigureAttributes; + id: string; +} + +export interface PatchCaseConfigureArgs extends ClientArgs, IndexRefresh { + configurationId: string; + updatedAttributes: Partial; + originalConfiguration: SavedObject; +} diff --git a/x-pack/plugins/cases/server/services/connector_mappings/index.ts b/x-pack/plugins/cases/server/services/connector_mappings/index.ts index 3f0c2d64260a7..f5301337770d6 100644 --- a/x-pack/plugins/cases/server/services/connector_mappings/index.ts +++ b/x-pack/plugins/cases/server/services/connector_mappings/index.ts @@ -5,41 +5,38 @@ * 2.0. */ -import type { Logger, SavedObjectReference, SavedObjectsClientContract } from '@kbn/core/server'; +import type { + Logger, + SavedObject, + SavedObjectsFindResponse, + SavedObjectsUpdateResponse, +} from '@kbn/core/server'; import { CASE_CONNECTOR_MAPPINGS_SAVED_OBJECT } from '../../../common/constants'; +import type { + FindConnectorMappingsArgs, + PostConnectorMappingsArgs, + UpdateConnectorMappingsArgs, +} from './types'; +import type { ConnectorMappingsPersistedAttributes } from '../../common/types/connector_mappings'; import type { ConnectorMappings } from '../../../common/api'; -import type { SavedObjectFindOptionsKueryNode } from '../../common/types'; -import type { IndexRefresh } from '../types'; - -interface ClientArgs { - unsecuredSavedObjectsClient: SavedObjectsClientContract; -} -interface FindConnectorMappingsArgs extends ClientArgs { - options?: SavedObjectFindOptionsKueryNode; -} - -interface PostConnectorMappingsArgs extends ClientArgs, IndexRefresh { - attributes: ConnectorMappings; - references: SavedObjectReference[]; -} - -interface UpdateConnectorMappingsArgs extends ClientArgs, IndexRefresh { - mappingId: string; - attributes: Partial; - references: SavedObjectReference[]; -} export class ConnectorMappingsService { constructor(private readonly log: Logger) {} - public async find({ unsecuredSavedObjectsClient, options }: FindConnectorMappingsArgs) { + public async find({ + unsecuredSavedObjectsClient, + options, + }: FindConnectorMappingsArgs): Promise> { try { this.log.debug(`Attempting to find all connector mappings`); - return await unsecuredSavedObjectsClient.find({ - ...options, - type: CASE_CONNECTOR_MAPPINGS_SAVED_OBJECT, - }); + const connectorMappings = + await unsecuredSavedObjectsClient.find({ + ...options, + type: CASE_CONNECTOR_MAPPINGS_SAVED_OBJECT, + }); + + return connectorMappings as SavedObjectsFindResponse; } catch (error) { this.log.error(`Attempting to find all connector mappings: ${error}`); throw error; @@ -51,17 +48,20 @@ export class ConnectorMappingsService { attributes, references, refresh, - }: PostConnectorMappingsArgs) { + }: PostConnectorMappingsArgs): Promise> { try { this.log.debug(`Attempting to POST a new connector mappings`); - return await unsecuredSavedObjectsClient.create( - CASE_CONNECTOR_MAPPINGS_SAVED_OBJECT, - attributes, - { - references, - refresh, - } - ); + const connectorMappings = + await unsecuredSavedObjectsClient.create( + CASE_CONNECTOR_MAPPINGS_SAVED_OBJECT, + attributes, + { + references, + refresh, + } + ); + + return connectorMappings as SavedObject; } catch (error) { this.log.error(`Error on POST a new connector mappings: ${error}`); throw error; @@ -74,18 +74,21 @@ export class ConnectorMappingsService { attributes, references, refresh, - }: UpdateConnectorMappingsArgs) { + }: UpdateConnectorMappingsArgs): Promise> { try { this.log.debug(`Attempting to UPDATE connector mappings ${mappingId}`); - return await unsecuredSavedObjectsClient.update( - CASE_CONNECTOR_MAPPINGS_SAVED_OBJECT, - mappingId, - attributes, - { - references, - refresh, - } - ); + const updatedMappings = + await unsecuredSavedObjectsClient.update( + CASE_CONNECTOR_MAPPINGS_SAVED_OBJECT, + mappingId, + attributes, + { + references, + refresh, + } + ); + + return updatedMappings as SavedObjectsUpdateResponse; } catch (error) { this.log.error(`Error on UPDATE connector mappings ${mappingId}: ${error}`); throw error; diff --git a/x-pack/plugins/cases/server/services/connector_mappings/types.ts b/x-pack/plugins/cases/server/services/connector_mappings/types.ts new file mode 100644 index 0000000000000..a82663dbdfdac --- /dev/null +++ b/x-pack/plugins/cases/server/services/connector_mappings/types.ts @@ -0,0 +1,30 @@ +/* + * 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 { SavedObjectReference, SavedObjectsClientContract } from '@kbn/core/server'; + +import type { ConnectorMappings } from '../../../common/api'; +import type { SavedObjectFindOptionsKueryNode } from '../../common/types'; +import type { IndexRefresh } from '../types'; + +export interface ClientArgs { + unsecuredSavedObjectsClient: SavedObjectsClientContract; +} +export interface FindConnectorMappingsArgs extends ClientArgs { + options?: SavedObjectFindOptionsKueryNode; +} + +export interface PostConnectorMappingsArgs extends ClientArgs, IndexRefresh { + attributes: ConnectorMappings; + references: SavedObjectReference[]; +} + +export interface UpdateConnectorMappingsArgs extends ClientArgs, IndexRefresh { + mappingId: string; + attributes: Partial; + references: SavedObjectReference[]; +} diff --git a/x-pack/plugins/cases/server/services/index.ts b/x-pack/plugins/cases/server/services/index.ts index e15584b6ced9e..f1bfc940a36f1 100644 --- a/x-pack/plugins/cases/server/services/index.ts +++ b/x-pack/plugins/cases/server/services/index.ts @@ -6,7 +6,6 @@ */ import type { SavedObjectsClientContract } from '@kbn/core/server'; -import type { ConnectorTypes } from '../../common/api'; export { CasesService } from './cases'; export { CaseConfigureService } from './configure'; @@ -19,14 +18,3 @@ export { UserProfileService } from './user_profiles'; export interface ClientArgs { unsecuredSavedObjectsClient: SavedObjectsClientContract; } - -export type ESConnectorFields = Array<{ - key: string; - value: unknown; -}>; - -export interface ESCaseConnector { - name: string; - type: ConnectorTypes; - fields: ESConnectorFields | null; -} diff --git a/x-pack/plugins/cases/server/services/notifications/email_notification_service.ts b/x-pack/plugins/cases/server/services/notifications/email_notification_service.ts index 2800a248b1394..8c8fd98e1a848 100644 --- a/x-pack/plugins/cases/server/services/notifications/email_notification_service.ts +++ b/x-pack/plugins/cases/server/services/notifications/email_notification_service.ts @@ -11,7 +11,7 @@ import type { NotificationsPluginStart } from '@kbn/notifications-plugin/server' import type { SecurityPluginStart } from '@kbn/security-plugin/server'; import type { UserProfileUserInfo } from '@kbn/user-profile-components'; import { CASE_SAVED_OBJECT, MAX_CONCURRENT_SEARCHES } from '../../../common/constants'; -import type { CaseSavedObject } from '../../common/types'; +import type { CaseSavedObjectTransformed } from '../../common/types/case'; import { getCaseViewPath } from '../../common/utils'; import type { NotificationService, NotifyArgs } from './types'; @@ -46,12 +46,12 @@ export class EmailNotificationService implements NotificationService { this.publicBaseUrl = publicBaseUrl; } - private static getTitle(theCase: CaseSavedObject) { + private static getTitle(theCase: CaseSavedObjectTransformed) { return `[Elastic][Cases] ${theCase.attributes.title}`; } private static getMessage( - theCase: CaseSavedObject, + theCase: CaseSavedObjectTransformed, spaceId: string, publicBaseUrl?: IBasePath['publicBaseUrl'] ) { diff --git a/x-pack/plugins/cases/server/services/notifications/types.ts b/x-pack/plugins/cases/server/services/notifications/types.ts index 0efc326cf7835..48909c00a77d7 100644 --- a/x-pack/plugins/cases/server/services/notifications/types.ts +++ b/x-pack/plugins/cases/server/services/notifications/types.ts @@ -6,11 +6,11 @@ */ import type { CaseAssignees } from '../../../common/api'; -import type { CaseSavedObject } from '../../common/types'; +import type { CaseSavedObjectTransformed } from '../../common/types/case'; export interface NotifyArgs { assignees: CaseAssignees; - theCase: CaseSavedObject; + theCase: CaseSavedObjectTransformed; } export interface NotificationService { diff --git a/x-pack/plugins/cases/server/services/so_references.ts b/x-pack/plugins/cases/server/services/so_references.ts index f85c4cab1829d..8a3cc747c752a 100644 --- a/x-pack/plugins/cases/server/services/so_references.ts +++ b/x-pack/plugins/cases/server/services/so_references.ts @@ -5,15 +5,16 @@ * 2.0. */ -import type { SavedObjectsUpdateResponse } from '@kbn/core/server'; -import type { SavedObject, SavedObjectReference } from '@kbn/core/types'; +import type { + SavedObjectsUpdateResponse, + SavedObject, + SavedObjectReference, +} from '@kbn/core/server'; import { isEqual, uniqWith } from 'lodash'; import type { CommentAttributesNoSO, - CommentRequest, CommentAttributes, CommentPatchAttributes, - CommentAttributesWithoutRefs, } from '../../common/api'; import type { PersistableStateAttachmentTypeRegistry } from '../attachment_framework/persistable_state_registry'; import { @@ -21,11 +22,17 @@ import { extractPersistableStateReferencesFromSO, } from '../attachment_framework/so_references'; import { EXTERNAL_REFERENCE_REF_NAME } from '../common/constants'; -import { isCommentRequestTypeExternalReferenceSO } from '../common/utils'; +import type { + AttachmentPersistedAttributes, + AttachmentRequestAttributes, +} from '../common/types/attachments'; +import { isCommentRequestTypeExternalReferenceSO } from './type_guards'; import type { PartialField } from '../types'; import { SOReferenceExtractor } from './so_reference_extractor'; -export const getAttachmentSOExtractor = (attachment: Partial) => { +export const getAttachmentSOExtractor = ( + attachment: Partial +): SOReferenceExtractor => { const fieldsToExtract = []; if (isCommentRequestTypeExternalReferenceSO(attachment)) { @@ -47,7 +54,7 @@ type OptionalAttributes = PartialField, 'attributes'>; * then the error field will be set and attributes will be undefined. */ export const injectAttachmentAttributesAndHandleErrors = ( - savedObject: OptionalAttributes, + savedObject: OptionalAttributes, persistableStateAttachmentTypeRegistry: PersistableStateAttachmentTypeRegistry ): OptionalAttributes => { if (!hasAttributes(savedObject)) { @@ -64,9 +71,9 @@ const hasAttributes = (savedObject: OptionalAttributes): savedObject is Sa }; export const injectAttachmentSOAttributesFromRefs = ( - savedObject: SavedObject, + savedObject: SavedObject, persistableStateAttachmentTypeRegistry: PersistableStateAttachmentTypeRegistry -) => { +): SavedObject => { const soExtractor = getAttachmentSOExtractor(savedObject.attributes); const so = soExtractor.populateFieldsFromReferences(savedObject); const injectedAttributes = injectPersistableReferencesToSO(so.attributes, so.references, { @@ -78,9 +85,9 @@ export const injectAttachmentSOAttributesFromRefs = ( export const injectAttachmentSOAttributesFromRefsForPatch = ( updatedAttributes: CommentPatchAttributes, - savedObject: SavedObjectsUpdateResponse, + savedObject: SavedObjectsUpdateResponse, persistableStateAttachmentTypeRegistry: PersistableStateAttachmentTypeRegistry -) => { +): SavedObjectsUpdateResponse => { const soExtractor = getAttachmentSOExtractor(savedObject.attributes); const so = soExtractor.populateFieldsFromReferencesForPatch({ dataBeforeRequest: updatedAttributes, @@ -101,11 +108,17 @@ export const injectAttachmentSOAttributesFromRefsForPatch = ( } as SavedObjectsUpdateResponse; }; +interface ExtractionResults { + attributes: AttachmentPersistedAttributes; + references: SavedObjectReference[]; + didDeleteOperation: boolean; +} + export const extractAttachmentSORefsFromAttributes = ( attributes: CommentAttributes | CommentPatchAttributes, references: SavedObjectReference[], persistableStateAttachmentTypeRegistry: PersistableStateAttachmentTypeRegistry -) => { +): ExtractionResults => { const soExtractor = getAttachmentSOExtractor(attributes); const { @@ -129,5 +142,5 @@ export const extractAttachmentSORefsFromAttributes = ( }; }; -export const getUniqueReferences = (references: SavedObjectReference[]) => +export const getUniqueReferences = (references: SavedObjectReference[]): SavedObjectReference[] => uniqWith(references, isEqual); diff --git a/x-pack/plugins/cases/server/services/test_utils.ts b/x-pack/plugins/cases/server/services/test_utils.ts index d0108564d476a..f0cfdbe6b1866 100644 --- a/x-pack/plugins/cases/server/services/test_utils.ts +++ b/x-pack/plugins/cases/server/services/test_utils.ts @@ -7,7 +7,6 @@ import type { SavedObject, SavedObjectReference, SavedObjectsFindResult } from '@kbn/core/server'; import { ACTION_SAVED_OBJECT_TYPE } from '@kbn/actions-plugin/server'; -import type { ESConnectorFields } from '.'; import { CONNECTOR_ID_REFERENCE_NAME, PUSH_CONNECTOR_ID_REFERENCE_NAME } from '../common/constants'; import type { CaseAttributes, @@ -17,9 +16,11 @@ import type { } from '../../common/api'; import { CaseSeverity, CaseStatuses, ConnectorTypes, NONE_CONNECTOR_ID } from '../../common/api'; import { CASE_SAVED_OBJECT, SECURITY_SOLUTION_OWNER } from '../../common/constants'; -import type { ESCaseAttributes, ExternalServicesWithoutConnectorId } from './cases/types'; -import { ESCaseSeverity, ESCaseStatus } from './cases/types'; import { getNoneCaseConnector } from '../common/utils'; +import type { ConnectorPersistedFields } from '../common/types/connectors'; +import type { CasePersistedAttributes } from '../common/types/case'; +import { CasePersistedSeverity, CasePersistedStatus } from '../common/types/case'; +import type { ExternalServicePersisted } from '../common/types/external_service'; /** * This is only a utility interface to help with constructing test cases. After the migration, the ES format will no longer @@ -29,7 +30,7 @@ export interface ESCaseConnectorWithId { id: string; name: string; type: ConnectorTypes; - fields: ESConnectorFields | null; + fields: ConnectorPersistedFields | null; } /** @@ -97,7 +98,7 @@ export const createExternalService = ( ...overrides, }); -export const basicESCaseFields: ESCaseAttributes = { +export const basicESCaseFields: CasePersistedAttributes = { closed_at: null, closed_by: null, created_at: '2019-11-25T21:54:48.952Z', @@ -106,11 +107,11 @@ export const basicESCaseFields: ESCaseAttributes = { email: 'testemail@elastic.co', username: 'elastic', }, - severity: ESCaseSeverity.LOW, + severity: CasePersistedSeverity.LOW, duration: null, description: 'This is a brand new case of a bad meanie defacing data', title: 'Super Bad Security Issue', - status: ESCaseStatus.OPEN, + status: CasePersistedStatus.OPEN, tags: ['defacement'], updated_at: '2019-11-25T21:54:48.952Z', updated_by: { @@ -167,9 +168,9 @@ export const createCaseSavedObjectResponse = ({ }: { connector?: ESCaseConnectorWithId; externalService?: CaseFullExternalService; - overrides?: Partial; + overrides?: Partial; caseId?: string; -} = {}): SavedObject => { +} = {}): SavedObject => { const references: SavedObjectReference[] = createSavedObjectReferences({ connector, externalService, @@ -181,7 +182,7 @@ export const createCaseSavedObjectResponse = ({ fields: connector?.fields ?? null, }; - let restExternalService: ExternalServicesWithoutConnectorId | null = null; + let restExternalService: ExternalServicePersisted | null = null; if (externalService !== null) { const { connector_id: ignored, ...rest } = externalService ?? { connector_name: '.jira', diff --git a/x-pack/plugins/cases/server/services/transform.ts b/x-pack/plugins/cases/server/services/transform.ts index 50d5192610d4f..1229ec1fd6c62 100644 --- a/x-pack/plugins/cases/server/services/transform.ts +++ b/x-pack/plugins/cases/server/services/transform.ts @@ -9,7 +9,7 @@ import type { SavedObjectReference } from '@kbn/core/server'; import { ACTION_SAVED_OBJECT_TYPE } from '@kbn/actions-plugin/server'; import type { CaseConnector, ConnectorTypeFields } from '../../common/api'; import { getNoneCaseConnector } from '../common/utils'; -import type { ESCaseConnector, ESConnectorFields } from '.'; +import type { ConnectorPersistedFields, ConnectorPersisted } from '../common/types/connectors'; export function findConnectorIdReference( name: string, @@ -23,7 +23,7 @@ export function transformESConnectorToExternalModel({ references, referenceName, }: { - connector?: ESCaseConnector; + connector?: ConnectorPersisted; references?: SavedObjectReference[]; referenceName: string; }): CaseConnector | undefined { @@ -32,7 +32,7 @@ export function transformESConnectorToExternalModel({ } function transformConnectorFieldsToExternalModel( - connector?: ESCaseConnector, + connector?: ConnectorPersisted, connectorId?: string ): CaseConnector | undefined { if (!connector) { @@ -72,7 +72,7 @@ export function transformESConnectorOrUseDefault({ references, referenceName, }: { - connector?: ESCaseConnector; + connector?: ConnectorPersisted; references?: SavedObjectReference[]; referenceName: string; }): CaseConnector { @@ -82,12 +82,12 @@ export function transformESConnectorOrUseDefault({ ); } -export function transformFieldsToESModel(connector: CaseConnector): ESConnectorFields { +export function transformFieldsToESModel(connector: CaseConnector): ConnectorPersistedFields { if (!connector.fields) { return []; } - return Object.entries(connector.fields).reduce( + return Object.entries(connector.fields).reduce( (acc, [key, value]) => [ ...acc, { diff --git a/x-pack/plugins/cases/server/services/type_guards.ts b/x-pack/plugins/cases/server/services/type_guards.ts new file mode 100644 index 0000000000000..ec4c100b17585 --- /dev/null +++ b/x-pack/plugins/cases/server/services/type_guards.ts @@ -0,0 +1,22 @@ +/* + * 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 { CommentRequestExternalReferenceSOType } from '../../common/api'; +import { CommentType, ExternalReferenceStorageType } from '../../common/api'; +import type { AttachmentRequestAttributes } from '../common/types/attachments'; + +/** + * A type narrowing function for external reference saved object attachments. + */ +export const isCommentRequestTypeExternalReferenceSO = ( + context: Partial +): context is CommentRequestExternalReferenceSOType => { + return ( + context.type === CommentType.externalReference && + context.externalReferenceStorage?.type === ExternalReferenceStorageType.savedObject + ); +}; 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 252e3985a7483..167f0e123fb07 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 ff58f9e6a52fa..25096baddf479 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 { UserActionPersistedAttributes } from '../../../common/types/user_actions'; import { CASE_SAVED_OBJECT, CASE_USER_ACTION_SAVED_OBJECT } from '../../../../common/constants'; -import type { CaseSavedObject } from '../../../common/types'; 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: CaseSavedObject[]; - 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 b04cb76f3022c..5ce99d41a5ed2 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 439e57eed386d..10a6104e15807 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'; @@ -30,13 +29,14 @@ import { PUSH_CONNECTOR_ID_REFERENCE_NAME, } from '../../common/constants'; import { findConnectorIdReference } from '../transform'; -import { isCommentRequestTypeExternalReferenceSO } from '../../common/utils'; +import { isCommentRequestTypeExternalReferenceSO } from '../type_guards'; 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 4d9813c42591d..f88bd2ba3fe15 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[]; +} diff --git a/x-pack/plugins/cases/server/telemetry/queries/cases.test.ts b/x-pack/plugins/cases/server/telemetry/queries/cases.test.ts index b97235ff82247..560997e8802be 100644 --- a/x-pack/plugins/cases/server/telemetry/queries/cases.test.ts +++ b/x-pack/plugins/cases/server/telemetry/queries/cases.test.ts @@ -7,7 +7,7 @@ import type { SavedObjectsFindResponse } from '@kbn/core/server'; import { savedObjectsRepositoryMock, loggingSystemMock } from '@kbn/core/server/mocks'; -import { ESCaseStatus } from '../../services/cases/types'; +import { CasePersistedStatus } from '../../common/types/case'; import type { AttachmentAggregationResult, AttachmentFrameworkAggsResult, @@ -99,7 +99,7 @@ describe('getCasesTelemetryData', () => { status: { buckets: [ { - key: ESCaseStatus.OPEN, + key: CasePersistedStatus.OPEN, doc_count: 2, }, ], diff --git a/x-pack/plugins/cases/server/telemetry/queries/cases.ts b/x-pack/plugins/cases/server/telemetry/queries/cases.ts index 59576fa1f45c0..abd1979d752e8 100644 --- a/x-pack/plugins/cases/server/telemetry/queries/cases.ts +++ b/x-pack/plugins/cases/server/telemetry/queries/cases.ts @@ -14,8 +14,6 @@ import { CASE_USER_ACTION_SAVED_OBJECT, OWNERS, } from '../../../common/constants'; -import { ESCaseStatus } from '../../services/cases/types'; -import type { ESCaseAttributes } from '../../services/cases/types'; import type { CollectTelemetryDataParams, CasesTelemetry, @@ -37,12 +35,14 @@ import { getReferencesAggregationQuery, getSolutionValues, } from './utils'; +import type { CasePersistedAttributes } from '../../common/types/case'; +import { CasePersistedStatus } from '../../common/types/case'; export const getLatestCasesDates = async ({ savedObjectsClient, }: CollectTelemetryDataParams): Promise => { const find = async (sortField: string) => - savedObjectsClient.find({ + savedObjectsClient.find({ page: 1, perPage: 1, sortField, @@ -94,9 +94,12 @@ export const getCasesTelemetryData = async ({ total: casesRes.total, ...getCountsFromBuckets(aggregationsBuckets.counts), status: { - open: findValueInBuckets(aggregationsBuckets.status, ESCaseStatus.OPEN), - inProgress: findValueInBuckets(aggregationsBuckets.status, ESCaseStatus.IN_PROGRESS), - closed: findValueInBuckets(aggregationsBuckets.status, ESCaseStatus.CLOSED), + open: findValueInBuckets(aggregationsBuckets.status, CasePersistedStatus.OPEN), + inProgress: findValueInBuckets( + aggregationsBuckets.status, + CasePersistedStatus.IN_PROGRESS + ), + closed: findValueInBuckets(aggregationsBuckets.status, CasePersistedStatus.CLOSED), }, syncAlertsOn: findValueInBuckets(aggregationsBuckets.syncAlerts, 1), syncAlertsOff: findValueInBuckets(aggregationsBuckets.syncAlerts, 0), diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/hooks/use_add_to_case.ts b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/hooks/use_add_to_case.ts index 67f79242a9376..bdd2e228d93f3 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/hooks/use_add_to_case.ts +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/hooks/use_add_to_case.ts @@ -8,7 +8,7 @@ import { useCallback, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { HttpSetup, MountPoint } from '@kbn/core/public'; -import { Case } from '@kbn/cases-plugin/common'; +import { CaseUI } from '@kbn/cases-plugin/common'; import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; import { CasesDeepLinkId, DRAFT_COMMENT_STORAGE_ID } from '@kbn/cases-plugin/public'; import { observabilityFeatureId } from '@kbn/observability-shared-plugin/public'; @@ -17,7 +17,7 @@ import { AddToCaseProps } from '../header/add_to_case_action'; async function addToCase( http: HttpSetup, - theCase: Case, + theCase: CaseUI, attributes: TypedLensByValueInput['attributes'], timeRange?: { from: string; to: string }, owner?: string @@ -46,7 +46,7 @@ export const useAddToCase = ({ owner = observabilityFeatureId, }: AddToCaseProps & { appId?: 'securitySolutionUI' | 'observability'; - getToastText: (thaCase: Case) => MountPoint; + getToastText: (thaCase: CaseUI) => MountPoint; }) => { const [isSaving, setIsSaving] = useState(false); const [isCasesOpen, setIsCasesOpen] = useState(false); @@ -59,7 +59,7 @@ export const useAddToCase = ({ } = useKibana().services; const onCaseClicked = useCallback( - (theCase?: Case) => { + (theCase?: CaseUI) => { if (theCase && lensAttributes) { setIsCasesOpen(false); setIsSaving(true); diff --git a/x-pack/plugins/osquery/cypress/tasks/api_fixtures.ts b/x-pack/plugins/osquery/cypress/tasks/api_fixtures.ts index ce3be460ed22f..2a19019ea3ffb 100644 --- a/x-pack/plugins/osquery/cypress/tasks/api_fixtures.ts +++ b/x-pack/plugins/osquery/cypress/tasks/api_fixtures.ts @@ -10,7 +10,7 @@ import type { RuleResponse, } from '@kbn/security-solution-plugin/common/detection_engine/rule_schema'; import type { AgentPolicy } from '@kbn/fleet-plugin/common'; -import type { CaseResponse } from '@kbn/cases-plugin/common'; +import type { Case } from '@kbn/cases-plugin/common'; import type { SavedQuerySOFormData } from '../../public/saved_queries/form/use_saved_query_form'; import type { LiveQueryDetailsItem } from '../../public/actions/use_live_query_details'; import type { PackSavedObject, PackItem } from '../../public/packs/types'; @@ -181,7 +181,7 @@ export const cleanupRule = (id: string) => { }; export const loadCase = (owner: string) => - request({ + request({ method: 'POST', url: '/api/cases', body: { diff --git a/x-pack/plugins/security_solution/common/endpoint/data_loaders/index_case.ts b/x-pack/plugins/security_solution/common/endpoint/data_loaders/index_case.ts index d9c297789ffdc..fffdd11815112 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_loaders/index_case.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_loaders/index_case.ts @@ -6,7 +6,7 @@ */ import type { KbnClient } from '@kbn/test'; -import type { CaseResponse } from '@kbn/cases-plugin/common'; +import type { Case } from '@kbn/cases-plugin/common'; import { CASES_URL } from '@kbn/cases-plugin/common'; import type { CasePostRequest } from '@kbn/cases-plugin/common/api'; import { CaseSeverity, ConnectorTypes } from '@kbn/cases-plugin/common/api'; @@ -14,7 +14,7 @@ import type { AxiosError } from 'axios'; import { EndpointError } from '../errors'; export interface IndexedCase { - data: CaseResponse; + data: Case; cleanup: () => Promise<{ /** The ID of the cases that were deleted */ data: string; @@ -55,7 +55,7 @@ export const indexCase = async ( }; const createdCase = ( - await kbnClient.request({ + await kbnClient.request({ method: 'POST', path: CASES_URL, body: newCaseReq, diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/api_fixtures.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/api_fixtures.ts index 3b8b7cfae6340..708c10ac3cc4d 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/api_fixtures.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/api_fixtures.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { CaseResponse } from '@kbn/cases-plugin/common'; +import type { Case } from '@kbn/cases-plugin/common'; import type { RuleResponse } from '../../../../common/detection_engine/rule_schema'; import { request } from './common'; @@ -69,7 +69,7 @@ export const loadRule = (includeResponseActions = true) => }).then((response) => response.body); export const loadCase = (owner: string) => - request({ + request({ method: 'POST', url: '/api/cases', body: { diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/cases_table/use_case_items.ts b/x-pack/plugins/security_solution/public/overview/components/detection_response/cases_table/use_case_items.ts index 5bb453e566ae9..6961fc5fbe90e 100644 --- a/x-pack/plugins/security_solution/public/overview/components/detection_response/cases_table/use_case_items.ts +++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/cases_table/use_case_items.ts @@ -7,8 +7,7 @@ import { useState, useEffect, useMemo } from 'react'; -import type { CaseStatuses } from '@kbn/cases-plugin/common'; -import type { Cases } from '@kbn/cases-plugin/common/ui'; +import type { CaseStatuses, CasesUI } from '@kbn/cases-plugin/common'; import { v4 as uuidv4 } from 'uuid'; import { APP_ID } from '../../../../../common/constants'; @@ -103,7 +102,7 @@ export const useCaseItems: UseCaseItems = ({ skip }) => { return { items, isLoading, updatedAt }; }; -function parseCases(casesResponse: Cases): CaseItem[] { +function parseCases(casesResponse: CasesUI): CaseItem[] { const allCases = casesResponse.cases || []; return allCases.reduce((accumulated, currentCase) => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.tsx index 5da2a90ce14e4..508f0ffb63a4b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.tsx @@ -10,7 +10,7 @@ import { EuiButton, EuiContextMenuPanel, EuiContextMenuItem, EuiPopover } from ' import React, { useCallback, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; -import type { Case } from '@kbn/cases-plugin/common'; +import type { CaseUI } from '@kbn/cases-plugin/common'; import { APP_ID, APP_UI_ID } from '../../../../../common/constants'; import { timelineSelectors } from '../../../store/timeline'; import { setInsertTimeline, showTimeline } from '../../../store/timeline/actions'; @@ -49,7 +49,7 @@ const AddToCaseButtonComponent: React.FC = ({ timelineId }) => { const [isCaseModalOpen, openCaseModal] = useState(false); const onRowClick = useCallback( - async (theCase?: Case) => { + async (theCase?: CaseUI) => { openCaseModal(false); await navigateToApp(APP_UI_ID, { deepLinkId: SecurityPageName.case, diff --git a/x-pack/test/cases_api_integration/common/lib/alerts.ts b/x-pack/test/cases_api_integration/common/lib/alerts.ts index c949b805f45d0..be0ee606f503d 100644 --- a/x-pack/test/cases_api_integration/common/lib/alerts.ts +++ b/x-pack/test/cases_api_integration/common/lib/alerts.ts @@ -12,7 +12,7 @@ import { ToolingLog } from '@kbn/tooling-log'; import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '@kbn/security-solution-plugin/common/constants'; import { DetectionAlert } from '@kbn/security-solution-plugin/common/detection_engine/schemas/alerts'; import { RiskEnrichmentFields } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/enrichments/types'; -import { CaseResponse, CommentType } from '@kbn/cases-plugin/common'; +import { Case, CommentType } from '@kbn/cases-plugin/common'; import { ALERT_CASE_IDS } from '@kbn/rule-data-utils'; import { getRuleForSignalTesting, @@ -199,7 +199,7 @@ export const createCaseAndAttachAlert = async ({ owner: string; alerts: Alerts; getAlerts: (alerts: Alerts) => Promise>>; -}): Promise => { +}): Promise => { const cases = await Promise.all( [...Array(totalCases).keys()].map((index) => createCase( diff --git a/x-pack/test/cases_api_integration/common/lib/api/attachments.ts b/x-pack/test/cases_api_integration/common/lib/api/attachments.ts index f9e8f2658db81..944c2415ec38e 100644 --- a/x-pack/test/cases_api_integration/common/lib/api/attachments.ts +++ b/x-pack/test/cases_api_integration/common/lib/api/attachments.ts @@ -11,7 +11,7 @@ import { AllCommentsResponse, BulkCreateCommentRequest, BulkGetAttachmentsResponse, - CaseResponse, + Case, CommentPatchRequest, CommentRequest, CommentResponse, @@ -63,7 +63,7 @@ export const createComment = async ({ auth?: { user: User; space: string | null } | null; expectedHttpCode?: number; headers?: Record; -}): Promise => { +}): Promise => { const apiCall = supertest.post( `${getSpaceUrlPrefix(auth?.space)}${CASES_URL}/${caseId}/comments` ); @@ -91,7 +91,7 @@ export const bulkCreateAttachments = async ({ params: BulkCreateCommentRequest; auth?: { user: User; space: string | null }; expectedHttpCode?: number; -}): Promise => { +}): Promise => { const { body: theCase } = await supertest .post( `${getSpaceUrlPrefix(auth.space)}${CASES_INTERNAL_URL}/${caseId}/attachments/_bulk_create` @@ -114,7 +114,7 @@ export const createCaseAndBulkCreateAttachments = async ({ numberOfAttachments?: number; auth?: { user: User; space: string | null }; expectedHttpCode?: number; -}): Promise<{ theCase: CaseResponse; attachments: BulkCreateCommentRequest }> => { +}): Promise<{ theCase: Case; attachments: BulkCreateCommentRequest }> => { const postedCase = await createCase(supertest, postCaseReq); const attachments = getAttachments(numberOfAttachments); const patchedCase = await bulkCreateAttachments({ @@ -247,7 +247,7 @@ export const updateComment = async ({ expectedHttpCode?: number; auth?: { user: User; space: string | null } | null; headers?: Record; -}): Promise => { +}): Promise => { const apiCall = supertest.patch( `${getSpaceUrlPrefix(auth?.space)}${CASES_URL}/${caseId}/comments` ); diff --git a/x-pack/test/cases_api_integration/common/lib/api/case.ts b/x-pack/test/cases_api_integration/common/lib/api/case.ts index 9485ea3a797b7..29e813c9dd7c1 100644 --- a/x-pack/test/cases_api_integration/common/lib/api/case.ts +++ b/x-pack/test/cases_api_integration/common/lib/api/case.ts @@ -6,7 +6,7 @@ */ import { CASES_URL } from '@kbn/cases-plugin/common'; -import { CasePostRequest, CaseResponse } from '@kbn/cases-plugin/common/api'; +import { CasePostRequest, Case } from '@kbn/cases-plugin/common/api'; import type SuperTest from 'supertest'; import { User } from '../authentication/types'; @@ -19,7 +19,7 @@ export const createCase = async ( expectedHttpCode: number = 200, auth: { user: User; space: string | null } | null = { user: superUser, space: null }, headers: Record = {} -): Promise => { +): Promise => { const apiCall = supertest.post(`${getSpaceUrlPrefix(auth?.space)}${CASES_URL}`); setupAuth({ apiCall, headers, auth }); diff --git a/x-pack/test/cases_api_integration/common/lib/api/connectors.ts b/x-pack/test/cases_api_integration/common/lib/api/connectors.ts index eee179df52d2b..0a2b00b7acbb1 100644 --- a/x-pack/test/cases_api_integration/common/lib/api/connectors.ts +++ b/x-pack/test/cases_api_integration/common/lib/api/connectors.ts @@ -15,7 +15,7 @@ import { CaseConnector, ConnectorTypes, CasePostRequest, - CaseResponse, + Case, GetCaseConnectorsResponse, getCaseConnectorsUrl, } from '@kbn/cases-plugin/common/api'; @@ -219,7 +219,7 @@ export const createCaseWithConnector = async ({ createCaseReq?: CasePostRequest; headers?: Record; }): Promise<{ - postedCase: CaseResponse; + postedCase: Case; connector: CreateConnectorResponse; configuration: CasesConfigureResponse; }> => { diff --git a/x-pack/test/cases_api_integration/common/lib/api/index.ts b/x-pack/test/cases_api_integration/common/lib/api/index.ts index 88fe7a1482379..a4358cc87358b 100644 --- a/x-pack/test/cases_api_integration/common/lib/api/index.ts +++ b/x-pack/test/cases_api_integration/common/lib/api/index.ts @@ -27,9 +27,9 @@ import { } from '@kbn/cases-plugin/common/constants'; import { CasesConfigureResponse, - CaseResponse, + Case, CaseStatuses, - CasesResponse, + Cases, CasesFindResponse, CasesPatchRequest, CasesConfigurePatch, @@ -45,9 +45,9 @@ import { } from '@kbn/cases-plugin/common/api'; import { SignalHit } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/types'; import { ActionResult } from '@kbn/actions-plugin/server/types'; -import { ESCasesConfigureAttributes } from '@kbn/cases-plugin/server/services/configure/types'; -import { ESCaseAttributes } from '@kbn/cases-plugin/server/services/cases/types'; +import { CasePersistedAttributes } from '@kbn/cases-plugin/server/common/types/case'; import type { SavedObjectsRawDocSource } from '@kbn/core/server'; +import type { ConfigurePersistedAttributes } from '@kbn/cases-plugin/server/common/types/configure'; import { User } from '../authentication/types'; import { superUser } from '../authentication/users'; import { getSpaceUrlPrefix, setupAuth } from './helpers'; @@ -130,8 +130,8 @@ export const setStatus = async ({ }: { supertest: SuperTest.SuperTest; cases: SetStatusCasesParams[]; -}): Promise => { - const { body }: { body: CasesResponse } = await supertest +}): Promise => { + const { body }: { body: Cases } = await supertest .patch(CASES_URL) .set('kbn-xsrf', 'true') .send({ cases }) @@ -312,7 +312,7 @@ export const getConnectorMappingsFromES = async ({ es }: { es: Client }) => { }; interface ConfigureSavedObject { - 'cases-configure': ESCasesConfigureAttributes; + 'cases-configure': ConfigurePersistedAttributes; } /** @@ -343,7 +343,7 @@ export const getConfigureSavedObjectsFromES = async ({ es }: { es: Client }) => export const getCaseSavedObjectsFromES = async ({ es }: { es: Client }) => { const cases: TransportResult< - estypes.SearchResponse<{ cases: ESCaseAttributes }>, + estypes.SearchResponse<{ cases: CasePersistedAttributes }>, unknown > = await es.search( { @@ -366,7 +366,7 @@ export const getCaseSavedObjectsFromES = async ({ es }: { es: Client }) => { export const getCaseCommentSavedObjectsFromES = async ({ es }: { es: Client }) => { const comments: TransportResult< - estypes.SearchResponse<{ ['cases-comments']: ESCaseAttributes }>, + estypes.SearchResponse<{ ['cases-comments']: CasePersistedAttributes }>, unknown > = await es.search( { @@ -389,7 +389,7 @@ export const getCaseCommentSavedObjectsFromES = async ({ es }: { es: Client }) = export const getCaseUserActionsSavedObjectsFromES = async ({ es }: { es: Client }) => { const userActions: TransportResult< - estypes.SearchResponse<{ ['cases-user-actions']: ESCaseAttributes }>, + estypes.SearchResponse<{ ['cases-user-actions']: CasePersistedAttributes }>, unknown > = await es.search( { @@ -422,7 +422,7 @@ export const updateCase = async ({ expectedHttpCode?: number; auth?: { user: User; space: string | null } | null; headers?: Record; -}): Promise => { +}): Promise => { const apiCall = supertest.patch(`${getSpaceUrlPrefix(auth?.space)}${CASES_URL}`); setupAuth({ apiCall, headers, auth }); @@ -514,7 +514,7 @@ export const getCase = async ({ includeComments?: boolean; expectedHttpCode?: number; auth?: { user: User; space: string | null }; -}): Promise => { +}): Promise => { const { body: theCase } = await supertest .get( `${getSpaceUrlPrefix(auth?.space)}${CASES_URL}/${caseId}?includeComments=${includeComments}` @@ -674,7 +674,7 @@ export const pushCase = async ({ expectedHttpCode?: number; auth?: { user: User; space: string | null } | null; headers?: Record; -}): Promise => { +}): Promise => { const apiCall = supertest.post( `${getSpaceUrlPrefix(auth?.space)}${CASES_URL}/${caseId}/connector/${connectorId}/_push` ); diff --git a/x-pack/test/cases_api_integration/common/lib/api/omit.ts b/x-pack/test/cases_api_integration/common/lib/api/omit.ts index 0b069f409157b..4f0b3402b847d 100644 --- a/x-pack/test/cases_api_integration/common/lib/api/omit.ts +++ b/x-pack/test/cases_api_integration/common/lib/api/omit.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { CaseResponse, CommentResponse } from '@kbn/cases-plugin/common/api'; +import { Case, CommentResponse } from '@kbn/cases-plugin/common/api'; import { omit } from 'lodash'; interface CommonSavedObjectAttributes { @@ -36,10 +36,8 @@ export const removeServerGeneratedPropertiesFromSavedObject = < ]); }; -export const removeServerGeneratedPropertiesFromCase = ( - theCase: CaseResponse -): Partial => { - return removeServerGeneratedPropertiesFromSavedObject(theCase, ['closed_at']); +export const removeServerGeneratedPropertiesFromCase = (theCase: Case): Partial => { + return removeServerGeneratedPropertiesFromSavedObject(theCase, ['closed_at']); }; export const removeServerGeneratedPropertiesFromComments = ( diff --git a/x-pack/test/cases_api_integration/common/lib/mock.ts b/x-pack/test/cases_api_integration/common/lib/mock.ts index 1ea6c1b1e1359..8b8562e145395 100644 --- a/x-pack/test/cases_api_integration/common/lib/mock.ts +++ b/x-pack/test/cases_api_integration/common/lib/mock.ts @@ -7,7 +7,7 @@ import { CasePostRequest, - CaseResponse, + Case, CasesFindResponse, CommentResponse, ConnectorTypes, @@ -161,7 +161,7 @@ export const persistableStateAttachment: CommentRequestPersistableStateType = { export const postCaseResp = ( id?: string | null, req: CasePostRequest = postCaseReq -): Partial => ({ +): Partial => ({ ...req, ...(id != null ? { id } : {}), comments: [], diff --git a/x-pack/test/cases_api_integration/common/lib/validation.ts b/x-pack/test/cases_api_integration/common/lib/validation.ts index e022beb5a597a..dd1ca12a2db15 100644 --- a/x-pack/test/cases_api_integration/common/lib/validation.ts +++ b/x-pack/test/cases_api_integration/common/lib/validation.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { AttachmentTotals, - CaseResponse, + Case, CasesByAlertId, RelatedCaseInfo, } from '@kbn/cases-plugin/common/api'; @@ -17,7 +17,7 @@ import { xorWith, isEqual } from 'lodash'; type AttachmentTotalsKeys = keyof AttachmentTotals; export interface TestCaseWithTotals { - caseInfo: CaseResponse; + caseInfo: Case; totals?: Partial; } diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/alerts/get_cases.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/alerts/get_cases.ts index ba3ad76740d29..07ea283247d91 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/alerts/get_cases.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/alerts/get_cases.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { CASES_URL } from '@kbn/cases-plugin/common/constants'; -import { CaseResponse } from '@kbn/cases-plugin/common/api'; +import { Case } from '@kbn/cases-plugin/common/api'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -71,14 +71,14 @@ export default ({ getService }: FtrProviderContext): void => { // if there are more than 100 responses, the implementation sets the aggregation size to the // specific value const numCases = 102; - const createCasePromises: Array> = []; + const createCasePromises: Array> = []; for (let i = 0; i < numCases; i++) { createCasePromises.push(createCase(supertest, getPostCaseRequest())); } const cases = await Promise.all(createCasePromises); - const commentPromises: Array> = []; + const commentPromises: Array> = []; for (const caseInfo of cases) { commentPromises.push( createComment({ supertest, caseId: caseInfo.id, params: postCommentAlertReq }) diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/find_cases.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/find_cases.ts index c0e6322f638e5..38893e313a11f 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/find_cases.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/find_cases.ts @@ -9,13 +9,8 @@ import { v1 as uuidv1 } from 'uuid'; import expect from '@kbn/expect'; import { CASES_URL } from '@kbn/cases-plugin/common/constants'; +import { Case, CaseSeverity, CaseStatuses, CommentType } from '@kbn/cases-plugin/common/api'; import { ALERTING_CASES_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; -import { - CaseResponse, - CaseSeverity, - CaseStatuses, - CommentType, -} from '@kbn/cases-plugin/common/api'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -243,7 +238,7 @@ export default ({ getService }: FtrProviderContext): void => { const postedCase = await createCase(supertest, postCaseReq); // all fields that contain the UserRt definition must be included here (aka created_by, closed_by, and updated_by) // see https://github.com/elastic/kibana/issues/139503 - const queryFields: Array> = [ + const queryFields: Array> = [ ['title', 'created_by', 'closed_by', 'updated_by'], ['title', 'description', 'created_by', 'closed_by', 'updated_by'], ]; @@ -501,7 +496,7 @@ export default ({ getService }: FtrProviderContext): void => { await deleteAllCaseItems(es); }); - const createCasesWithTitleAsNumber = async (total: number): Promise => { + const createCasesWithTitleAsNumber = async (total: number): Promise => { const responsePromises = []; for (let i = 0; i < total; i++) { // this doesn't guarantee that the cases will be created in order that the for-loop executes, diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/import_export.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/import_export.ts index 1a3dd08e369d0..b030b0ea5db4d 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/import_export.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/import_export.ts @@ -28,7 +28,10 @@ import { CaseSeverity, CaseUserActionAttributesWithoutConnectorId, } from '@kbn/cases-plugin/common/api'; -import { ESCaseSeverity, ESCaseStatus } from '@kbn/cases-plugin/server/services/cases/types'; +import { + CasePersistedSeverity, + CasePersistedStatus, +} from '@kbn/cases-plugin/server/common/types/case'; import { ObjectRemover as ActionsRemover } from '../../../../../alerting_api_integration/common/lib'; import { deleteAllCaseItems, @@ -211,8 +214,8 @@ const expectExportToHaveCaseSavedObject = ( expect(createdCaseSO.attributes.connector.name).to.eql(caseRequest.connector.name); expect(createdCaseSO.attributes.connector.fields).to.eql([]); expect(createdCaseSO.attributes.settings).to.eql(caseRequest.settings); - expect(createdCaseSO.attributes.status).to.eql(ESCaseStatus.OPEN); - expect(createdCaseSO.attributes.severity).to.eql(ESCaseSeverity.LOW); + expect(createdCaseSO.attributes.status).to.eql(CasePersistedStatus.OPEN); + expect(createdCaseSO.attributes.severity).to.eql(CasePersistedSeverity.LOW); expect(createdCaseSO.attributes.duration).to.eql(null); expect(createdCaseSO.attributes.tags).to.eql(caseRequest.tags); }; diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/migrations.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/migrations.ts index a63e1b3be5c67..f908e90c58afb 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/migrations.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/migrations.ts @@ -8,7 +8,10 @@ import expect from '@kbn/expect'; import { CASES_URL, SECURITY_SOLUTION_OWNER } from '@kbn/cases-plugin/common/constants'; import { AttributesTypeUser } from '@kbn/cases-plugin/common/api'; -import { ESCaseSeverity, ESCaseStatus } from '@kbn/cases-plugin/server/services/cases/types'; +import { + CasePersistedSeverity, + CasePersistedStatus, +} from '@kbn/cases-plugin/server/common/types/case'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; import { deleteAllCaseItems, @@ -499,11 +502,11 @@ export default function createGetTests({ getService }: FtrProviderContext) { describe('severity', () => { it('severity keyword values are converted to matching short', async () => { - const expectedSeverityValues: Record = { - 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf6': ESCaseSeverity.LOW, - 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf7': ESCaseSeverity.MEDIUM, - 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf8': ESCaseSeverity.HIGH, - 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf9': ESCaseSeverity.CRITICAL, + const expectedSeverityValues: Record = { + 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf6': CasePersistedSeverity.LOW, + 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf7': CasePersistedSeverity.MEDIUM, + 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf8': CasePersistedSeverity.HIGH, + 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf9': CasePersistedSeverity.CRITICAL, }; const casesFromES = await getCaseSavedObjectsFromES({ es }); @@ -518,11 +521,11 @@ export default function createGetTests({ getService }: FtrProviderContext) { describe('status', () => { it('status keyword values are converted to matching short', async () => { - const expectedStatusValues: Record = { - 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf6': ESCaseStatus.OPEN, - 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf7': ESCaseStatus.OPEN, - 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf8': ESCaseStatus.IN_PROGRESS, - 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf9': ESCaseStatus.CLOSED, + const expectedStatusValues: Record = { + 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf6': CasePersistedStatus.OPEN, + 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf7': CasePersistedStatus.OPEN, + 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf8': CasePersistedStatus.IN_PROGRESS, + 'cases:063d5820-1284-11ed-81af-63a2bdfb2bf9': CasePersistedStatus.CLOSED, }; const casesFromES = await getCaseSavedObjectsFromES({ es }); diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts index 8f784d2e9c697..34b4c0dbaa019 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/patch_cases.ts @@ -11,7 +11,7 @@ import { ALERT_WORKFLOW_STATUS } from '@kbn/rule-data-utils'; import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '@kbn/security-solution-plugin/common/constants'; import { CaseSeverity, - CasesResponse, + Cases, CaseStatuses, CommentType, ConnectorTypes, @@ -597,7 +597,7 @@ export default ({ getService }: FtrProviderContext): void => { ); // does NOT updates alert status when the status is updated and syncAlerts=false - const updatedIndWithStatus: CasesResponse = (await setStatus({ + const updatedIndWithStatus: Cases = (await setStatus({ supertest, cases: [ { @@ -611,7 +611,7 @@ export default ({ getService }: FtrProviderContext): void => { status: CaseStatuses['in-progress'], }, ], - })) as CasesResponse; + })) as Cases; await es.indices.refresh({ index: defaultSignalsIndex }); @@ -730,7 +730,7 @@ export default ({ getService }: FtrProviderContext): void => { signals.get(signalsIndex2)?.get(signalIDInSecondIndex)?._source?.signal?.status ).to.be(CaseStatuses.open); - const updatedIndWithStatus: CasesResponse = (await setStatus({ + const updatedIndWithStatus: Cases = (await setStatus({ supertest, cases: [ { @@ -739,7 +739,7 @@ export default ({ getService }: FtrProviderContext): void => { status: CaseStatuses.closed, }, ], - })) as CasesResponse; + })) as Cases; await es.indices.refresh({ index: defaultSignalsIndex }); await es.indices.refresh({ index: signalsIndex2 }); diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/client/update_alert_status.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/client/update_alert_status.ts index 6926b3e088ad1..be47e250c7a9f 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/client/update_alert_status.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/client/update_alert_status.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { CasesResponse, CaseStatuses, CommentType } from '@kbn/cases-plugin/common/api'; +import { Cases, CaseStatuses, CommentType } from '@kbn/cases-plugin/common/api'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { postCaseReq } from '../../../../common/lib/mock'; @@ -96,7 +96,7 @@ export default ({ getService }: FtrProviderContext): void => { // does NOT updates alert status when the status is updated and syncAlerts=false // this performs the cases update through the test plugin that leverages the cases client instead // of going through RESTful API of the cases plugin - const { body: updatedIndWithStatus }: { body: CasesResponse } = await supertest + const { body: updatedIndWithStatus }: { body: Cases } = await supertest .patch('/api/cases_user/cases') .set('kbn-xsrf', 'true') .send({ diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/bulk_create_attachments.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/bulk_create_attachments.ts index a26031124ca45..74b2799d232ac 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/bulk_create_attachments.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/bulk_create_attachments.ts @@ -11,7 +11,7 @@ import { ALERT_CASE_IDS, ALERT_WORKFLOW_STATUS } from '@kbn/rule-data-utils'; import { BulkCreateCommentRequest, - CaseResponse, + Case, CaseStatuses, CommentRequestExternalReferenceSOType, CommentType, @@ -80,7 +80,7 @@ export default ({ getService }: FtrProviderContext): void => { const log = getService('log'); const validateCommentsIgnoringOrder = ( - comments: CaseResponse['comments'], + comments: Case['comments'], attachments: BulkCreateCommentRequest ) => { expect(comments?.length).to.eql(attachments.length); diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/bulk_delete_file_attachments.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/bulk_delete_file_attachments.ts index bd2a4b8f85456..3c0c1b39c5a93 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/bulk_delete_file_attachments.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/bulk_delete_file_attachments.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { CaseResponse } from '@kbn/cases-plugin/common'; +import { Case } from '@kbn/cases-plugin/common'; import { constructFileKindIdByOwner } from '@kbn/cases-plugin/common/files'; import { Owner } from '@kbn/cases-plugin/common/constants/types'; import { CASES_TEST_FIXTURE_FILE_KIND_ID } from '@kbn/cases-api-integration-test-plugin/server/files'; @@ -62,7 +62,7 @@ export default ({ getService }: FtrProviderContext): void => { }); describe('failures', () => { - let postedCase: CaseResponse; + let postedCase: Case; before(async () => { postedCase = await createCase(supertest, getPostCaseRequest()); diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/bulk_get_attachments.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/bulk_get_attachments.ts index c5751ebf99a19..2d1a7c2ab69a6 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/bulk_get_attachments.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/bulk_get_attachments.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { AttributesTypeExternalReference, AttributesTypeExternalReferenceSO, - CaseResponse, + Case, CommentResponseTypePersistableState, } from '@kbn/cases-plugin/common/api'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; @@ -50,7 +50,7 @@ export default ({ getService }: FtrProviderContext): void => { describe('bulk_get_attachments', () => { describe('setup using two comments', () => { - let updatedCase: CaseResponse; + let updatedCase: Case; before(async () => { const postedCase = await createCase(supertest, postCaseReq); @@ -212,8 +212,8 @@ export default ({ getService }: FtrProviderContext): void => { }); describe('security and observability cases', () => { - let secCase: CaseResponse; - let obsCase: CaseResponse; + let secCase: Case; + let obsCase: Case; let secAttachmentId: string; let obsAttachmentId: string; diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/find_user_actions.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/find_user_actions.ts index ea7b41be84d89..28bab81a70bee 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/find_user_actions.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/find_user_actions.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { ActionTypes, - CaseResponse, + Case, CaseSeverity, CaseStatuses, CommentUserAction, @@ -131,7 +131,7 @@ export default ({ getService }: FtrProviderContext): void => { }); describe('pagination', () => { - let theCase: CaseResponse; + let theCase: Case; beforeEach(async () => { theCase = await createCase(supertest, getPostCaseRequest()); @@ -793,9 +793,9 @@ export default ({ getService }: FtrProviderContext): void => { describe('rbac', () => { const supertestWithoutAuth = getService('supertestWithoutAuth'); - let secCase: CaseResponse; - let obsCase: CaseResponse; - let secCaseSpace2: CaseResponse; + let secCase: Case; + let obsCase: Case; + let secCaseSpace2: Case; beforeEach(async () => { [secCase, obsCase, secCaseSpace2] = await Promise.all([ diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/get_all_user_actions.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/get_all_user_actions.ts index fc8ab00e63c64..744e70d3809a6 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/get_all_user_actions.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/get_all_user_actions.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { - CaseResponse, + Case, CaseSeverity, CaseStatuses, CommentType, @@ -342,7 +342,7 @@ export default ({ getService }: FtrProviderContext): void => { describe('rbac', () => { const supertestWithoutAuth = getService('supertestWithoutAuth'); - let caseInfo: CaseResponse; + let caseInfo: Case; beforeEach(async () => { caseInfo = await createCase(supertestWithoutAuth, getPostCaseRequest(), 200, { user: superUser, diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/get_user_action_stats.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/get_user_action_stats.ts index 8448f22b7f9e0..6801fa4fe3785 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/get_user_action_stats.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/get_user_action_stats.ts @@ -6,12 +6,7 @@ */ import expect from '@kbn/expect'; -import { - CaseResponse, - CaseSeverity, - CaseStatuses, - ConnectorTypes, -} from '@kbn/cases-plugin/common/api'; +import { Case, CaseSeverity, CaseStatuses, ConnectorTypes } from '@kbn/cases-plugin/common/api'; import { globalRead, @@ -140,7 +135,7 @@ export default ({ getService }: FtrProviderContext): void => { describe('rbac', () => { const supertestWithoutAuth = getService('supertestWithoutAuth'); - let theCase: CaseResponse; + let theCase: Case; beforeEach(async () => { theCase = await createCase(supertestWithoutAuth, getPostCaseRequest(), 200, { user: superUser, diff --git a/x-pack/test/functional/services/cases/api.ts b/x-pack/test/functional/services/cases/api.ts index 743037fed22c5..2322c8b798eb5 100644 --- a/x-pack/test/functional/services/cases/api.ts +++ b/x-pack/test/functional/services/cases/api.ts @@ -6,12 +6,7 @@ */ import pMap from 'p-map'; -import { - CasePostRequest, - CaseResponse, - CaseSeverity, - CaseStatuses, -} from '@kbn/cases-plugin/common/api'; +import { CasePostRequest, Case, CaseSeverity, CaseStatuses } from '@kbn/cases-plugin/common/api'; import { createCase as createCaseAPI, deleteAllCaseItems, @@ -36,7 +31,7 @@ export function CasesAPIServiceProvider({ getService }: FtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); return { - async createCase(overwrites: Partial = {}): Promise { + async createCase(overwrites: Partial = {}): Promise { const caseData = { ...generateRandomCaseWithoutConnector(), ...overwrites, @@ -66,7 +61,7 @@ export function CasesAPIServiceProvider({ getService }: FtrProviderContext) { }: { caseId: Parameters[0]['caseId']; params: Parameters[0]['params']; - }): Promise { + }): Promise { return createComment({ supertest: kbnSupertest, params, caseId }); }, @@ -100,7 +95,7 @@ export function CasesAPIServiceProvider({ getService }: FtrProviderContext) { return suggestUserProfiles({ supertest: kbnSupertest, req: options }); }, - async getCase({ caseId }: OmitSupertest[0]>): Promise { + async getCase({ caseId }: OmitSupertest[0]>): Promise { return getCase({ supertest: kbnSupertest, caseId }); }, diff --git a/x-pack/test/functional_with_es_ssl/apps/cases/group2/attachment_framework.ts b/x-pack/test/functional_with_es_ssl/apps/cases/group2/attachment_framework.ts index 9b18dcbca8ebc..a81f862b54b65 100644 --- a/x-pack/test/functional_with_es_ssl/apps/cases/group2/attachment_framework.ts +++ b/x-pack/test/functional_with_es_ssl/apps/cases/group2/attachment_framework.ts @@ -9,7 +9,7 @@ import type SuperTest from 'supertest'; import { ExternalReferenceStorageType, CommentType, - CaseResponse, + Case, CommentRequest, } from '@kbn/cases-plugin/common/api'; import { expect } from 'expect'; @@ -84,7 +84,7 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { */ describe('Attachment framework', () => { describe('External reference attachments', () => { - let caseWithAttachment: CaseResponse; + let caseWithAttachment: Case; before(async () => { caseWithAttachment = await createAttachmentAndNavigate({ @@ -180,7 +180,7 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { }, }); - let caseWithAttachment: CaseResponse; + let caseWithAttachment: Case; let dataViewId = ''; before(async () => {