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] Add the ability to filter cases by date in the find and status endpoints #128652

Merged
merged 12 commits into from
Mar 31, 2022
6 changes: 6 additions & 0 deletions docs/api/cases/cases-api-find-cases.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ Defaults to `OR`.
`fields`::
(Optional, array of strings) The fields in the entity to return in the response.

`from`::
(Optional, string) Returns only cases that were created after a specific date. The date must be specified as a <<kuery-query,KQL>> data range or date match expression. preview:[]

`owner`::
(Optional, string or array of strings) A filter to limit the retrieved cases to
a specific set of applications. Valid values are: `cases`, `observability`,
Expand Down Expand Up @@ -78,6 +81,9 @@ Defaults to `desc`.
`tags`::
(Optional, string or array of strings) Filters the returned cases by tags.

`to`::
(Optional, string) Returns only cases that were created before a specific date. The date must be specified as a <<kuery-query,KQL>> data range or date match expression. preview:[]

=== Response code

`200`::
Expand Down
10 changes: 10 additions & 0 deletions x-pack/plugins/cases/common/api/cases/case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ export const CasesFindRequestRt = rt.partial({
* The fields in the entity to return in the response
*/
fields: rt.union([rt.array(rt.string), rt.string]),
/**
* A KQL date. If used all cases created after (gte) the from date will be returned
*/
from: rt.string,
/**
* The page of objects to return
*/
Expand All @@ -180,11 +184,17 @@ export const CasesFindRequestRt = rt.partial({
* The order to sort by
*/
sortOrder: rt.union([rt.literal('desc'), rt.literal('asc')]),

/**
* A KQL date. If used all cases created before (lte) the to date will be returned.
*/
to: rt.string,
/**
* The owner(s) to filter by. The user making the request must have privileges to retrieve cases of that
* ownership or they will be ignored. If no owner is included, then all ownership types will be included in the response
* that the user has access to.
*/

owner: rt.union([rt.array(rt.string), rt.string]),
});

Expand Down
8 changes: 8 additions & 0 deletions x-pack/plugins/cases/common/api/cases/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ export const CasesStatusResponseRt = rt.type({
});

export const CasesStatusRequestRt = rt.partial({
/**
* A KQL date. If used all cases created after (gte) the from date will be returned
*/
from: rt.string,
/**
* A KQL date. If used all cases created before (lte) the to date will be returned.
*/
to: rt.string,
/**
* The owner of the cases to retrieve the status stats from. If no owner is provided the stats for all cases
* that the user has access to will be returned.
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/cases/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const SAVED_OBJECT_TYPES = [
*/

export const CASES_URL = '/api/cases' as const;
export const CASE_FIND_URL = `${CASES_URL}/_find` as const;
export const CASE_DETAILS_URL = `${CASES_URL}/{case_id}` as const;
export const CASE_CONFIGURE_URL = `${CASES_URL}/configure` as const;
export const CASE_CONFIGURE_DETAILS_URL = `${CASES_URL}/configure/{configuration_id}` as const;
Expand Down
42 changes: 39 additions & 3 deletions x-pack/plugins/cases/public/client/api/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@

import { httpServiceMock } from '../../../../../../src/core/public/mocks';
import { createClientAPI } from '.';
import { allCases, casesStatus } from '../../containers/mock';

describe('createClientAPI', () => {
const http = httpServiceMock.createStartContract({ basePath: '' });
const api = createClientAPI({ http });

beforeEach(() => {
jest.clearAllMocks();
});

describe('getRelatedCases', () => {
const http = httpServiceMock.createStartContract({ basePath: '' });
const api = createClientAPI({ http });
const res = [
{
id: 'test-id',
Expand All @@ -43,4 +43,40 @@ describe('createClientAPI', () => {
});
});
});

describe('cases', () => {
describe('find', () => {
const http = httpServiceMock.createStartContract({ basePath: '' });
const api = createClientAPI({ http });
http.get.mockResolvedValue(allCases);

it('should return the correct response', async () => {
expect(await api.cases.find({ from: 'now-1d' })).toEqual(allCases);
});

it('should have been called with the correct path', async () => {
await api.cases.find({ perPage: 10 });
expect(http.get).toHaveBeenCalledWith('/api/cases/_find', {
query: { perPage: 10 },
});
});
});

describe('getAllCasesMetrics', () => {
const http = httpServiceMock.createStartContract({ basePath: '' });
const api = createClientAPI({ http });
http.get.mockResolvedValue(casesStatus);

it('should return the correct response', async () => {
expect(await api.cases.getAllCasesMetrics({ from: 'now-1d' })).toEqual(casesStatus);
});

it('should have been called with the correct path', async () => {
await api.cases.getAllCasesMetrics({ from: 'now-1d' });
expect(http.get).toHaveBeenCalledWith('/api/cases/status', {
query: { from: 'now-1d' },
});
});
});
});
});
17 changes: 16 additions & 1 deletion x-pack/plugins/cases/public/client/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@
*/

import { HttpStart } from 'kibana/public';
import { CasesByAlertId, CasesByAlertIDRequest, getCasesFromAlertsUrl } from '../../../common/api';
import {
CasesByAlertId,
CasesByAlertIDRequest,
CasesFindRequest,
getCasesFromAlertsUrl,
CasesResponse,
CasesStatusRequest,
CasesStatusResponse,
} from '../../../common/api';
import { CASE_FIND_URL, CASE_STATUS_URL } from '../../../common/constants';
import { CasesUiStart } from '../../types';

export const createClientAPI = ({ http }: { http: HttpStart }): CasesUiStart['api'] => {
Expand All @@ -16,5 +25,11 @@ export const createClientAPI = ({ http }: { http: HttpStart }): CasesUiStart['ap
query: CasesByAlertIDRequest
): Promise<CasesByAlertId> =>
http.get<CasesByAlertId>(getCasesFromAlertsUrl(alertId), { query }),
cases: {
find: (query: CasesFindRequest): Promise<CasesResponse> =>
http.get<CasesResponse>(CASE_FIND_URL, { query }),
getAllCasesMetrics: (query: CasesStatusRequest): Promise<CasesStatusResponse> =>
http.get<CasesStatusResponse>(CASE_STATUS_URL, { query }),
},
};
};
1 change: 1 addition & 0 deletions x-pack/plugins/cases/public/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { CasesUiStart } from './types';

const apiMock: jest.Mocked<CasesUiStart['api']> = {
getRelatedCases: jest.fn(),
cases: { find: jest.fn(), getAllCasesMetrics: jest.fn() },
};

const uiMock: jest.Mocked<CasesUiStart['ui']> = {
Expand Down
8 changes: 8 additions & 0 deletions x-pack/plugins/cases/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ import type { TriggersAndActionsUIPublicPluginStart as TriggersActionsStart } fr
import {
CasesByAlertId,
CasesByAlertIDRequest,
CasesFindRequest,
CasesResponse,
CasesStatusRequest,
CasesStatusResponse,
CommentRequestAlertType,
CommentRequestUserType,
} from '../common/api';
Expand Down Expand Up @@ -74,6 +78,10 @@ export interface RenderAppProps {
export interface CasesUiStart {
api: {
getRelatedCases: (alertId: string, query: CasesByAlertIDRequest) => Promise<CasesByAlertId>;
cases: {
find: (query: CasesFindRequest) => Promise<CasesResponse>;
getAllCasesMetrics: (query: CasesStatusRequest) => Promise<CasesStatusResponse>;
};
};
ui: {
/**
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/cases/server/client/cases/find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ export const find = async (
sortByField: queryParams.sortField,
status: queryParams.status,
owner: queryParams.owner,
from: queryParams.from,
to: queryParams.to,
};

const statusStatsOptions = constructQueryOptions({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export async function getStatusTotalsByType(

const options = constructQueryOptions({
owner: queryParams.owner,
from: queryParams.from,
to: queryParams.to,
authorizationFilter,
});

Expand Down
Loading