From 3e885c195216bf0c29ed2abe721be82a0d53b600 Mon Sep 17 00:00:00 2001 From: stephmilovic Date: Tue, 5 May 2020 10:55:14 -0600 Subject: [PATCH 1/7] bug fixing --- .../public/containers/case/translations.ts | 18 +++----- .../case/use_get_case_user_actions.tsx | 44 +++++++++++++++++++ .../case/use_post_push_to_service.tsx | 37 +++++----------- .../use_push_to_service/helpers.tsx | 2 +- .../use_push_to_service/translations.ts | 2 +- .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 7 files changed, 61 insertions(+), 46 deletions(-) diff --git a/x-pack/plugins/siem/public/containers/case/translations.ts b/x-pack/plugins/siem/public/containers/case/translations.ts index d5ea287fd2cdd..79edcc56b0362 100644 --- a/x-pack/plugins/siem/public/containers/case/translations.ts +++ b/x-pack/plugins/siem/public/containers/case/translations.ts @@ -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', diff --git a/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx b/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx index a2290f946be9b..97f1d55f822d6 100644 --- a/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx +++ b/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx @@ -17,6 +17,7 @@ import { CaseFullExternalService } from '../../../../case/common/api/cases'; interface CaseService extends CaseExternalService { firstPushIndex: number; lastPushIndex: number; + commentsToUpdate: string[]; hasDataToPush: boolean; } @@ -69,11 +70,30 @@ export const getPushedInfo = ( .action !== 'push-to-service' ); }; + const commentsAndIndex = caseUserActions.reduce< + Array<{ + commentId: string; + commentIndex: number; + }> + >( + (bacc, mua, index) => + mua.actionField[0] === 'comment' && mua.commentId != null + ? [ + ...bacc, + { + commentId: mua.commentId, + commentIndex: index, + }, + ] + : bacc, + [] + ); const caseServices = caseUserActions.reduce((acc, cua, i) => { if (cua.action !== 'push-to-service') { return acc; } + const externalService = getExternalService(`${cua.newValue}`); if (externalService === null) { return acc; @@ -87,6 +107,18 @@ export const getPushedInfo = ( ...acc[externalService.connectorId], ...externalService, lastPushIndex: i, + commentsToUpdate: commentsAndIndex.reduce( + (bacc, currentComment) => + currentComment.commentIndex > i + ? bacc.indexOf(currentComment.commentId) > -1 + ? [ + ...bacc.filter(e => e !== currentComment.commentId), + currentComment.commentId, + ] + : [...bacc, currentComment.commentId] + : bacc, + [] + ), }, } : { @@ -95,6 +127,18 @@ export const getPushedInfo = ( firstPushIndex: i, lastPushIndex: i, hasDataToPush: hasDataToPushForConnector(externalService.connectorId), + commentsToUpdate: commentsAndIndex.reduce( + (bacc, currentComment) => + currentComment.commentIndex > i + ? bacc.indexOf(currentComment.commentId) > -1 + ? [ + ...bacc.filter(e => e !== currentComment.commentId), + currentComment.commentId, + ] + : [...bacc, currentComment.commentId] + : bacc, + [] + ), }, }), }; diff --git a/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.tsx b/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.tsx index 3d0836cdc8adf..0eb2730c54029 100644 --- a/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.tsx +++ b/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.tsx @@ -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,13 @@ 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 +174,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, diff --git a/x-pack/plugins/siem/public/pages/case/components/use_push_to_service/helpers.tsx b/x-pack/plugins/siem/public/pages/case/components/use_push_to_service/helpers.tsx index 1e4fd92058e8d..0613c40d1181d 100644 --- a/x-pack/plugins/siem/public/pages/case/components/use_push_to_service/helpers.tsx +++ b/x-pack/plugins/siem/public/pages/case/components/use_push_to_service/helpers.tsx @@ -32,7 +32,7 @@ export const getKibanaConfigError = () => ({ title: i18n.PUSH_DISABLE_BY_KIBANA_CONFIG_TITLE, description: ( Date: Tue, 5 May 2020 13:08:31 -0600 Subject: [PATCH 2/7] tests --- .../case/use_get_case_user_actions.test.tsx | 108 +++++++++++++++++- .../case/use_post_push_to_service.test.tsx | 29 +++++ .../case/use_post_push_to_service.tsx | 1 - .../use_push_to_service/index.test.tsx | 1 + .../user_action_tree/index.test.tsx | 2 + 5 files changed, 139 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.test.tsx b/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.test.tsx index 0848d12c8d308..1603beddbb1dc 100644 --- a/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.test.tsx +++ b/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.test.tsx @@ -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, }, }, diff --git a/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.test.tsx b/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.test.tsx index 72609e15d1ec4..96fa824c1cadd 100644 --- a/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.test.tsx +++ b/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.test.tsx @@ -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(() => + usePostPushToService() + ); + await waitForNextUpdate(); + result.current.postPushToService(samplePush2); + await waitForNextUpdate(); + expect(spyOnPushToService).toBeCalledWith( + samplePush2.connectorId, formatServiceRequestData(basicCase, 'none', {}), abortCtrl.signal ); diff --git a/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.tsx b/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.tsx index 0eb2730c54029..7f4c4a4276172 100644 --- a/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.tsx +++ b/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.tsx @@ -163,7 +163,6 @@ export const formatServiceRequestData = ( updatedAt, updatedBy, } = myCase; - const actualExternalService = caseServices[connectorId] ?? null; return { diff --git a/x-pack/plugins/siem/public/pages/case/components/use_push_to_service/index.test.tsx b/x-pack/plugins/siem/public/pages/case/components/use_push_to_service/index.test.tsx index b09c7d00140c3..b19c2dbf5273a 100644 --- a/x-pack/plugins/siem/public/pages/case/components/use_push_to_service/index.test.tsx +++ b/x-pack/plugins/siem/public/pages/case/components/use_push_to_service/index.test.tsx @@ -33,6 +33,7 @@ describe('usePushToService', () => { ...basicPush, firstPushIndex: 0, lastPushIndex: 0, + commentsToUpdate: [], hasDataToPush: true, }, }; diff --git a/x-pack/plugins/siem/public/pages/case/components/user_action_tree/index.test.tsx b/x-pack/plugins/siem/public/pages/case/components/user_action_tree/index.test.tsx index 736974545a1df..b9a94f83fded1 100644 --- a/x-pack/plugins/siem/public/pages/case/components/user_action_tree/index.test.tsx +++ b/x-pack/plugins/siem/public/pages/case/components/user_action_tree/index.test.tsx @@ -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, }, }, From 5922aa2d58a249e619ecb7e88f7a1420043f3fc7 Mon Sep 17 00:00:00 2001 From: stephmilovic Date: Tue, 5 May 2020 16:39:17 -0600 Subject: [PATCH 3/7] pr changeS --- .../case/use_get_case_user_actions.tsx | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx b/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx index 97f1d55f822d6..db9bbc684e5cc 100644 --- a/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx +++ b/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx @@ -49,6 +49,24 @@ export interface UseGetCaseUserActions extends CaseUserActionsState { const getExternalService = (value: string): CaseExternalService | null => convertToCamelCase(parseString(`${value}`)); +interface CommentsAndIndex { + commentId: string; + commentIndex: number; +} +// if the comment happens after the lastUpdateToCaseIndex, it should be included in commentsToUpdate +const buildCommentsToUpdate = ( + commentsAndIndex: CommentsAndIndex[], + lastUpdateToCaseIndex: number +) => + commentsAndIndex.reduce( + (bacc, currentComment) => + currentComment.commentIndex > lastUpdateToCaseIndex + ? bacc.indexOf(currentComment.commentId) > -1 + ? [...bacc.filter(e => e !== currentComment.commentId), currentComment.commentId] + : [...bacc, currentComment.commentId] + : bacc, + [] + ); export const getPushedInfo = ( caseUserActions: CaseUserActions[], @@ -70,12 +88,7 @@ export const getPushedInfo = ( .action !== 'push-to-service' ); }; - const commentsAndIndex = caseUserActions.reduce< - Array<{ - commentId: string; - commentIndex: number; - }> - >( + const commentsAndIndex = caseUserActions.reduce( (bacc, mua, index) => mua.actionField[0] === 'comment' && mua.commentId != null ? [ @@ -107,18 +120,7 @@ export const getPushedInfo = ( ...acc[externalService.connectorId], ...externalService, lastPushIndex: i, - commentsToUpdate: commentsAndIndex.reduce( - (bacc, currentComment) => - currentComment.commentIndex > i - ? bacc.indexOf(currentComment.commentId) > -1 - ? [ - ...bacc.filter(e => e !== currentComment.commentId), - currentComment.commentId, - ] - : [...bacc, currentComment.commentId] - : bacc, - [] - ), + commentsToUpdate: buildCommentsToUpdate(commentsAndIndex, i), }, } : { @@ -127,18 +129,7 @@ export const getPushedInfo = ( firstPushIndex: i, lastPushIndex: i, hasDataToPush: hasDataToPushForConnector(externalService.connectorId), - commentsToUpdate: commentsAndIndex.reduce( - (bacc, currentComment) => - currentComment.commentIndex > i - ? bacc.indexOf(currentComment.commentId) > -1 - ? [ - ...bacc.filter(e => e !== currentComment.commentId), - currentComment.commentId, - ] - : [...bacc, currentComment.commentId] - : bacc, - [] - ), + commentsToUpdate: buildCommentsToUpdate(commentsAndIndex, i), }, }), }; From e63e934d53e7902fde263df4d5efa7f65a61aedf Mon Sep 17 00:00:00 2001 From: stephmilovic Date: Wed, 6 May 2020 08:31:45 -0600 Subject: [PATCH 4/7] move reduce --- .../case/use_get_case_user_actions.tsx | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx b/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx index db9bbc684e5cc..bb2fdc60d1395 100644 --- a/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx +++ b/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx @@ -53,20 +53,6 @@ interface CommentsAndIndex { commentId: string; commentIndex: number; } -// if the comment happens after the lastUpdateToCaseIndex, it should be included in commentsToUpdate -const buildCommentsToUpdate = ( - commentsAndIndex: CommentsAndIndex[], - lastUpdateToCaseIndex: number -) => - commentsAndIndex.reduce( - (bacc, currentComment) => - currentComment.commentIndex > lastUpdateToCaseIndex - ? bacc.indexOf(currentComment.commentId) > -1 - ? [...bacc.filter(e => e !== currentComment.commentId), currentComment.commentId] - : [...bacc, currentComment.commentId] - : bacc, - [] - ); export const getPushedInfo = ( caseUserActions: CaseUserActions[], @@ -102,7 +88,7 @@ export const getPushedInfo = ( [] ); - const caseServices = caseUserActions.reduce((acc, cua, i) => { + let caseServices = caseUserActions.reduce((acc, cua, i) => { if (cua.action !== 'push-to-service') { return acc; } @@ -120,7 +106,7 @@ export const getPushedInfo = ( ...acc[externalService.connectorId], ...externalService, lastPushIndex: i, - commentsToUpdate: buildCommentsToUpdate(commentsAndIndex, i), + commentsToUpdate: [], }, } : { @@ -129,12 +115,31 @@ export const getPushedInfo = ( firstPushIndex: i, lastPushIndex: i, hasDataToPush: hasDataToPushForConnector(externalService.connectorId), - commentsToUpdate: buildCommentsToUpdate(commentsAndIndex, i), + commentsToUpdate: [], }, }), }; }, {}); + caseServices = Object.keys(caseServices).reduce((acc, key) => { + return { + ...acc, + [key]: { + ...caseServices[key], + // if the comment happens after the lastUpdateToCaseIndex, it should be included in commentsToUpdate + commentsToUpdate: commentsAndIndex.reduce( + (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 { From 00a687f907264314080a586b810742ccffc546ab Mon Sep 17 00:00:00 2001 From: stephmilovic Date: Wed, 6 May 2020 08:56:37 -0600 Subject: [PATCH 5/7] update property actions incident --- .../case/use_get_case_user_actions.tsx | 2 +- .../pages/case/components/case_status/index.tsx | 9 ++++++++- .../pages/case/components/case_view/actions.tsx | 16 +++++++++++----- .../pages/case/components/case_view/index.tsx | 6 ++++++ 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx b/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx index bb2fdc60d1395..5afe06a9828e5 100644 --- a/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx +++ b/x-pack/plugins/siem/public/containers/case/use_get_case_user_actions.tsx @@ -14,7 +14,7 @@ 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[]; diff --git a/x-pack/plugins/siem/public/pages/case/components/case_status/index.tsx b/x-pack/plugins/siem/public/pages/case/components/case_status/index.tsx index 718eb95767f2e..f48d9a68ffaf0 100644 --- a/x-pack/plugins/siem/public/pages/case/components/case_status/index.tsx +++ b/x-pack/plugins/siem/public/pages/case/components/case_status/index.tsx @@ -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 = ({ badgeColor, buttonLabel, caseData, + currentExternalIncident, disabled = false, icon, isLoading, @@ -100,7 +103,11 @@ const CaseStatusComp: React.FC = ({ /> - + diff --git a/x-pack/plugins/siem/public/pages/case/components/case_view/actions.tsx b/x-pack/plugins/siem/public/pages/case/components/case_view/actions.tsx index 216180eb2cf0a..4acdaef6ca51f 100644 --- a/x-pack/plugins/siem/public/pages/case/components/case_view/actions.tsx +++ b/x-pack/plugins/siem/public/pages/case/components/case_view/actions.tsx @@ -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 = ({ caseData, disabled = false }) => { +const CaseViewActionsComponent: React.FC = ({ + caseData, + currentExternalIncident, + disabled = false, +}) => { // Delete case const { handleToggleModal, @@ -48,17 +54,17 @@ const CaseViewActionsComponent: React.FC = ({ 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) { diff --git a/x-pack/plugins/siem/public/pages/case/components/case_view/index.tsx b/x-pack/plugins/siem/public/pages/case/components/case_view/index.tsx index 14039dc2cbc30..da9f76e729f5d 100644 --- a/x-pack/plugins/siem/public/pages/case/components/case_view/index.tsx +++ b/x-pack/plugins/siem/public/pages/case/components/case_view/index.tsx @@ -164,6 +164,11 @@ export const CaseComponent = React.memo( () => connectors.find(c => c.id === caseData.connectorId)?.name ?? 'none', [connectors, caseData.connectorId] ); + + const currentExternalIncident = useMemo(() => { + return caseServices[caseData.connectorId]; + }, [caseServices, caseData.connectorId]); + const { pushButton, pushCallouts } = usePushToService({ caseConnectorId: caseData.connectorId, caseConnectorName, @@ -254,6 +259,7 @@ export const CaseComponent = React.memo( title={caseData.title} > Date: Wed, 6 May 2020 11:05:00 -0600 Subject: [PATCH 6/7] fix type issue and add test --- .../components/case_view/actions.test.tsx | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/siem/public/pages/case/components/case_view/actions.test.tsx b/x-pack/plugins/siem/public/pages/case/components/case_view/actions.test.tsx index 8b6ee76dd783d..24fbd59b3282b 100644 --- a/x-pack/plugins/siem/public/pages/case/components/case_view/actions.test.tsx +++ b/x-pack/plugins/siem/public/pages/case/components/case_view/actions.test.tsx @@ -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( - + ); @@ -54,7 +55,7 @@ describe('CaseView actions', () => { })); const wrapper = mount( - + ); @@ -64,4 +65,33 @@ describe('CaseView actions', () => { { id: basicCase.id, title: basicCase.title }, ]); }); + it('displays active incident link', () => { + const wrapper = mount( + + + + ); + + 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)); + }); }); From f45320865b907f778e44a3f19250c49b5bf76e02 Mon Sep 17 00:00:00 2001 From: stephmilovic Date: Wed, 6 May 2020 14:13:40 -0600 Subject: [PATCH 7/7] fix test whoops --- .../pages/case/components/case_view/index.test.tsx | 1 + .../public/pages/case/components/case_view/index.tsx | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/siem/public/pages/case/components/case_view/index.test.tsx b/x-pack/plugins/siem/public/pages/case/components/case_view/index.test.tsx index 7ce9d7b8533e4..a6e6b19a071ce 100644 --- a/x-pack/plugins/siem/public/pages/case/components/case_view/index.test.tsx +++ b/x-pack/plugins/siem/public/pages/case/components/case_view/index.test.tsx @@ -70,6 +70,7 @@ describe('CaseView ', () => { const defaultUseGetCaseUserActions = { caseUserActions, + caseServices: {}, fetchCaseUserActions, firstIndexPushToService: -1, hasDataToPush: false, diff --git a/x-pack/plugins/siem/public/pages/case/components/case_view/index.tsx b/x-pack/plugins/siem/public/pages/case/components/case_view/index.tsx index da9f76e729f5d..fed8ec8edbe8b 100644 --- a/x-pack/plugins/siem/public/pages/case/components/case_view/index.tsx +++ b/x-pack/plugins/siem/public/pages/case/components/case_view/index.tsx @@ -165,9 +165,13 @@ export const CaseComponent = React.memo( [connectors, caseData.connectorId] ); - const currentExternalIncident = useMemo(() => { - return caseServices[caseData.connectorId]; - }, [caseServices, 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,