Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cases] Do not add already attached alerts to the case #154322

Merged
merged 29 commits into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ded8ba6
Convert usePostCase to react query
cnasikas Apr 3, 2023
ec27c8d
Get attachmetns after the creation/selection of the case
cnasikas Apr 3, 2023
fd46ee0
Filter out alerts that are already attached to the case
cnasikas Apr 3, 2023
ba55f1b
Merge branch 'main' into prevent_alerts_same_case
cnasikas Apr 4, 2023
96ca600
Revert create case flyout changes
cnasikas Apr 4, 2023
96ce67e
Fix types
cnasikas Apr 4, 2023
7294aba
Add tests
cnasikas Apr 4, 2023
4bcf6f8
Fix test
cnasikas Apr 4, 2023
296bb51
Merge branch 'main' into prevent_alerts_same_case
cnasikas Apr 5, 2023
ececbce
PR feedback
cnasikas Apr 6, 2023
88b2afb
Fix mutation key
cnasikas Apr 6, 2023
dc2f694
Merge branch 'main' into prevent_alerts_same_case
kibanamachine Apr 6, 2023
5867f8f
Merge branch 'main' into prevent_alerts_same_case
kibanamachine Apr 7, 2023
7e247a2
Merge branch 'main' into prevent_alerts_same_case
kibanamachine Apr 10, 2023
c85d731
Merge branch 'main' into prevent_alerts_same_case
cnasikas Apr 10, 2023
9c55506
Merge branch 'prevent_alerts_same_case' of github.com:cnasikas/kibana…
cnasikas Apr 10, 2023
fe6a63e
Show information toaster if no attachments are defined
cnasikas Apr 10, 2023
8d86cae
Fix test
cnasikas Apr 10, 2023
30e216b
Merge branch 'main' into prevent_alerts_same_case
cnasikas Apr 10, 2023
ef895ad
Merge branch 'main' into prevent_alerts_same_case
kibanamachine Apr 10, 2023
b414a59
Merge branch 'main' into prevent_alerts_same_case
kibanamachine Apr 11, 2023
c6ce336
Merge branch 'main' into prevent_alerts_same_case
kibanamachine Apr 11, 2023
e6152f8
fix osquery version
patrykkopycinski Apr 11, 2023
061eded
fix version
patrykkopycinski Apr 11, 2023
afe554f
Merge branch 'main' into prevent_alerts_same_case
patrykkopycinski Apr 11, 2023
a20de6c
fix osquery cypress
patrykkopycinski Apr 13, 2023
b5f9a73
osquery cypress pipeline
patrykkopycinski Apr 13, 2023
9e70861
Merge branch 'main' into prevent_alerts_same_case
kibanamachine Apr 13, 2023
e03b35e
Merge branch 'main' into prevent_alerts_same_case
patrykkopycinski Apr 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jest.mock('./all_cases_selector_modal', () => {
});

const onSuccess = jest.fn();
const getAttachments = jest.fn().mockReturnValue([alertComment]);
const useCasesToastMock = useCasesToast as jest.Mock;
const AllCasesSelectorModalMock = AllCasesSelectorModal as unknown as jest.Mock;

Expand All @@ -41,7 +42,7 @@ const TestComponent: React.FC = () => {
const hook = useCasesAddToExistingCaseModal({ onSuccess });

const onClick = () => {
hook.open({ attachments: [alertComment] });
hook.open({ getAttachments });
};

return <button type="button" data-test-subj="open-modal" onClick={onClick} />;
Expand Down Expand Up @@ -138,6 +139,21 @@ 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);
return null;
});

const result = appMockRender.render(<TestComponent />);
userEvent.click(result.getByTestId('open-modal'));

await waitFor(() => {
expect(getAttachments).toHaveBeenCalledTimes(1);
expect(getAttachments).toHaveBeenCalledWith({ theCase: { id: 'test' } });
});
});

it('should call createAttachments when a case is selected and show a toast message', async () => {
const mockBulkCreateAttachments = jest.fn();
useCreateAttachmentsMock.mockReturnValueOnce({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ export const useCasesAddToExistingCaseModal = (props: AddToExistingFlyoutProps =
}, [dispatch]);

const handleOnRowClick = useCallback(
async (theCase: Case | undefined, attachments: CaseAttachmentsWithoutOwner) => {
async (
theCase: Case | undefined,
getAttachments?: ({ theCase }: { theCase?: Case }) => CaseAttachmentsWithoutOwner
) => {
const attachments = getAttachments?.({ theCase }) ?? [];
adcoelho marked this conversation as resolved.
Show resolved Hide resolved
// when the case is undefined in the modal
// the user clicked "create new case"
if (theCase === undefined) {
Expand Down Expand Up @@ -101,15 +105,18 @@ export const useCasesAddToExistingCaseModal = (props: AddToExistingFlyoutProps =
);

const openModal = useCallback(
({ attachments }: { attachments?: CaseAttachmentsWithoutOwner } = {}) => {
({
getAttachments,
}: {
getAttachments?: ({ theCase }: { theCase?: Case }) => CaseAttachmentsWithoutOwner;
} = {}) => {
dispatch({
type: CasesContextStoreActionsList.OPEN_ADD_TO_CASE_MODAL,
payload: {
...props,
hiddenStatuses: [CaseStatuses.closed, StatusAll],
onRowClick: (theCase?: Case) => {
const caseAttachments = attachments ?? [];
handleOnRowClick(theCase, caseAttachments);
handleOnRowClick(theCase, getAttachments);
},
onClose: () => {
closeModal();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ describe('use cases add to new case flyout hook', () => {
},
{ wrapper }
);

result.current.open({ attachments: [alertComment] });

expect(dispatch).toHaveBeenCalledWith(
expect.objectContaining({
type: CasesContextStoreActionsList.OPEN_CREATE_CASE_FLYOUT,
Expand Down
72 changes: 43 additions & 29 deletions x-pack/plugins/cases/public/components/create/form_context.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const sampleId = 'case-id';
const defaultPostCase = {
isLoading: false,
isError: false,
postCase,
mutateAsync: postCase,
};

const defaultCreateCaseForm: CreateCaseFormFieldsProps = {
Expand Down Expand Up @@ -226,7 +226,7 @@ describe('Create case', () => {
expect(postCase).toHaveBeenCalled();
});

expect(postCase).toBeCalledWith({ ...sampleDataWithoutTags, tags: sampleTags });
expect(postCase).toBeCalledWith({ request: { ...sampleDataWithoutTags, tags: sampleTags } });
});

it('should post a case on submit click with the selected severity', async () => {
Expand Down Expand Up @@ -258,8 +258,10 @@ describe('Create case', () => {
});

expect(postCase).toBeCalledWith({
...sampleDataWithoutTags,
severity: CaseSeverity.HIGH,
request: {
...sampleDataWithoutTags,
severity: CaseSeverity.HIGH,
},
});
});

Expand Down Expand Up @@ -313,8 +315,10 @@ describe('Create case', () => {
await waitFor(() => expect(postCase).toHaveBeenCalled());

expect(postCase).toBeCalledWith({
...sampleDataWithoutTags,
settings: { syncAlerts: false },
request: {
...sampleDataWithoutTags,
settings: { syncAlerts: false },
},
});
});

Expand Down Expand Up @@ -343,8 +347,10 @@ describe('Create case', () => {
await waitFor(() => expect(postCase).toHaveBeenCalled());

expect(postCase).toBeCalledWith({
...sampleDataWithoutTags,
settings: { syncAlerts: false },
request: {
...sampleDataWithoutTags,
settings: { syncAlerts: false },
},
});
});

Expand Down Expand Up @@ -398,18 +404,20 @@ describe('Create case', () => {
await waitFor(() => expect(postCase).toHaveBeenCalled());

expect(postCase).toBeCalledWith({
...sampleDataWithoutTags,
connector: {
fields: {
impact: null,
severity: null,
urgency: null,
category: null,
subcategory: null,
request: {
...sampleDataWithoutTags,
connector: {
fields: {
impact: null,
severity: null,
urgency: null,
category: null,
subcategory: null,
},
id: 'servicenow-1',
name: 'My SN connector',
type: '.servicenow',
},
id: 'servicenow-1',
name: 'My SN connector',
type: '.servicenow',
},
});
});
Expand Down Expand Up @@ -449,7 +457,7 @@ describe('Create case', () => {
});

expect(pushCaseToExternalService).not.toHaveBeenCalled();
expect(postCase).toBeCalledWith(sampleDataWithoutTags);
expect(postCase).toBeCalledWith({ request: sampleDataWithoutTags });
});
});

Expand Down Expand Up @@ -501,20 +509,22 @@ describe('Create case', () => {
});

expect(postCase).toBeCalledWith({
...sampleDataWithoutTags,
connector: {
id: 'resilient-2',
name: 'My Connector 2',
type: '.resilient',
fields: { incidentTypes: ['21'], severityCode: '4' },
request: {
...sampleDataWithoutTags,
connector: {
id: 'resilient-2',
name: 'My Resilient connector',
type: '.resilient',
fields: { incidentTypes: ['21'], severityCode: '4' },
},
},
});

expect(pushCaseToExternalService).toHaveBeenCalledWith({
caseId: sampleId,
connector: {
id: 'resilient-2',
name: 'My Connector 2',
name: 'My Resilient connector',
type: '.resilient',
fields: { incidentTypes: ['21'], severityCode: '4' },
},
Expand Down Expand Up @@ -572,6 +582,7 @@ describe('Create case', () => {
...sampleConnectorData,
data: connectorsMock,
});

const attachments = [
{
alertId: '1234',
Expand Down Expand Up @@ -623,6 +634,7 @@ describe('Create case', () => {
...sampleConnectorData,
data: connectorsMock,
});

const attachments: CaseAttachments = [];

mockedContext.render(
Expand Down Expand Up @@ -766,8 +778,10 @@ describe('Create case', () => {
});

expect(postCase).toBeCalledWith({
...sampleDataWithoutTags,
assignees: [{ uid: userProfiles[0].uid }],
request: {
...sampleDataWithoutTags,
assignees: [{ uid: userProfiles[0].uid }],
},
});
});

Expand Down
38 changes: 20 additions & 18 deletions x-pack/plugins/cases/public/components/create/form_context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const FormContext: React.FC<Props> = ({
useGetSupportedActionConnectors();
const { owner, appId } = useCasesContext();
const { isSyncAlertsEnabled } = useCasesFeatures();
const { postCase } = usePostCase();
const { mutateAsync: postCase } = usePostCase();
const { createAttachments } = useCreateAttachments();
const { pushCaseToExternalService } = usePostPushToService();
const { startTransaction } = useCreateCaseWithAttachmentsTransaction();
Expand All @@ -84,48 +84,50 @@ export const FormContext: React.FC<Props> = ({
? normalizeActionConnector(caseConnector, fields)
: getNoneConnector();

const updatedCase = await postCase({
...userFormData,
connector: connectorToUpdate,
settings: { syncAlerts },
owner: selectedOwner ?? owner[0],
const theCase = await postCase({
request: {
...userFormData,
connector: connectorToUpdate,
settings: { syncAlerts },
owner: selectedOwner ?? owner[0],
},
});

// add attachments to the case
if (updatedCase && Array.isArray(attachments) && attachments.length > 0) {
if (theCase && Array.isArray(attachments) && attachments.length > 0) {
await createAttachments({
caseId: updatedCase.id,
caseOwner: updatedCase.owner,
caseId: theCase.id,
caseOwner: theCase.owner,
data: attachments,
});
}

if (afterCaseCreated && updatedCase) {
await afterCaseCreated(updatedCase, createAttachments);
if (afterCaseCreated && theCase) {
await afterCaseCreated(theCase, createAttachments);
}

if (updatedCase?.id && connectorToUpdate.id !== 'none') {
if (theCase?.id && connectorToUpdate.id !== 'none') {
await pushCaseToExternalService({
caseId: updatedCase.id,
caseId: theCase.id,
connector: connectorToUpdate,
});
}

if (onSuccess && updatedCase) {
onSuccess(updatedCase);
if (onSuccess && theCase) {
onSuccess(theCase);
}
}
},
[
appId,
startTransaction,
isSyncAlertsEnabled,
connectors,
startTransaction,
appId,
attachments,
postCase,
owner,
afterCaseCreated,
onSuccess,
attachments,
createAttachments,
pushCaseToExternalService,
]
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/cases/public/containers/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export const ERROR_TITLE = i18n.translate('xpack.cases.containers.errorTitle', {
defaultMessage: 'Error fetching data',
});

export const ERROR_CREATING_CASE = i18n.translate('xpack.cases.containers.errorCreatingCaseTitle', {
defaultMessage: 'Error creating case',
});

export const ERROR_DELETING = i18n.translate('xpack.cases.containers.errorDeletingTitle', {
defaultMessage: 'Error deleting data',
});
Expand Down
Loading