[ResponseOps] [Cases] Allow sorting cases list by status, severity and title (#148193)

Connected to #132041

## Summary

Sorting by status, severity, and title is now allowed in the all-cases
list.

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [x] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)

---

## Release notes

Sorting by status, severity, and title is now allowed in the all-cases
list.

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Antonio 2023-01-03 14:09:50 +01:00 committed by GitHub
parent 5fddc7da81
commit 0b1ecc9844
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 144 additions and 15 deletions

View file

@ -127,8 +127,11 @@ export type SingleCaseMetricsFeature =
| 'lifespan';
export enum SortFieldCase {
createdAt = 'createdAt',
closedAt = 'closedAt',
createdAt = 'createdAt',
severity = 'severity',
status = 'status',
title = 'title',
}
export type ElasticUser = SnakeToCamelCase<User>;

View file

@ -8,7 +8,7 @@
import React from 'react';
import { mount } from 'enzyme';
import moment from 'moment-timezone';
import { render, waitFor, screen, act } from '@testing-library/react';
import { render, waitFor, screen, act, within } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import userEvent from '@testing-library/user-event';
import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl';
@ -257,23 +257,28 @@ describe('AllCasesListGeneric', () => {
expect.objectContaining({
queryParams: {
...DEFAULT_QUERY_PARAMS,
sortOrder: 'asc',
},
})
);
});
});
it('renders the title column', async () => {
const res = appMockRenderer.render(<AllCasesList />);
expect(res.getByTestId('tableHeaderCell_title_0')).toBeInTheDocument();
});
it('renders the status column', async () => {
const res = appMockRenderer.render(<AllCasesList />);
expect(res.getByTestId('tableHeaderCell_Status_6')).toBeInTheDocument();
expect(res.getByTestId('tableHeaderCell_status_6')).toBeInTheDocument();
});
it('renders the severity column', async () => {
const res = appMockRenderer.render(<AllCasesList />);
expect(res.getByTestId('tableHeaderCell_Severity_7')).toBeInTheDocument();
expect(res.getByTestId('tableHeaderCell_severity_7')).toBeInTheDocument();
});
it('should render the case stats', () => {
@ -393,6 +398,66 @@ describe('AllCasesListGeneric', () => {
});
});
it('should sort by status', async () => {
const result = appMockRenderer.render(<AllCasesList isSelectorView={false} />);
userEvent.click(
within(result.getByTestId('tableHeaderCell_status_6')).getByTestId('tableHeaderSortButton')
);
await waitFor(() => {
expect(useGetCasesMock).toHaveBeenLastCalledWith(
expect.objectContaining({
queryParams: {
...DEFAULT_QUERY_PARAMS,
sortField: SortFieldCase.status,
sortOrder: 'asc',
},
})
);
});
});
it('should sort by severity', async () => {
const result = appMockRenderer.render(<AllCasesList isSelectorView={false} />);
userEvent.click(
within(result.getByTestId('tableHeaderCell_severity_7')).getByTestId('tableHeaderSortButton')
);
await waitFor(() => {
expect(useGetCasesMock).toHaveBeenLastCalledWith(
expect.objectContaining({
queryParams: {
...DEFAULT_QUERY_PARAMS,
sortField: SortFieldCase.severity,
sortOrder: 'asc',
},
})
);
});
});
it('should sort by title', async () => {
const result = appMockRenderer.render(<AllCasesList isSelectorView={false} />);
userEvent.click(
within(result.getByTestId('tableHeaderCell_title_0')).getByTestId('tableHeaderSortButton')
);
await waitFor(() => {
expect(useGetCasesMock).toHaveBeenLastCalledWith(
expect.objectContaining({
queryParams: {
...DEFAULT_QUERY_PARAMS,
sortField: SortFieldCase.title,
sortOrder: 'asc',
},
})
);
});
});
it('should filter by status: closed', async () => {
const result = appMockRenderer.render(<AllCasesList isSelectorView={false} />);
userEvent.click(result.getByTestId('case-status-filter'));

View file

@ -45,7 +45,8 @@ const ProgressLoader = styled(EuiProgress)`
`;
const getSortField = (field: string): SortFieldCase =>
field === SortFieldCase.closedAt ? SortFieldCase.closedAt : SortFieldCase.createdAt;
// @ts-ignore
SortFieldCase[field] ?? SortFieldCase.title;
export interface AllCasesListProps {
hiddenStatuses?: CaseStatusWithAllStatus[];

View file

@ -49,8 +49,10 @@ describe('useCasesColumns ', () => {
Object {
"columns": Array [
Object {
"field": "title",
"name": "Name",
"render": [Function],
"sortable": true,
"width": "20%",
},
Object {
@ -95,12 +97,16 @@ describe('useCasesColumns ', () => {
"render": [Function],
},
Object {
"field": "status",
"name": "Status",
"render": [Function],
"sortable": true,
},
Object {
"field": "severity",
"name": "Severity",
"render": [Function],
"sortable": true,
},
Object {
"align": "right",
@ -130,8 +136,10 @@ describe('useCasesColumns ', () => {
Object {
"columns": Array [
Object {
"field": "title",
"name": "Name",
"render": [Function],
"sortable": true,
"width": "20%",
},
Object {
@ -176,12 +184,16 @@ describe('useCasesColumns ', () => {
"render": [Function],
},
Object {
"field": "status",
"name": "Status",
"render": [Function],
"sortable": true,
},
Object {
"field": "severity",
"name": "Severity",
"render": [Function],
"sortable": true,
},
Object {
"align": "right",
@ -210,8 +222,10 @@ describe('useCasesColumns ', () => {
Object {
"columns": Array [
Object {
"field": "title",
"name": "Name",
"render": [Function],
"sortable": true,
"width": "20%",
},
Object {
@ -250,12 +264,16 @@ describe('useCasesColumns ', () => {
"render": [Function],
},
Object {
"field": "status",
"name": "Status",
"render": [Function],
"sortable": true,
},
Object {
"field": "severity",
"name": "Severity",
"render": [Function],
"sortable": true,
},
Object {
"align": "right",
@ -282,8 +300,10 @@ describe('useCasesColumns ', () => {
Object {
"columns": Array [
Object {
"field": "title",
"name": "Name",
"render": [Function],
"sortable": true,
"width": "20%",
},
Object {
@ -321,12 +341,16 @@ describe('useCasesColumns ', () => {
"render": [Function],
},
Object {
"field": "status",
"name": "Status",
"render": [Function],
"sortable": true,
},
Object {
"field": "severity",
"name": "Severity",
"render": [Function],
"sortable": true,
},
Object {
"align": "right",
@ -347,8 +371,10 @@ describe('useCasesColumns ', () => {
Object {
"columns": Array [
Object {
"field": "title",
"name": "Name",
"render": [Function],
"sortable": true,
"width": "20%",
},
Object {
@ -387,12 +413,16 @@ describe('useCasesColumns ', () => {
"render": [Function],
},
Object {
"field": "status",
"name": "Status",
"render": [Function],
"sortable": true,
},
Object {
"field": "severity",
"name": "Severity",
"render": [Function],
"sortable": true,
},
Object {
"align": "right",
@ -418,8 +448,10 @@ describe('useCasesColumns ', () => {
Object {
"columns": Array [
Object {
"field": "title",
"name": "Name",
"render": [Function],
"sortable": true,
"width": "20%",
},
Object {
@ -458,12 +490,16 @@ describe('useCasesColumns ', () => {
"render": [Function],
},
Object {
"field": "status",
"name": "Status",
"render": [Function],
"sortable": true,
},
Object {
"field": "severity",
"name": "Severity",
"render": [Function],
"sortable": true,
},
Object {
"align": "right",
@ -487,8 +523,10 @@ describe('useCasesColumns ', () => {
Object {
"columns": Array [
Object {
"field": "title",
"name": "Name",
"render": [Function],
"sortable": true,
"width": "20%",
},
Object {
@ -527,12 +565,16 @@ describe('useCasesColumns ', () => {
"render": [Function],
},
Object {
"field": "status",
"name": "Status",
"render": [Function],
"sortable": true,
},
Object {
"field": "severity",
"name": "Severity",
"render": [Function],
"sortable": true,
},
Object {
"align": "right",
@ -555,8 +597,10 @@ describe('useCasesColumns ', () => {
Object {
"columns": Array [
Object {
"field": "title",
"name": "Name",
"render": [Function],
"sortable": true,
"width": "20%",
},
Object {
@ -595,12 +639,16 @@ describe('useCasesColumns ', () => {
"render": [Function],
},
Object {
"field": "status",
"name": "Status",
"render": [Function],
"sortable": true,
},
Object {
"field": "severity",
"name": "Severity",
"render": [Function],
"sortable": true,
},
Object {
"align": "right",
@ -622,8 +670,10 @@ describe('useCasesColumns ', () => {
Object {
"columns": Array [
Object {
"field": "title",
"name": "Name",
"render": [Function],
"sortable": true,
"width": "20%",
},
Object {
@ -662,12 +712,16 @@ describe('useCasesColumns ', () => {
"render": [Function],
},
Object {
"field": "status",
"name": "Status",
"render": [Function],
"sortable": true,
},
Object {
"field": "severity",
"name": "Severity",
"render": [Function],
"sortable": true,
},
],
}

View file

@ -112,8 +112,10 @@ export const useCasesColumns = ({
const columns: CasesColumns[] = [
{
field: 'title',
name: i18n.NAME,
render: (theCase: Case) => {
sortable: true,
render: (title: string, theCase: Case) => {
if (theCase.id != null && theCase.title != null) {
const caseDetailsLinkComponent = isSelectorView ? (
<TruncatedText text={theCase.title} />
@ -287,23 +289,27 @@ export const useCasesColumns = ({
},
},
{
field: 'status',
name: i18n.STATUS,
render: (theCase: Case) => {
if (theCase.status === null || theCase.status === undefined) {
return getEmptyTagValue();
sortable: true,
render: (status: Case['status']) => {
if (status != null) {
return <Status status={status} />;
}
return <Status status={theCase.status} />;
return getEmptyTagValue();
},
},
{
field: 'severity',
name: i18n.SEVERITY,
render: (theCase: Case) => {
if (theCase.severity != null) {
const severityData = severities[theCase.severity ?? CaseSeverity.LOW];
sortable: true,
render: (severity: Case['severity']) => {
if (severity != null) {
const severityData = severities[severity ?? CaseSeverity.LOW];
return (
<EuiHealth
data-test-subj={`case-table-column-severity-${theCase.severity}`}
data-test-subj={`case-table-column-severity-${severity}`}
color={severityData.color}
>
{severityData.label}