[Cases] Separate Cases SO attributes from HTTP APIs (#155898)

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 <christos.nasikas@elastic.co>
Co-authored-by: Patryk Kopyciński <contact@patrykkopycinski.com>
This commit is contained in:
Jonathan Buttner 2023-04-28 08:31:21 -04:00 committed by GitHub
parent 24927cb061
commit 6d5e2456d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
166 changed files with 1715 additions and 1444 deletions

View file

@ -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<typeof CaseAttributesRt>;
export type CasePostRequest = rt.TypeOf<typeof CasePostRequestRt>;
export type CaseResponse = rt.TypeOf<typeof CaseResponseRt>;
export type Case = rt.TypeOf<typeof CaseRt>;
export type CaseResolveResponse = rt.TypeOf<typeof CaseResolveResponseRt>;
export type CasesResponse = rt.TypeOf<typeof CasesResponseRt>;
export type Cases = rt.TypeOf<typeof CasesRt>;
export type CasesFindRequest = rt.TypeOf<typeof CasesFindRequestRt>;
export type CasesByAlertIDRequest = rt.TypeOf<typeof CasesByAlertIDRequestRt>;
export type CasesFindResponse = rt.TypeOf<typeof CasesFindResponseRt>;
@ -375,13 +375,15 @@ export type CasesByAlertId = rt.TypeOf<typeof CasesByAlertIdRt>;
export type CasesBulkGetRequest = rt.TypeOf<typeof CasesBulkGetRequestRt>;
export type CasesBulkGetResponse = rt.TypeOf<typeof CasesBulkGetResponseRt>;
export type CasesBulkGetRequestCertainFields<
Field extends keyof CaseResponse = keyof CaseResponse
> = Omit<CasesBulkGetRequest, 'fields'> & {
export type CasesBulkGetRequestCertainFields<Field extends keyof Case = keyof Case> = Omit<
CasesBulkGetRequest,
'fields'
> & {
fields?: Field[];
};
export type CasesBulkGetResponseCertainFields<
Field extends keyof CaseResponse = keyof CaseResponse
> = Omit<CasesBulkGetResponse, 'cases'> & {
cases: Array<Pick<CaseResponse, Field | 'id' | 'version' | 'owner'>>;
export type CasesBulkGetResponseCertainFields<Field extends keyof Case = keyof Case> = Omit<
CasesBulkGetResponse,
'cases'
> & {
cases: Array<Pick<Case, Field | 'id' | 'version' | 'owner'>>;
};

View file

@ -68,5 +68,3 @@ export const SavedObjectFindOptionsRt = rt.partial({
*/
sortOrder: rt.union([rt.literal('desc'), rt.literal('asc')]),
});
export type SavedObjectFindOptions = rt.TypeOf<typeof SavedObjectFindOptionsRt>;

View file

@ -38,13 +38,15 @@ export {
} from './api';
export type {
CaseResponse,
Case,
Cases,
CasesBulkGetRequestCertainFields,
CasesBulkGetResponseCertainFields,
} from './api';
export type {
Case,
CaseUI,
CasesUI,
Ecs,
CasesFeatures,
CaseViewRefreshPropInterface,

View file

@ -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<SnakeToCamelCase<UserActionFindResponse>,
userActions: CaseUserActions[];
};
export type CaseUserActionsStats = SnakeToCamelCase<CaseUserActionStatsResponse>;
export type Case = Omit<SnakeToCamelCase<CaseResponse>, 'comments'> & { comments: Comment[] };
export type Cases = Omit<SnakeToCamelCase<CasesFindResponse>, 'cases'> & { cases: Case[] };
export type CaseUI = Omit<SnakeToCamelCase<CaseSnakeCase>, 'comments'> & { comments: Comment[] };
export type CasesUI = Omit<SnakeToCamelCase<CasesFindResponse>, 'cases'> & { cases: CaseUI[] };
export type CasesStatus = SnakeToCamelCase<CasesStatusResponse>;
export type CasesMetrics = SnakeToCamelCase<CasesMetricsResponse>;
export type CaseUpdateRequest = SnakeToCamelCase<CasePatchRequest>;
@ -101,7 +101,7 @@ export type CaseConnectors = SnakeToCamelCase<GetCaseConnectorsResponse>;
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;
}

View file

@ -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 = <Field extends keyof CaseResponse = keyof CaseResponse>(
export const decodeCasesBulkGetResponse = <Field extends keyof Case = keyof Case>(
res: CasesBulkGetResponseCertainFields<Field>,
fields?: string[]
) => {
const typeToDecode = getTypeForCertainFieldsFromArray(CasesResponseRt, fields);
const typeToDecode = getTypeForCertainFieldsFromArray(CasesRt, fields);
pipe(typeToDecode.decode(res.cases), fold(throwErrors(createToasterPlainError), identity));
return res;

View file

@ -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<Cases> => {
}: HTTPService & { query: CasesFindRequest }): Promise<CasesUI> => {
const res = await http.get<CasesFindResponse>(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 <Field extends keyof CaseResponse = keyof CaseResponse>({
export const bulkGetCases = async <Field extends keyof Case = keyof Case>({
http,
signal,
params,

View file

@ -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 = <T, U extends {}>(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<CaseResponse, Case>(restCase),
...convertToCamelCase<Case, CaseUI>(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,

View file

@ -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<CasesByAlertId> =>
http.get<CasesByAlertId>(getCasesFromAlertsUrl(alertId), { query }),
cases: {
find: (query: CasesFindRequest, signal?: AbortSignal): Promise<Cases> =>
find: (query: CasesFindRequest, signal?: AbortSignal): Promise<CasesUI> =>
getCases({ http, query, signal }),
getCasesStatus: (query: CasesStatusRequest, signal?: AbortSignal): Promise<CasesStatus> =>
getCasesStatus({ http, query, signal }),

View file

@ -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<Props = {}> {
}
export interface CommonAttachmentViewProps {
caseData: Pick<Case, 'id' | 'title'>;
caseData: Pick<CaseUI, 'id' | 'title'>;
}
export interface ExternalReferenceAttachmentViewProps extends CommonAttachmentViewProps {

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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<Case['assignees']>({
useItemsAction<CaseUI['assignees']>({
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),

View file

@ -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: <EuiTextColor>{i18n.COPY_ID_ACTION_LABEL}</EuiTextColor>,
onClick: () => {

View file

@ -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<boolean>(false);
const [caseToBeDeleted, setCaseToBeDeleted] = useState<Case[]>([]);
const [caseToBeDeleted, setCaseToBeDeleted] = useState<CaseUI[]>([]);
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: <EuiTextColor color={color}>{getDeleteActionTitle(selectedCases.length)}</EuiTextColor>,
onClick: () => openModal(selectedCases),

View file

@ -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,

View file

@ -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,

View file

@ -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;
}

View file

@ -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;

View file

@ -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<Case['tags']>({
useItemsAction<CaseUI['tags']>({
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),

View file

@ -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<T> = 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 = <T,>({
const { mutate: updateCases } = useUpdateCases();
const { permissions } = useCasesContext();
const [isFlyoutOpen, setIsFlyoutOpen] = useState<boolean>(false);
const [selectedCasesToEdit, setSelectedCasesToEdit] = useState<Case[]>([]);
const [selectedCasesToEdit, setSelectedCasesToEdit] = useState<CaseUI[]>([]);
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);

View file

@ -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: <T>(item: Payload[number]) => EuiSelectableOption<T>;
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<string, number>();

View file

@ -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;
}

View file

@ -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<AllCasesListProps>(
@ -84,7 +84,7 @@ export const AllCasesList = React.memo<AllCasesListProps>(
isSelectorView,
initialFilterOptions
);
const [selectedCases, setSelectedCases] = useState<Case[]>([]);
const [selectedCases, setSelectedCases] = useState<CaseUI[]>([]);
const { data = initialData, isFetching: isLoadingCases } = useGetCases({
filterOptions,
@ -224,7 +224,7 @@ export const AllCasesList = React.memo<AllCasesListProps>(
[data, queryParams]
);
const euiBasicTableSelectionProps = useMemo<EuiTableSelectionType<Case>>(
const euiBasicTableSelectionProps = useMemo<EuiTableSelectionType<CaseUI>>(
() => ({
onSelectionChange: setSelectedCases,
initialSelected: selectedCases,
@ -235,7 +235,7 @@ export const AllCasesList = React.memo<AllCasesListProps>(
const isDataEmpty = useMemo(() => data.total === 0, [data]);
const tableRowProps = useCallback(
(theCase: Case) => ({
(theCase: CaseUI) => ({
'data-test-subj': `cases-table-row-${theCase.id}`,
}),
[]

View file

@ -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<string, UserProfileWithAvatar>;
compressedDisplayLimit?: number;
}

View file

@ -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<AllCasesSelectorModalProps>(
}, [onClose]);
const onClick = useCallback(
(theCase?: Case) => {
(theCase?: CaseUI) => {
closeModal();
if (onRowClick) {
onRowClick(theCase);

View file

@ -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;
});

View file

@ -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<AllCasesSelectorModalProps, 'onRo
title?: string;
content?: string;
};
onSuccess?: (theCase: Case) => 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: () => {

View file

@ -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<Case>['columns'];
data: Cases;
columns: EuiBasicTableProps<CaseUI>['columns'];
data: CasesUI;
goToCreateCase?: () => void;
isCasesLoading: boolean;
isCommentUpdating: boolean;
isDataEmpty: boolean;
isSelectorView?: boolean;
onChange: EuiBasicTableProps<Case>['onChange'];
onChange: EuiBasicTableProps<CaseUI>['onChange'];
pagination: Pagination;
selectedCases: Case[];
selection: EuiTableSelectionType<Case>;
sorting: EuiBasicTableProps<Case>['sorting'];
selectedCases: CaseUI[];
selection: EuiTableSelectionType<CaseUI>;
sorting: EuiBasicTableProps<CaseUI>['sorting'];
tableRef: MutableRefObject<EuiBasicTable | null>;
tableRowProps: EuiBasicTableProps<Case>['rowProps'];
tableRowProps: EuiBasicTableProps<CaseUI>['rowProps'];
deselectCases: () => void;
}

View file

@ -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<Case> | null;
actions: EuiTableComputedColumnType<CaseUI> | 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 (
<ActionColumn theCase={theCase} key={theCase.id} disableActions={disableActions} />
);

View file

@ -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;
}

View file

@ -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<Case>
| EuiTableComputedColumnType<Case>
| EuiTableFieldDataColumnType<Case>;
| EuiTableActionsColumnType<CaseUI>
| EuiTableComputedColumnType<CaseUI>
| EuiTableFieldDataColumnType<CaseUI>;
const MediumShadeText = styled.p`
color: ${({ theme }) => theme.eui.euiColorMediumShade};
@ -80,7 +80,7 @@ export interface GetCasesColumn {
userProfiles: Map<string, UserProfileWithAvatar>;
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']) => (
<AssigneesColumn assignees={assignees} userProfiles={userProfiles} />
),
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 = (
<LineClampedEuiBadgeGroup data-test-subj="case-table-column-tags">
@ -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 (
<span data-test-subj={`case-table-column-closedAt`}>
@ -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 (
<span data-test-subj={`case-table-column-createdAt`}>
@ -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 (
<span data-test-subj="case-table-column-updatedAt">
@ -304,7 +304,7 @@ export const useCasesColumns = ({
columns.push(
{
name: i18n.EXTERNAL_INCIDENT,
render: (theCase: Case) => {
render: (theCase: CaseUI) => {
if (theCase.id != null) {
return <ExternalServiceColumn theCase={theCase} connectors={connectors} />;
}
@ -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 <Status status={status} />;
}
@ -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 (
<EuiButton
@ -376,7 +376,7 @@ export const useCasesColumns = ({
};
interface Props {
theCase: Case;
theCase: CaseUI;
connectors: ActionConnector[];
}

View file

@ -17,7 +17,7 @@ import {
useEuiTheme,
} from '@elastic/eui';
import * as i18n from './translations';
import type { Case } from '../../../common/ui/types';
import type { CaseUI } from '../../../common/ui/types';
import { useRefreshCases } from './use_on_refresh_cases';
import { useBulkActions } from './use_bulk_actions';
import { useCasesContext } from '../cases_context/use_cases_context';
@ -25,7 +25,7 @@ import { useCasesContext } from '../cases_context/use_cases_context';
interface Props {
isSelectorView?: boolean;
totalCases: number;
selectedCases: Case[];
selectedCases: CaseUI[];
deselectCases: () => void;
}

View file

@ -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<CaseViewActions> = ({ caseData, currentExternalIncident }) => {

View file

@ -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']) {

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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: {

View file

@ -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<string | null | undefined, 'configurable'>;
caseData: Case;
caseData: CaseUI;
actionsNavigation?: CasesNavigation<string, 'configurable'>;
showAlertDetails?: (alertId: string, index: string) => void;
useFetchAlertData: UseFetchAlertData;

View file

@ -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;

View file

@ -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;

View file

@ -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],
};

View file

@ -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 = {

View file

@ -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[];

View file

@ -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: {

View file

@ -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;
}

View file

@ -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(

View file

@ -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<void>;
onClose?: () => void;
onSuccess?: (theCase: Case) => void;
onSuccess?: (theCase: CaseUI) => void;
attachments?: CaseAttachmentsWithoutOwner;
headerContent?: React.ReactNode;
initialValue?: Pick<CasePostRequest, 'title' | 'description'>;

View file

@ -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,

View file

@ -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<Partial<CreateCaseFormFieldsProps>, 'withSteps'> {
onCancel: () => void;
onSuccess: (theCase: Case) => void;
onSuccess: (theCase: CaseUI) => void;
afterCaseCreated?: (
theCase: Case,
theCase: CaseUI,
createAttachments: UseCreateAttachments['createAttachments']
) => Promise<void>;
timelineIntegration?: CasesTimelineIntegration;
@ -208,7 +208,7 @@ export const CreateCaseForm: React.FC<CreateCaseFormProps> = React.memo(
onConfirmationCallback: handleOnConfirmationCallback,
});
const handleOnSuccess = (theCase: Case): void => {
const handleOnSuccess = (theCase: CaseUI): void => {
removeItemFromSessionStorage(draftStorageKey);
return onSuccess(theCase);
};

View file

@ -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<void>;
children?: JSX.Element | JSX.Element[];
onSuccess?: (theCase: Case) => void;
onSuccess?: (theCase: CaseUI) => void;
attachments?: CaseAttachmentsWithoutOwner;
initialValue?: Pick<CasePostRequest, 'title' | 'description'>;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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<void>;
onSuccess: (theCase: CaseUI) => Promise<void>;
}
const CreateModalComponent: React.FC<CreateCaseModalProps> = ({

View file

@ -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;

View file

@ -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<string, UserProfileWithAvatar>;
currentUserProfile: CurrentUserProfile;
data: Case;
data: CaseUI;
getRuleDetailsHref?: RuleDetailsNavigation['href'];
actionsNavigation?: ActionsNavigation;
onRuleDetailsClick?: RuleDetailsNavigation['onClick'];
@ -48,7 +48,7 @@ export type SupportedUserActionTypes = keyof Omit<typeof ActionTypes, Unsupporte
export interface UserActionBuilderArgs {
appId?: string;
caseData: Case;
caseData: CaseUI;
userProfiles: Map<string, UserProfileWithAvatar>;
currentUserProfile: CurrentUserProfile;
externalReferenceAttachmentTypeRegistry: ExternalReferenceAttachmentTypeRegistry;

View file

@ -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

View file

@ -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<Case> => Promise.resolve(basicCase);
): Promise<CaseUI> => Promise.resolve(basicCase);
export const resolveCase = async (
caseId: string,
@ -101,9 +101,9 @@ export const getCases = async ({
sortOrder: 'desc',
},
signal,
}: FetchCasesProps): Promise<Cases> => Promise.resolve(allCases);
}: FetchCasesProps): Promise<CasesUI> => Promise.resolve(allCases);
export const postCase = async (newCase: CasePostRequest, signal: AbortSignal): Promise<Case> =>
export const postCase = async (newCase: CasePostRequest, signal: AbortSignal): Promise<CaseUI> =>
Promise.resolve(basicCasePost);
export const patchCase = async (
@ -111,18 +111,18 @@ export const patchCase = async (
updatedCase: Pick<CasePatchRequest, 'description' | 'status' | 'tags' | 'title'>,
version: string,
signal: AbortSignal
): Promise<Case[]> => Promise.resolve([basicCase]);
): Promise<CaseUI[]> => Promise.resolve([basicCase]);
export const updateCases = async (
cases: CaseUpdateRequest[],
signal: AbortSignal
): Promise<Case[]> => Promise.resolve(allCases.cases);
): Promise<CaseUI[]> => Promise.resolve(allCases.cases);
export const createAttachments = async (
newComment: CommentRequest,
caseId: string,
signal: AbortSignal
): Promise<Case> => Promise.resolve(basicCase);
): Promise<CaseUI> => Promise.resolve(basicCase);
export const deleteComment = async (
caseId: string,
@ -136,7 +136,7 @@ export const patchComment = async (
commentUpdate: string,
version: string,
signal: AbortSignal
): Promise<Case> => Promise.resolve(basicCaseCommentPatch);
): Promise<CaseUI> => Promise.resolve(basicCaseCommentPatch);
export const deleteCases = async (caseIds: string[], signal: AbortSignal): Promise<boolean> =>
Promise.resolve(true);
@ -145,7 +145,7 @@ export const pushCase = async (
caseId: string,
connectorId: string,
signal: AbortSignal
): Promise<Case> => Promise.resolve(pushedCase);
): Promise<CaseUI> => Promise.resolve(pushedCase);
export const getActionLicense = async (signal: AbortSignal): Promise<ActionLicense[]> =>
Promise.resolve(actionLicenses);

View file

@ -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<Case> => {
const response = await KibanaServices.get().http.fetch<CaseResponse>(getCaseDetailsUrl(caseId), {
): Promise<CaseUI> => {
const response = await KibanaServices.get().http.fetch<Case>(getCaseDetailsUrl(caseId), {
method: 'GET',
query: {
includeComments,
@ -223,7 +223,7 @@ export const getCases = async ({
sortOrder: 'desc',
},
signal,
}: FetchCasesProps): Promise<Cases> => {
}: FetchCasesProps): Promise<CasesUI> => {
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<Case> => {
const response = await KibanaServices.get().http.fetch<CaseResponse>(CASES_URL, {
export const postCase = async (newCase: CasePostRequest, signal: AbortSignal): Promise<CaseUI> => {
const response = await KibanaServices.get().http.fetch<Case>(CASES_URL, {
method: 'POST',
body: JSON.stringify(newCase),
signal,
@ -262,8 +262,8 @@ export const patchCase = async (
>,
version: string,
signal: AbortSignal
): Promise<Case[]> => {
const response = await KibanaServices.get().http.fetch<CasesResponse>(CASES_URL, {
): Promise<CaseUI[]> => {
const response = await KibanaServices.get().http.fetch<Cases>(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<Case[]> => {
): Promise<CaseUI[]> => {
if (cases.length === 0) {
return [];
}
const response = await KibanaServices.get().http.fetch<CasesResponse>(CASES_URL, {
const response = await KibanaServices.get().http.fetch<Cases>(CASES_URL, {
method: 'PATCH',
body: JSON.stringify({ cases }),
signal,
@ -292,15 +292,12 @@ export const postComment = async (
newComment: CommentRequest,
caseId: string,
signal: AbortSignal
): Promise<Case> => {
const response = await KibanaServices.get().http.fetch<CaseResponse>(
`${CASES_URL}/${caseId}/comments`,
{
method: 'POST',
body: JSON.stringify(newComment),
signal,
}
);
): Promise<CaseUI> => {
const response = await KibanaServices.get().http.fetch<Case>(`${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<Case> => {
const response = await KibanaServices.get().http.fetch<CaseResponse>(getCaseCommentsUrl(caseId), {
}): Promise<CaseUI> => {
const response = await KibanaServices.get().http.fetch<Case>(getCaseCommentsUrl(caseId), {
method: 'PATCH',
body: JSON.stringify({
comment: commentUpdate,
@ -342,7 +339,7 @@ export const deleteComment = async ({
commentId: string;
signal: AbortSignal;
}): Promise<void> => {
await KibanaServices.get().http.fetch<CaseResponse>(getCaseCommentDeleteUrl(caseId, commentId), {
await KibanaServices.get().http.fetch<Case>(getCaseCommentDeleteUrl(caseId, commentId), {
method: 'DELETE',
signal,
});
@ -361,8 +358,8 @@ export const pushCase = async (
caseId: string,
connectorId: string,
signal: AbortSignal
): Promise<Case> => {
const response = await KibanaServices.get().http.fetch<CaseResponse>(
): Promise<CaseUI> => {
const response = await KibanaServices.get().http.fetch<Case>(
getCasePushUrl(caseId, connectorId),
{
method: 'POST',
@ -390,8 +387,8 @@ export const createAttachments = async (
attachments: BulkCreateCommentRequest,
caseId: string,
signal: AbortSignal
): Promise<Case> => {
const response = await KibanaServices.get().http.fetch<CaseResponse>(
): Promise<CaseUI> => {
const response = await KibanaServices.get().http.fetch<Case>(
INTERNAL_BULK_CREATE_ATTACHMENTS_URL.replace('{case_id}', caseId),
{
method: 'POST',

View file

@ -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,

View file

@ -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 {

View file

@ -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<QueryParams>;
filterOptions?: Partial<FilterOptions>;
} = {}
): UseQueryResult<Cases> => {
): UseQueryResult<CasesUI> => {
const toasts = useToasts();
return useQuery(
casesQueriesKeys.cases(params),

View file

@ -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<Case | undefined>;
}: PushToServiceRequest) => Promise<CaseUI | undefined>;
}
export const usePostPushToService = (): UsePostPushToService => {

View file

@ -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', () => {

View file

@ -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 = <T>(a: unknown): T => a as T;
@ -49,8 +49,8 @@ export const covertToSnakeCase = (obj: Record<string, unknown>) =>
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 => {

View file

@ -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<CasesByAlertId>;
cases: {
find: (query: CasesFindRequest, signal?: AbortSignal) => Promise<Cases>;
find: (query: CasesFindRequest, signal?: AbortSignal) => Promise<CasesUI>;
getCasesStatus: (query: CasesStatusRequest, signal?: AbortSignal) => Promise<CasesStatus>;
getCasesMetrics: (query: CasesMetricsRequest, signal?: AbortSignal) => Promise<CasesMetrics>;
bulkGet: <Field extends keyof CaseResponse = keyof CaseResponse>(
bulkGet: <Field extends keyof Case = keyof Case>(
params: CasesBulkGetRequestCertainFields<Field>,
signal?: AbortSignal
) => Promise<CasesBulkGetResponseCertainFields<Field>>;

View file

@ -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<CaseResponse> => {
export const addComment = async (addArgs: AddArgs, clientArgs: CasesClientArgs): Promise<Case> => {
const { comment, caseId } = addArgs;
const query = pipe(
CommentRequestRt.decode(comment),

View file

@ -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<CaseResponse> => {
): Promise<Case> => {
const { attachments, caseId } = args;
pipe(

View file

@ -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<CaseResponse>;
bulkCreate(params: BulkCreateArgs): Promise<CaseResponse>;
add(params: AddArgs): Promise<Case>;
bulkCreate(params: BulkCreateArgs): Promise<Case>;
bulkGet(params: BulkGetArgs): Promise<BulkGetAttachmentsResponse>;
/**
* 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<CaseResponse>;
update(updateArgs: UpdateArgs): Promise<Case>;
}
/**

View file

@ -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<CaseResponse> {
): Promise<Case> {
const {
services: { attachmentService },
logger,

View file

@ -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<keyof CaseResponse>;
const typeProps = getTypeProps(CaseRt) ?? {};
const validFields = Object.keys(typeProps) as Array<keyof Case>;
beforeEach(() => {
jest.clearAllMocks();

View file

@ -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<CaseAttributes>;
/**
* Retrieves multiple cases by ids.
*/
export const bulkGet = async <Field extends keyof CaseResponse = keyof CaseResponse>(
export const bulkGet = async <Field extends keyof Case = keyof Case>(
params: CasesBulkGetRequestCertainFields<Field>,
clientArgs: CasesClientArgs
): Promise<CasesBulkGetResponseCertainFields<Field>> => {
@ -66,7 +66,7 @@ export const bulkGet = async <Field extends keyof CaseResponse = keyof CaseRespo
const [validCases, soBulkGetErrors] = partition(
cases.saved_objects,
(caseInfo) => 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 <Field extends keyof CaseResponse = keyof CaseRespo
return pick(flattenedCase, [...fields, 'id', 'version']);
});
const typeToEncode = getTypeForCertainFieldsFromArray(CasesResponseRt, fields);
const typeToEncode = getTypeForCertainFieldsFromArray(CasesRt, fields);
const casesToReturn = typeToEncode.encode(flattenedCases);
const errors = constructErrors(soBulkGetErrors, unauthorizedCases);
@ -124,7 +124,7 @@ const throwErrorIfFieldsAreInvalid = (fields?: string[]) => {
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'] = [];

View file

@ -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<Field extends keyof CaseResponse = keyof CaseResponse>(
bulkGet<Field extends keyof Case = keyof Case>(
params: CasesBulkGetRequestCertainFields<Field>
): Promise<CasesBulkGetResponseCertainFields<Field>>;
/**

View file

@ -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<CaseResponse> => {
export const create = async (data: CasePostRequest, clientArgs: CasesClientArgs): Promise<Case> => {
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 });
}

View file

@ -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<string, CaseResponse>(
const casesMap = new Map<string, Case>(
mockCases.map((obj) => {
return [obj.id, flattenCaseSavedObject({ savedObject: obj, totalComment: 2 })];
})

View file

@ -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<CaseResponse> => {
): Promise<Case> => {
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,

View file

@ -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<CaseResponse> => {
): Promise<Case> => {
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,

View file

@ -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<string, CaseSavedObject>,
casesMap: Map<string, CaseSavedObjectTransformed>,
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<CasesResponse> => {
): Promise<Cases> => {
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<string, CaseSavedObject>());
}, new Map<string, CaseSavedObjectTransformed>());
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<CaseAttributes>,
casesMap: Map<string, CaseSavedObject>,
casesMap: Map<string, CaseSavedObjectTransformed>,
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<CaseAttributes>
): CaseSavedObject => {
): CaseSavedObjectTransformed => {
return {
...originalSO,
...updatedSO,

View file

@ -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<string, UserProfile>,
publicBaseUrl?: IBasePath['publicBaseUrl']
@ -307,7 +307,7 @@ export const addKibanaInformationToDescription = (
};
const addKibanaInformationToComments = (
comments: CaseResponse['comments'] = [],
comments: Case['comments'] = [],
userProfiles?: Map<string, UserProfile>
): 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, UserProfile>
): string => {
return (

View file

@ -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(() => {

View file

@ -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(() => {

View file

@ -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(() => {

View file

@ -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();

View file

@ -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 {}

View file

@ -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 {

View file

@ -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, ESCaseSeverity> = {
[CaseSeverity.LOW]: ESCaseSeverity.LOW,
[CaseSeverity.MEDIUM]: ESCaseSeverity.MEDIUM,
[CaseSeverity.HIGH]: ESCaseSeverity.HIGH,
[CaseSeverity.CRITICAL]: ESCaseSeverity.CRITICAL,
export const SEVERITY_EXTERNAL_TO_ESMODEL: Record<CaseSeverity, CasePersistedSeverity> = {
[CaseSeverity.LOW]: CasePersistedSeverity.LOW,
[CaseSeverity.MEDIUM]: CasePersistedSeverity.MEDIUM,
[CaseSeverity.HIGH]: CasePersistedSeverity.HIGH,
[CaseSeverity.CRITICAL]: CasePersistedSeverity.CRITICAL,
};
export const SEVERITY_ESMODEL_TO_EXTERNAL: Record<ESCaseSeverity, CaseSeverity> = {
[ESCaseSeverity.LOW]: CaseSeverity.LOW,
[ESCaseSeverity.MEDIUM]: CaseSeverity.MEDIUM,
[ESCaseSeverity.HIGH]: CaseSeverity.HIGH,
[ESCaseSeverity.CRITICAL]: CaseSeverity.CRITICAL,
export const SEVERITY_ESMODEL_TO_EXTERNAL: Record<CasePersistedSeverity, CaseSeverity> = {
[CasePersistedSeverity.LOW]: CaseSeverity.LOW,
[CasePersistedSeverity.MEDIUM]: CaseSeverity.MEDIUM,
[CasePersistedSeverity.HIGH]: CaseSeverity.HIGH,
[CasePersistedSeverity.CRITICAL]: CaseSeverity.CRITICAL,
};
export const STATUS_EXTERNAL_TO_ESMODEL: Record<CaseStatuses, ESCaseStatus> = {
[CaseStatuses.open]: ESCaseStatus.OPEN,
[CaseStatuses['in-progress']]: ESCaseStatus.IN_PROGRESS,
[CaseStatuses.closed]: ESCaseStatus.CLOSED,
export const STATUS_EXTERNAL_TO_ESMODEL: Record<CaseStatuses, CasePersistedStatus> = {
[CaseStatuses.open]: CasePersistedStatus.OPEN,
[CaseStatuses['in-progress']]: CasePersistedStatus.IN_PROGRESS,
[CaseStatuses.closed]: CasePersistedStatus.CLOSED,
};
export const STATUS_ESMODEL_TO_EXTERNAL: Record<ESCaseStatus, CaseStatuses> = {
[ESCaseStatus.OPEN]: CaseStatuses.open,
[ESCaseStatus.IN_PROGRESS]: CaseStatuses['in-progress'],
[ESCaseStatus.CLOSED]: CaseStatuses.closed,
export const STATUS_ESMODEL_TO_EXTERNAL: Record<CasePersistedStatus, CaseStatuses> = {
[CasePersistedStatus.OPEN]: CaseStatuses.open,
[CasePersistedStatus.IN_PROGRESS]: CaseStatuses['in-progress'],
[CasePersistedStatus.CLOSED]: CaseStatuses.closed,
};

View file

@ -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<CaseResponse> {
public async encodeWithComments(): Promise<Case> {
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}`,

View file

@ -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<SavedObjectFindOptions, 'filter'> & {
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<CaseAttributes>;
export type FileAttachmentRequest = Omit<
CommentRequestExternalReferenceSOType,
'externalReferenceMetadata'

View file

@ -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<string, JsonValue> | null;
externalReferenceAttachmentTypeId?: string;
externalReferenceStorage?: {
type: string;
soType?: string;
};
persistableStateAttachmentState?: Record<string, JsonValue>;
persistableStateAttachmentTypeId?: string;
}
export type AttachmentPersistedAttributes = AttachmentRequestAttributes &
AttachmentCommonPersistedAttributes;

View file

@ -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<CasePersistedAttributes>;
export type CaseSavedObjectTransformed = SavedObject<CaseTransformedAttributes>;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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<string, unknown>;
}

View file

@ -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<string, CaseResponse>(
const casesMap = new Map<string, Case>(
mockCases.map((obj) => {
return [obj.id, flattenCaseSavedObject({ savedObject: obj, totalComment: 2 })];
})

View file

@ -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<string, CaseResponse>;
casesMap: Map<string, Case>;
countOpenCases: number;
countInProgressCases: number;
countClosedCases: number;
@ -120,11 +118,11 @@ export const flattenCaseSavedObject = ({
totalComment = comments.length,
totalAlerts = 0,
}: {
savedObject: CaseSavedObject;
savedObject: CaseSavedObjectTransformed;
comments?: Array<SavedObject<CommentAttributes>>;
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<CommentRequest>
): context is CommentRequestExternalReferenceSOType => {
return (
context.type === CommentType.externalReference &&
context.externalReferenceStorage?.type === ExternalReferenceStorageType.savedObject
);
};
/**
* A type narrowing function for file attachments.
*/

View file

@ -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 });
});

View file

@ -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 });
});

Some files were not shown because too many files have changed in this diff Show more