-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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] Improve bulk actions #142150
Merged
Merged
[Cases] Improve bulk actions #142150
Changes from 4 commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
95daaa5
Use react query for delete cases
cnasikas 6f2bb32
Convert delete to react query
cnasikas a425bbc
Convert update to react query
cnasikas cf19789
Convert use_get_cases_status to react query
cnasikas 10a670d
Convert use_get_cases_metrics to react query
cnasikas 4471cb2
Refresh metrics and statuses
cnasikas f58b6a8
Show loading when updating cases
cnasikas a43ea7b
Create query key builder
cnasikas 79beccc
Improve refreshing logic
cnasikas ad9b7cc
Improve delete messages
cnasikas d2b5c6c
Fix types and tests
cnasikas 6c3eb0f
Improvements
cnasikas 01fe84f
Merge branch 'main' into update_delete_rquery
cnasikas c3d9508
PR feedback
cnasikas b8eae38
Merge branch 'main' into update_delete_rquery
cnasikas cdbf449
Fix bug
cnasikas 40f2894
Refactor actions
cnasikas 384fe85
Merge branch 'main' into refactor_bulk_actions
cnasikas 753977b
Add status actions
cnasikas c2a354e
Change status to panel
cnasikas 09e4278
Add status column
cnasikas 09220c6
Improvements
cnasikas d2a64a6
Fix tests & types
cnasikas 939e4cd
Remove comment
cnasikas fb14028
Improve e2e tests
cnasikas e6dcaa2
Add unit tests
cnasikas c774576
Merge branch 'main' into refactor_bulk_actions
cnasikas 10f2763
Add permissions
cnasikas 8d4421c
Fix delete e2e
cnasikas 6af1146
Disable statuses
cnasikas 727410f
Fix i18n
cnasikas d96956b
PR feedback
cnasikas 98a2032
Disable actions when cases are selected
cnasikas 243a220
Improve modal tests
cnasikas 0454288
Disables checkbox on read only
cnasikas 76c8eb9
Merge branch 'main' into refactor_bulk_actions
cnasikas b4da899
PR feedback
cnasikas 0b285e3
Merge branch 'main' into refactor_bulk_actions
cnasikas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,12 +18,13 @@ import { | |
AppMockRenderer, | ||
createAppMockRenderer, | ||
noDeleteCasesPermissions, | ||
readCasesPermissions, | ||
TestProviders, | ||
} from '../../common/mock'; | ||
import { useGetCasesMockState, connectorsMock } from '../../containers/mock'; | ||
|
||
import { StatusAll } from '../../../common/ui/types'; | ||
import { CaseSeverity, CaseStatuses } from '../../../common/api'; | ||
import { CaseStatuses } from '../../../common/api'; | ||
import { SECURITY_SOLUTION_OWNER } from '../../../common/constants'; | ||
import { getEmptyTagValue } from '../empty_value'; | ||
import { useKibana } from '../../common/lib/kibana'; | ||
|
@@ -360,60 +361,21 @@ describe('AllCasesListGeneric', () => { | |
}); | ||
|
||
it('should call onRowClick when clicking a case with modal=true', async () => { | ||
const theCase = defaultGetCases.data.cases[0]; | ||
|
||
const wrapper = mount( | ||
<TestProviders> | ||
<AllCasesList isSelectorView={true} onRowClick={onRowClick} /> | ||
</TestProviders> | ||
); | ||
|
||
wrapper.find('[data-test-subj="cases-table-row-select-1"]').first().simulate('click'); | ||
wrapper | ||
.find(`[data-test-subj="cases-table-row-select-${theCase.id}"]`) | ||
.first() | ||
.simulate('click'); | ||
|
||
await waitFor(() => { | ||
expect(onRowClick).toHaveBeenCalledWith({ | ||
assignees: [{ uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0' }], | ||
closedAt: null, | ||
closedBy: null, | ||
comments: [], | ||
connector: { fields: null, id: '123', name: 'My Connector', type: '.jira' }, | ||
createdAt: '2020-02-19T23:06:33.798Z', | ||
createdBy: { | ||
email: '[email protected]', | ||
fullName: 'Leslie Knope', | ||
username: 'lknope', | ||
}, | ||
description: 'Security banana Issue', | ||
severity: CaseSeverity.LOW, | ||
duration: null, | ||
externalService: { | ||
connectorId: '123', | ||
connectorName: 'connector name', | ||
externalId: 'external_id', | ||
externalTitle: 'external title', | ||
externalUrl: 'basicPush.com', | ||
pushedAt: '2020-02-20T15:02:57.995Z', | ||
pushedBy: { | ||
email: '[email protected]', | ||
fullName: 'Leslie Knope', | ||
username: 'lknope', | ||
}, | ||
}, | ||
id: '1', | ||
owner: SECURITY_SOLUTION_OWNER, | ||
status: 'open', | ||
tags: ['coke', 'pepsi'], | ||
title: 'Another horrible breach!!', | ||
totalAlerts: 0, | ||
totalComment: 0, | ||
updatedAt: '2020-02-20T15:02:57.995Z', | ||
updatedBy: { | ||
email: '[email protected]', | ||
fullName: 'Leslie Knope', | ||
username: 'lknope', | ||
}, | ||
version: 'WzQ3LDFd', | ||
settings: { | ||
syncAlerts: true, | ||
}, | ||
}); | ||
expect(onRowClick).toHaveBeenCalledWith(theCase); | ||
}); | ||
}); | ||
|
||
|
@@ -746,6 +708,10 @@ describe('AllCasesListGeneric', () => { | |
it('Renders bulk action', async () => { | ||
const result = appMockRenderer.render(<AllCasesList />); | ||
|
||
act(() => { | ||
userEvent.click(result.getByTestId('checkboxSelectAll')); | ||
}); | ||
|
||
act(() => { | ||
userEvent.click(result.getByText('Bulk actions')); | ||
}); | ||
|
@@ -760,10 +726,9 @@ describe('AllCasesListGeneric', () => { | |
'Bulk update status: %s', | ||
async (status) => { | ||
const result = appMockRenderer.render(<AllCasesList />); | ||
const theCase = useGetCasesMockState.data.cases[0]; | ||
|
||
act(() => { | ||
userEvent.click(result.getByTestId(`checkboxSelectRow-${theCase.id}`)); | ||
userEvent.click(result.getByTestId('checkboxSelectAll')); | ||
}); | ||
|
||
act(() => { | ||
|
@@ -787,7 +752,11 @@ describe('AllCasesListGeneric', () => { | |
await waitForComponentToUpdate(); | ||
|
||
expect(updateCasesSpy).toBeCalledWith( | ||
[{ id: theCase.id, version: theCase.version, status }], | ||
useGetCasesMockState.data.cases.map(({ id, version }) => ({ | ||
id, | ||
version, | ||
status, | ||
})), | ||
expect.anything() | ||
); | ||
} | ||
|
@@ -836,6 +805,19 @@ describe('AllCasesListGeneric', () => { | |
); | ||
}); | ||
}); | ||
|
||
it('should disable the checkboxes when the user has read only permissions', async () => { | ||
appMockRenderer = createAppMockRenderer({ permissions: readCasesPermissions() }); | ||
const res = appMockRenderer.render(<AllCasesList />); | ||
|
||
expect(res.getByTestId('checkboxSelectAll')).toBeDisabled(); | ||
|
||
await waitFor(() => { | ||
for (const theCase of defaultGetCases.data.cases) { | ||
expect(res.getByTestId(`checkboxSelectRow-${theCase.id}`)).toBeDisabled(); | ||
} | ||
}); | ||
}); | ||
}); | ||
|
||
describe('Row actions', () => { | ||
|
@@ -857,7 +839,9 @@ describe('AllCasesListGeneric', () => { | |
|
||
it.each(statusTests)('update the status of a case: %s', async (status) => { | ||
const res = appMockRenderer.render(<AllCasesList />); | ||
const theCase = defaultGetCases.data.cases[0]; | ||
const openCase = useGetCasesMockState.data.cases[0]; | ||
const inProgressCase = useGetCasesMockState.data.cases[1]; | ||
const theCase = status === CaseStatuses.open ? inProgressCase : openCase; | ||
|
||
await waitFor(() => { | ||
expect(res.getByTestId(`case-action-popover-button-${theCase.id}`)).toBeInTheDocument(); | ||
|
@@ -887,7 +871,7 @@ describe('AllCasesListGeneric', () => { | |
|
||
await waitFor(() => { | ||
expect(updateCasesSpy).toHaveBeenCalledWith( | ||
[{ id: 'basic-case-id', status, version: 'WzQ3LDFd' }], | ||
[{ id: theCase.id, status, version: theCase.version }], | ||
expect.anything() | ||
); | ||
}); | ||
|
@@ -927,6 +911,20 @@ describe('AllCasesListGeneric', () => { | |
expect(deleteCasesSpy).toHaveBeenCalledWith(['basic-case-id'], expect.anything()); | ||
}); | ||
}); | ||
|
||
it('should disable row actions when bulk selecting cases', async () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we add a test for disabling the row actions when a single checkbox is selected? |
||
const res = appMockRenderer.render(<AllCasesList />); | ||
|
||
act(() => { | ||
userEvent.click(res.getByTestId('checkboxSelectAll')); | ||
}); | ||
|
||
await waitFor(() => { | ||
for (const theCase of defaultGetCases.data.cases) { | ||
expect(res.getByTestId(`case-action-popover-button-${theCase.id}`)).toBeDisabled(); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think it makes sense to move the permissions check within this hook (and the `use_status_action)? I know we'd still need it in the callers to do various other checks though. I think it'd encapsulate the logic a bit more though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved the logic to the hooks as you suggested. To avoid the consumers doing permissions checks, the hooks will return
canDelete
andcanUpdateStatus
respectively.