[SIEM] [Cases] External services not getting all comments bug fix (#65307)
This commit is contained in:
parent
c00b36e9e3
commit
c03bdccce1
|
@ -50,19 +50,11 @@ export const REOPENED_CASES = ({
|
|||
defaultMessage: 'Reopened {totalCases, plural, =1 {"{caseTitle}"} other {{totalCases} cases}}',
|
||||
});
|
||||
|
||||
export const TAG_FETCH_FAILURE = i18n.translate(
|
||||
'xpack.siem.containers.case.tagFetchFailDescription',
|
||||
{
|
||||
defaultMessage: 'Failed to fetch Tags',
|
||||
}
|
||||
);
|
||||
|
||||
export const SUCCESS_SEND_TO_EXTERNAL_SERVICE = i18n.translate(
|
||||
'xpack.siem.containers.case.pushToExterService',
|
||||
{
|
||||
defaultMessage: 'Successfully sent to ServiceNow',
|
||||
}
|
||||
);
|
||||
export const SUCCESS_SEND_TO_EXTERNAL_SERVICE = (serviceName: string) =>
|
||||
i18n.translate('xpack.siem.containers.case.pushToExternalService', {
|
||||
values: { serviceName },
|
||||
defaultMessage: 'Successfully sent to { serviceName }',
|
||||
});
|
||||
|
||||
export const ERROR_PUSH_TO_SERVICE = i18n.translate(
|
||||
'xpack.siem.case.configure.errorPushingToService',
|
||||
|
|
|
@ -122,13 +122,14 @@ describe('useGetCaseUserActions', () => {
|
|||
...basicPush,
|
||||
firstPushIndex: 3,
|
||||
lastPushIndex: 3,
|
||||
commentsToUpdate: [],
|
||||
hasDataToPush: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Correctly marks first/last index - hasDataToPush: true', () => {
|
||||
it('Correctly marks first/last index and comment id - hasDataToPush: true', () => {
|
||||
const userActions = [
|
||||
...caseUserActions,
|
||||
getUserAction(['pushed'], 'push-to-service'),
|
||||
|
@ -142,6 +143,83 @@ describe('useGetCaseUserActions', () => {
|
|||
...basicPush,
|
||||
firstPushIndex: 3,
|
||||
lastPushIndex: 3,
|
||||
commentsToUpdate: [userActions[userActions.length - 1].commentId],
|
||||
hasDataToPush: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Correctly marks first/last index and multiple comment ids, both needs push', () => {
|
||||
const userActions = [
|
||||
...caseUserActions,
|
||||
getUserAction(['pushed'], 'push-to-service'),
|
||||
getUserAction(['comment'], 'create'),
|
||||
{ ...getUserAction(['comment'], 'create'), commentId: 'muahaha' },
|
||||
];
|
||||
const result = getPushedInfo(userActions, '123');
|
||||
expect(result).toEqual({
|
||||
hasDataToPush: true,
|
||||
caseServices: {
|
||||
'123': {
|
||||
...basicPush,
|
||||
firstPushIndex: 3,
|
||||
lastPushIndex: 3,
|
||||
commentsToUpdate: [
|
||||
userActions[userActions.length - 2].commentId,
|
||||
userActions[userActions.length - 1].commentId,
|
||||
],
|
||||
hasDataToPush: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Correctly marks first/last index and multiple comment ids, one needs push', () => {
|
||||
const userActions = [
|
||||
...caseUserActions,
|
||||
getUserAction(['pushed'], 'push-to-service'),
|
||||
getUserAction(['comment'], 'create'),
|
||||
getUserAction(['pushed'], 'push-to-service'),
|
||||
{ ...getUserAction(['comment'], 'create'), commentId: 'muahaha' },
|
||||
];
|
||||
const result = getPushedInfo(userActions, '123');
|
||||
expect(result).toEqual({
|
||||
hasDataToPush: true,
|
||||
caseServices: {
|
||||
'123': {
|
||||
...basicPush,
|
||||
firstPushIndex: 3,
|
||||
lastPushIndex: 5,
|
||||
commentsToUpdate: [userActions[userActions.length - 1].commentId],
|
||||
hasDataToPush: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Correctly marks first/last index and multiple comment ids, one needs push and one needs update', () => {
|
||||
const userActions = [
|
||||
...caseUserActions,
|
||||
getUserAction(['pushed'], 'push-to-service'),
|
||||
getUserAction(['comment'], 'create'),
|
||||
getUserAction(['pushed'], 'push-to-service'),
|
||||
{ ...getUserAction(['comment'], 'create'), commentId: 'muahaha' },
|
||||
getUserAction(['comment'], 'update'),
|
||||
getUserAction(['comment'], 'update'),
|
||||
];
|
||||
const result = getPushedInfo(userActions, '123');
|
||||
expect(result).toEqual({
|
||||
hasDataToPush: true,
|
||||
caseServices: {
|
||||
'123': {
|
||||
...basicPush,
|
||||
firstPushIndex: 3,
|
||||
lastPushIndex: 5,
|
||||
commentsToUpdate: [
|
||||
userActions[userActions.length - 3].commentId,
|
||||
userActions[userActions.length - 1].commentId,
|
||||
],
|
||||
hasDataToPush: true,
|
||||
},
|
||||
},
|
||||
|
@ -162,6 +240,7 @@ describe('useGetCaseUserActions', () => {
|
|||
...basicPush,
|
||||
firstPushIndex: 3,
|
||||
lastPushIndex: 3,
|
||||
commentsToUpdate: [],
|
||||
hasDataToPush: false,
|
||||
},
|
||||
},
|
||||
|
@ -182,11 +261,34 @@ describe('useGetCaseUserActions', () => {
|
|||
...basicPush,
|
||||
firstPushIndex: 3,
|
||||
lastPushIndex: 5,
|
||||
commentsToUpdate: [],
|
||||
hasDataToPush: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
it('Correctly handles comment update with multiple push actions', () => {
|
||||
const userActions = [
|
||||
...caseUserActions,
|
||||
getUserAction(['pushed'], 'push-to-service'),
|
||||
getUserAction(['comment'], 'create'),
|
||||
getUserAction(['pushed'], 'push-to-service'),
|
||||
getUserAction(['comment'], 'update'),
|
||||
];
|
||||
const result = getPushedInfo(userActions, '123');
|
||||
expect(result).toEqual({
|
||||
hasDataToPush: true,
|
||||
caseServices: {
|
||||
'123': {
|
||||
...basicPush,
|
||||
firstPushIndex: 3,
|
||||
lastPushIndex: 5,
|
||||
commentsToUpdate: [userActions[userActions.length - 1].commentId],
|
||||
hasDataToPush: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Multiple connector tracking - hasDataToPush: true', () => {
|
||||
const pushAction123 = getUserAction(['pushed'], 'push-to-service');
|
||||
|
@ -215,6 +317,7 @@ describe('useGetCaseUserActions', () => {
|
|||
...basicPush,
|
||||
firstPushIndex: 3,
|
||||
lastPushIndex: 3,
|
||||
commentsToUpdate: [userActions[userActions.length - 2].commentId],
|
||||
hasDataToPush: true,
|
||||
},
|
||||
'456': {
|
||||
|
@ -224,6 +327,7 @@ describe('useGetCaseUserActions', () => {
|
|||
externalId: 'other_external_id',
|
||||
firstPushIndex: 5,
|
||||
lastPushIndex: 5,
|
||||
commentsToUpdate: [],
|
||||
hasDataToPush: false,
|
||||
},
|
||||
},
|
||||
|
@ -257,6 +361,7 @@ describe('useGetCaseUserActions', () => {
|
|||
...basicPush,
|
||||
firstPushIndex: 3,
|
||||
lastPushIndex: 3,
|
||||
commentsToUpdate: [userActions[userActions.length - 2].commentId],
|
||||
hasDataToPush: true,
|
||||
},
|
||||
'456': {
|
||||
|
@ -266,6 +371,7 @@ describe('useGetCaseUserActions', () => {
|
|||
externalId: 'other_external_id',
|
||||
firstPushIndex: 5,
|
||||
lastPushIndex: 5,
|
||||
commentsToUpdate: [],
|
||||
hasDataToPush: false,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -14,9 +14,10 @@ import { CaseExternalService, CaseUserActions, ElasticUser } from './types';
|
|||
import { convertToCamelCase, parseString } from './utils';
|
||||
import { CaseFullExternalService } from '../../../../case/common/api/cases';
|
||||
|
||||
interface CaseService extends CaseExternalService {
|
||||
export interface CaseService extends CaseExternalService {
|
||||
firstPushIndex: number;
|
||||
lastPushIndex: number;
|
||||
commentsToUpdate: string[];
|
||||
hasDataToPush: boolean;
|
||||
}
|
||||
|
||||
|
@ -48,6 +49,10 @@ export interface UseGetCaseUserActions extends CaseUserActionsState {
|
|||
|
||||
const getExternalService = (value: string): CaseExternalService | null =>
|
||||
convertToCamelCase<CaseFullExternalService, CaseExternalService>(parseString(`${value}`));
|
||||
interface CommentsAndIndex {
|
||||
commentId: string;
|
||||
commentIndex: number;
|
||||
}
|
||||
|
||||
export const getPushedInfo = (
|
||||
caseUserActions: CaseUserActions[],
|
||||
|
@ -69,11 +74,25 @@ export const getPushedInfo = (
|
|||
.action !== 'push-to-service'
|
||||
);
|
||||
};
|
||||
const commentsAndIndex = caseUserActions.reduce<CommentsAndIndex[]>(
|
||||
(bacc, mua, index) =>
|
||||
mua.actionField[0] === 'comment' && mua.commentId != null
|
||||
? [
|
||||
...bacc,
|
||||
{
|
||||
commentId: mua.commentId,
|
||||
commentIndex: index,
|
||||
},
|
||||
]
|
||||
: bacc,
|
||||
[]
|
||||
);
|
||||
|
||||
const caseServices = caseUserActions.reduce<CaseServices>((acc, cua, i) => {
|
||||
let caseServices = caseUserActions.reduce<CaseServices>((acc, cua, i) => {
|
||||
if (cua.action !== 'push-to-service') {
|
||||
return acc;
|
||||
}
|
||||
|
||||
const externalService = getExternalService(`${cua.newValue}`);
|
||||
if (externalService === null) {
|
||||
return acc;
|
||||
|
@ -87,6 +106,7 @@ export const getPushedInfo = (
|
|||
...acc[externalService.connectorId],
|
||||
...externalService,
|
||||
lastPushIndex: i,
|
||||
commentsToUpdate: [],
|
||||
},
|
||||
}
|
||||
: {
|
||||
|
@ -95,11 +115,31 @@ export const getPushedInfo = (
|
|||
firstPushIndex: i,
|
||||
lastPushIndex: i,
|
||||
hasDataToPush: hasDataToPushForConnector(externalService.connectorId),
|
||||
commentsToUpdate: [],
|
||||
},
|
||||
}),
|
||||
};
|
||||
}, {});
|
||||
|
||||
caseServices = Object.keys(caseServices).reduce<CaseServices>((acc, key) => {
|
||||
return {
|
||||
...acc,
|
||||
[key]: {
|
||||
...caseServices[key],
|
||||
// if the comment happens after the lastUpdateToCaseIndex, it should be included in commentsToUpdate
|
||||
commentsToUpdate: commentsAndIndex.reduce<string[]>(
|
||||
(bacc, currentComment) =>
|
||||
currentComment.commentIndex > caseServices[key].lastPushIndex
|
||||
? bacc.indexOf(currentComment.commentId) > -1
|
||||
? [...bacc.filter(e => e !== currentComment.commentId), currentComment.commentId]
|
||||
: [...bacc, currentComment.commentId]
|
||||
: bacc,
|
||||
[]
|
||||
),
|
||||
},
|
||||
};
|
||||
}, {});
|
||||
|
||||
const hasDataToPush =
|
||||
caseServices[caseConnectorId] != null ? caseServices[caseConnectorId].hasDataToPush : true;
|
||||
return {
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
serviceConnectorUser,
|
||||
} from './mock';
|
||||
import * as api from './api';
|
||||
import { CaseServices } from './use_get_case_user_actions';
|
||||
|
||||
jest.mock('./api');
|
||||
|
||||
|
@ -32,6 +33,7 @@ describe('usePostPushToService', () => {
|
|||
...basicPush,
|
||||
firstPushIndex: 1,
|
||||
lastPushIndex: 1,
|
||||
commentsToUpdate: [basicComment.id],
|
||||
hasDataToPush: false,
|
||||
},
|
||||
},
|
||||
|
@ -64,6 +66,7 @@ describe('usePostPushToService', () => {
|
|||
...basicPush,
|
||||
firstPushIndex: 1,
|
||||
lastPushIndex: 1,
|
||||
commentsToUpdate: [basicComment.id],
|
||||
hasDataToPush: true,
|
||||
},
|
||||
'456': {
|
||||
|
@ -71,6 +74,7 @@ describe('usePostPushToService', () => {
|
|||
connectorId: '456',
|
||||
externalId: 'other_external_id',
|
||||
firstPushIndex: 4,
|
||||
commentsToUpdate: [basicComment.id],
|
||||
lastPushIndex: 6,
|
||||
hasDataToPush: false,
|
||||
},
|
||||
|
@ -127,6 +131,31 @@ describe('usePostPushToService', () => {
|
|||
await waitForNextUpdate();
|
||||
expect(spyOnPushToService).toBeCalledWith(
|
||||
samplePush.connectorId,
|
||||
formatServiceRequestData(basicCase, '123', sampleCaseServices as CaseServices),
|
||||
abortCtrl.signal
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('calls pushToService with correct arguments when no push history', async () => {
|
||||
const samplePush2 = {
|
||||
caseId: pushedCase.id,
|
||||
caseServices: {},
|
||||
connectorName: 'connector name',
|
||||
connectorId: 'none',
|
||||
updateCase,
|
||||
};
|
||||
const spyOnPushToService = jest.spyOn(api, 'pushToService');
|
||||
|
||||
await act(async () => {
|
||||
const { result, waitForNextUpdate } = renderHook<string, UsePostPushToService>(() =>
|
||||
usePostPushToService()
|
||||
);
|
||||
await waitForNextUpdate();
|
||||
result.current.postPushToService(samplePush2);
|
||||
await waitForNextUpdate();
|
||||
expect(spyOnPushToService).toBeCalledWith(
|
||||
samplePush2.connectorId,
|
||||
formatServiceRequestData(basicCase, 'none', {}),
|
||||
abortCtrl.signal
|
||||
);
|
||||
|
|
|
@ -122,7 +122,10 @@ export const usePostPushToService = (): UsePostPushToService => {
|
|||
dispatch({ type: 'FETCH_SUCCESS_PUSH_SERVICE', payload: responseService });
|
||||
dispatch({ type: 'FETCH_SUCCESS_PUSH_CASE', payload: responseCase });
|
||||
updateCase(responseCase);
|
||||
displaySuccessToast(i18n.SUCCESS_SEND_TO_EXTERNAL_SERVICE, dispatchToaster);
|
||||
displaySuccessToast(
|
||||
i18n.SUCCESS_SEND_TO_EXTERNAL_SERVICE(connectorName),
|
||||
dispatchToaster
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (!cancel) {
|
||||
|
@ -156,25 +159,12 @@ export const formatServiceRequestData = (
|
|||
createdBy,
|
||||
comments,
|
||||
description,
|
||||
externalService,
|
||||
title,
|
||||
updatedAt,
|
||||
updatedBy,
|
||||
} = myCase;
|
||||
let actualExternalService = externalService;
|
||||
if (
|
||||
externalService != null &&
|
||||
externalService.connectorId !== connectorId &&
|
||||
caseServices[connectorId]
|
||||
) {
|
||||
actualExternalService = caseServices[connectorId];
|
||||
} else if (
|
||||
externalService != null &&
|
||||
externalService.connectorId !== connectorId &&
|
||||
!caseServices[connectorId]
|
||||
) {
|
||||
actualExternalService = null;
|
||||
}
|
||||
const actualExternalService = caseServices[connectorId] ?? null;
|
||||
|
||||
return {
|
||||
caseId,
|
||||
createdAt,
|
||||
|
@ -183,17 +173,9 @@ export const formatServiceRequestData = (
|
|||
username: createdBy?.username ?? '',
|
||||
},
|
||||
comments: comments
|
||||
.filter(c => {
|
||||
const lastPush = c.pushedAt != null ? new Date(c.pushedAt) : null;
|
||||
const lastUpdate = c.updatedAt != null ? new Date(c.updatedAt) : null;
|
||||
if (
|
||||
lastPush === null ||
|
||||
(lastPush != null && lastUpdate != null && lastPush.getTime() < lastUpdate?.getTime())
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.filter(
|
||||
c => actualExternalService == null || actualExternalService.commentsToUpdate.includes(c.id)
|
||||
)
|
||||
.map(c => ({
|
||||
commentId: c.id,
|
||||
comment: c.comment,
|
||||
|
|
|
@ -20,6 +20,7 @@ import * as i18n from '../case_view/translations';
|
|||
import { FormattedRelativePreferenceDate } from '../../../../components/formatted_date';
|
||||
import { CaseViewActions } from '../case_view/actions';
|
||||
import { Case } from '../../../../containers/case/types';
|
||||
import { CaseService } from '../../../../containers/case/use_get_case_user_actions';
|
||||
|
||||
const MyDescriptionList = styled(EuiDescriptionList)`
|
||||
${({ theme }) => css`
|
||||
|
@ -35,6 +36,7 @@ interface CaseStatusProps {
|
|||
badgeColor: string;
|
||||
buttonLabel: string;
|
||||
caseData: Case;
|
||||
currentExternalIncident: CaseService | null;
|
||||
disabled?: boolean;
|
||||
icon: string;
|
||||
isLoading: boolean;
|
||||
|
@ -50,6 +52,7 @@ const CaseStatusComp: React.FC<CaseStatusProps> = ({
|
|||
badgeColor,
|
||||
buttonLabel,
|
||||
caseData,
|
||||
currentExternalIncident,
|
||||
disabled = false,
|
||||
icon,
|
||||
isLoading,
|
||||
|
@ -100,7 +103,11 @@ const CaseStatusComp: React.FC<CaseStatusProps> = ({
|
|||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<CaseViewActions caseData={caseData} disabled={disabled} />
|
||||
<CaseViewActions
|
||||
caseData={caseData}
|
||||
currentExternalIncident={currentExternalIncident}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
|
|
|
@ -9,8 +9,9 @@ import { mount } from 'enzyme';
|
|||
|
||||
import { useDeleteCases } from '../../../../containers/case/use_delete_cases';
|
||||
import { TestProviders } from '../../../../mock';
|
||||
import { basicCase } from '../../../../containers/case/mock';
|
||||
import { basicCase, basicPush } from '../../../../containers/case/mock';
|
||||
import { CaseViewActions } from './actions';
|
||||
import * as i18n from './translations';
|
||||
jest.mock('../../../../containers/case/use_delete_cases');
|
||||
const useDeleteCasesMock = useDeleteCases as jest.Mock;
|
||||
|
||||
|
@ -34,7 +35,7 @@ describe('CaseView actions', () => {
|
|||
it('clicking trash toggles modal', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<CaseViewActions caseData={basicCase} />
|
||||
<CaseViewActions caseData={basicCase} currentExternalIncident={null} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
@ -54,7 +55,7 @@ describe('CaseView actions', () => {
|
|||
}));
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<CaseViewActions caseData={basicCase} />
|
||||
<CaseViewActions caseData={basicCase} currentExternalIncident={null} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
@ -64,4 +65,33 @@ describe('CaseView actions', () => {
|
|||
{ id: basicCase.id, title: basicCase.title },
|
||||
]);
|
||||
});
|
||||
it('displays active incident link', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<CaseViewActions
|
||||
caseData={basicCase}
|
||||
currentExternalIncident={{
|
||||
...basicPush,
|
||||
firstPushIndex: 5,
|
||||
lastPushIndex: 5,
|
||||
commentsToUpdate: [],
|
||||
hasDataToPush: false,
|
||||
}}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="confirm-delete-case-modal"]').exists()).toBeFalsy();
|
||||
|
||||
wrapper
|
||||
.find('button[data-test-subj="property-actions-ellipses"]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
expect(
|
||||
wrapper
|
||||
.find('[data-test-subj="property-actions-popout"]')
|
||||
.first()
|
||||
.prop('aria-label')
|
||||
).toEqual(i18n.VIEW_INCIDENT(basicPush.externalTitle));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,13 +13,19 @@ import { ConfirmDeleteCaseModal } from '../confirm_delete_case';
|
|||
import { SiemPageName } from '../../../home/types';
|
||||
import { PropertyActions } from '../property_actions';
|
||||
import { Case } from '../../../../containers/case/types';
|
||||
import { CaseService } from '../../../../containers/case/use_get_case_user_actions';
|
||||
|
||||
interface CaseViewActions {
|
||||
caseData: Case;
|
||||
currentExternalIncident: CaseService | null;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const CaseViewActionsComponent: React.FC<CaseViewActions> = ({ caseData, disabled = false }) => {
|
||||
const CaseViewActionsComponent: React.FC<CaseViewActions> = ({
|
||||
caseData,
|
||||
currentExternalIncident,
|
||||
disabled = false,
|
||||
}) => {
|
||||
// Delete case
|
||||
const {
|
||||
handleToggleModal,
|
||||
|
@ -48,17 +54,17 @@ const CaseViewActionsComponent: React.FC<CaseViewActions> = ({ caseData, disable
|
|||
label: i18n.DELETE_CASE,
|
||||
onClick: handleToggleModal,
|
||||
},
|
||||
...(caseData.externalService != null && !isEmpty(caseData.externalService?.externalUrl)
|
||||
...(currentExternalIncident != null && !isEmpty(currentExternalIncident?.externalUrl)
|
||||
? [
|
||||
{
|
||||
iconType: 'popout',
|
||||
label: i18n.VIEW_INCIDENT(caseData.externalService?.externalTitle ?? ''),
|
||||
onClick: () => window.open(caseData.externalService?.externalUrl, '_blank'),
|
||||
label: i18n.VIEW_INCIDENT(currentExternalIncident?.externalTitle ?? ''),
|
||||
onClick: () => window.open(currentExternalIncident?.externalUrl, '_blank'),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
[disabled, handleToggleModal, caseData]
|
||||
[disabled, handleToggleModal, currentExternalIncident]
|
||||
);
|
||||
|
||||
if (isDeleted) {
|
||||
|
|
|
@ -70,6 +70,7 @@ describe('CaseView ', () => {
|
|||
|
||||
const defaultUseGetCaseUserActions = {
|
||||
caseUserActions,
|
||||
caseServices: {},
|
||||
fetchCaseUserActions,
|
||||
firstIndexPushToService: -1,
|
||||
hasDataToPush: false,
|
||||
|
|
|
@ -164,6 +164,15 @@ export const CaseComponent = React.memo<CaseProps>(
|
|||
() => connectors.find(c => c.id === caseData.connectorId)?.name ?? 'none',
|
||||
[connectors, caseData.connectorId]
|
||||
);
|
||||
|
||||
const currentExternalIncident = useMemo(
|
||||
() =>
|
||||
caseServices != null && caseServices[caseData.connectorId] != null
|
||||
? caseServices[caseData.connectorId]
|
||||
: null,
|
||||
[caseServices, caseData.connectorId]
|
||||
);
|
||||
|
||||
const { pushButton, pushCallouts } = usePushToService({
|
||||
caseConnectorId: caseData.connectorId,
|
||||
caseConnectorName,
|
||||
|
@ -254,6 +263,7 @@ export const CaseComponent = React.memo<CaseProps>(
|
|||
title={caseData.title}
|
||||
>
|
||||
<CaseStatus
|
||||
currentExternalIncident={currentExternalIncident}
|
||||
caseData={caseData}
|
||||
disabled={!userCanCrud}
|
||||
isLoading={isLoading && updateKey === 'status'}
|
||||
|
|
|
@ -32,7 +32,7 @@ export const getKibanaConfigError = () => ({
|
|||
title: i18n.PUSH_DISABLE_BY_KIBANA_CONFIG_TITLE,
|
||||
description: (
|
||||
<FormattedMessage
|
||||
defaultMessage="The kibana.yml file is configured to only allow specific connectors. To enable opening a case in external systems, add .servicenow to the xpack.actions.enabledActiontypes setting. For more information, see {link}."
|
||||
defaultMessage="The kibana.yml file is configured to only allow specific connectors. To enable opening a case in external systems, add .[actionTypeId] (ex: .servicenow | .jira) to the xpack.actions.enabledActiontypes setting. For more information, see {link}."
|
||||
id="xpack.siem.case.caseView.pushToServiceDisableByConfigDescription"
|
||||
values={{
|
||||
link: (
|
||||
|
|
|
@ -33,6 +33,7 @@ describe('usePushToService', () => {
|
|||
...basicPush,
|
||||
firstPushIndex: 0,
|
||||
lastPushIndex: 0,
|
||||
commentsToUpdate: [],
|
||||
hasDataToPush: true,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -60,7 +60,7 @@ export const PUSH_DISABLE_BECAUSE_CASE_CLOSED_TITLE = i18n.translate(
|
|||
export const PUSH_DISABLE_BY_KIBANA_CONFIG_TITLE = i18n.translate(
|
||||
'xpack.siem.case.caseView.pushToServiceDisableByConfigTitle',
|
||||
{
|
||||
defaultMessage: 'Enable ServiceNow in Kibana configuration file',
|
||||
defaultMessage: 'Enable external service in Kibana configuration file',
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ describe('UserActionTree ', () => {
|
|||
...basicPush,
|
||||
firstPushIndex: 0,
|
||||
lastPushIndex: 0,
|
||||
commentsToUpdate: [`${ourActions[ourActions.length - 1].commentId}`],
|
||||
hasDataToPush: true,
|
||||
},
|
||||
},
|
||||
|
@ -111,6 +112,7 @@ describe('UserActionTree ', () => {
|
|||
...basicPush,
|
||||
firstPushIndex: 0,
|
||||
lastPushIndex: 0,
|
||||
commentsToUpdate: [],
|
||||
hasDataToPush: false,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -13281,8 +13281,6 @@
|
|||
"xpack.siem.containers.anomalies.stackByJobId": "ジョブ",
|
||||
"xpack.siem.containers.anomalies.title": "異常",
|
||||
"xpack.siem.containers.case.errorTitle": "データの取得中にエラーが発生",
|
||||
"xpack.siem.containers.case.pushToExterService": "ServiceNow への送信が正常に完了しました",
|
||||
"xpack.siem.containers.case.tagFetchFailDescription": "タグを取得できませんでした",
|
||||
"xpack.siem.containers.detectionEngine.addRuleFailDescription": "ルールを追加できませんでした",
|
||||
"xpack.siem.containers.detectionEngine.createPrePackagedRuleFailDescription": "Elasticから事前にパッケージ化されているルールをインストールすることができませんでした",
|
||||
"xpack.siem.containers.detectionEngine.createPrePackagedRuleSuccesDescription": "Elasticから事前にパッケージ化されているルールをインストールしました",
|
||||
|
|
|
@ -13288,8 +13288,6 @@
|
|||
"xpack.siem.containers.anomalies.stackByJobId": "作业",
|
||||
"xpack.siem.containers.anomalies.title": "异常",
|
||||
"xpack.siem.containers.case.errorTitle": "提取数据时出错",
|
||||
"xpack.siem.containers.case.pushToExterService": "已成功发送到 ServiceNow",
|
||||
"xpack.siem.containers.case.tagFetchFailDescription": "无法提取标记",
|
||||
"xpack.siem.containers.detectionEngine.addRuleFailDescription": "无法添加规则",
|
||||
"xpack.siem.containers.detectionEngine.createPrePackagedRuleFailDescription": "无法安装 elastic 的预打包规则",
|
||||
"xpack.siem.containers.detectionEngine.createPrePackagedRuleSuccesDescription": "已安装 elastic 的预打包规则",
|
||||
|
|
Loading…
Reference in a new issue