Make alerts list sortable by name and status (#93426) (#93959)

* Initial commit

* Update docs

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: Mike Côté <mikecote@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2021-03-08 13:27:27 -05:00 committed by GitHub
parent afb144d051
commit c4011f8b53
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 165 additions and 58 deletions

View file

@ -860,7 +860,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts", "path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts",
"lineNumber": 131 "lineNumber": 132
} }
}, },
{ {
@ -871,7 +871,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts", "path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts",
"lineNumber": 132 "lineNumber": 133
} }
}, },
{ {
@ -882,7 +882,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts", "path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts",
"lineNumber": 133 "lineNumber": 134
} }
}, },
{ {
@ -893,7 +893,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts", "path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts",
"lineNumber": 134 "lineNumber": 135
}, },
"signature": [ "signature": [
"Pick<", "Pick<",
@ -910,7 +910,7 @@
], ],
"source": { "source": {
"path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts", "path": "x-pack/plugins/alerting/server/alerts_client/alerts_client.ts",
"lineNumber": 130 "lineNumber": 131
}, },
"initialIsOpen": false "initialIsOpen": false
}, },

View file

@ -942,7 +942,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 156 "lineNumber": 161
} }
}, },
{ {
@ -953,7 +953,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 157 "lineNumber": 162
} }
}, },
{ {
@ -964,7 +964,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 158 "lineNumber": 163
}, },
"signature": [ "signature": [
"boolean | undefined" "boolean | undefined"
@ -973,7 +973,7 @@
], ],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 155 "lineNumber": 160
}, },
"initialIsOpen": false "initialIsOpen": false
}, },
@ -1130,7 +1130,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 221 "lineNumber": 227
} }
}, },
{ {
@ -1141,7 +1141,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 222 "lineNumber": 228
} }
}, },
{ {
@ -1152,7 +1152,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 223 "lineNumber": 229
} }
}, },
{ {
@ -1163,7 +1163,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 224 "lineNumber": 230
}, },
"signature": [ "signature": [
"string | ((docLinks: ", "string | ((docLinks: ",
@ -1185,7 +1185,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 225 "lineNumber": 231
}, },
"signature": [ "signature": [
"(alertParams: Params) => ", "(alertParams: Params) => ",
@ -1206,7 +1206,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 226 "lineNumber": 232
}, },
"signature": [ "signature": [
"React.FunctionComponent<any> | React.LazyExoticComponent<React.ComponentType<", "React.FunctionComponent<any> | React.LazyExoticComponent<React.ComponentType<",
@ -1228,7 +1228,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 229 "lineNumber": 235
} }
}, },
{ {
@ -1239,7 +1239,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 230 "lineNumber": 236
}, },
"signature": [ "signature": [
"string | undefined" "string | undefined"
@ -1248,7 +1248,7 @@
], ],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 220 "lineNumber": 226
}, },
"initialIsOpen": false "initialIsOpen": false
}, },
@ -1277,7 +1277,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 203 "lineNumber": 209
}, },
"signature": [ "signature": [
"Params" "Params"
@ -1291,7 +1291,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 204 "lineNumber": 210
} }
}, },
{ {
@ -1302,7 +1302,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 205 "lineNumber": 211
} }
}, },
{ {
@ -1313,7 +1313,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 206 "lineNumber": 212
}, },
"signature": [ "signature": [
"\"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"" "\"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\""
@ -1327,7 +1327,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 207 "lineNumber": 213
}, },
"signature": [ "signature": [
"<Key extends keyof Params>(property: Key, value: Params[Key] | undefined) => void" "<Key extends keyof Params>(property: Key, value: Params[Key] | undefined) => void"
@ -1341,7 +1341,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 208 "lineNumber": 214
}, },
"signature": [ "signature": [
"<Prop extends \"enabled\" | \"id\" | \"name\" | \"params\" | \"actions\" | \"muteAll\" | \"tags\" | \"alertTypeId\" | \"consumer\" | \"schedule\" | \"scheduledTaskId\" | \"createdBy\" | \"updatedBy\" | \"createdAt\" | \"updatedAt\" | \"apiKeyOwner\" | \"throttle\" | \"notifyWhen\" | \"mutedInstanceIds\" | \"executionStatus\">(key: Prop, value: Pick<", "<Prop extends \"enabled\" | \"id\" | \"name\" | \"params\" | \"actions\" | \"muteAll\" | \"tags\" | \"alertTypeId\" | \"consumer\" | \"schedule\" | \"scheduledTaskId\" | \"createdBy\" | \"updatedBy\" | \"createdAt\" | \"updatedAt\" | \"apiKeyOwner\" | \"throttle\" | \"notifyWhen\" | \"mutedInstanceIds\" | \"executionStatus\">(key: Prop, value: Pick<",
@ -1363,7 +1363,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 212 "lineNumber": 218
}, },
"signature": [ "signature": [
{ {
@ -1383,7 +1383,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 213 "lineNumber": 219
} }
}, },
{ {
@ -1394,7 +1394,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 214 "lineNumber": 220
}, },
"signature": [ "signature": [
{ {
@ -1415,7 +1415,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 215 "lineNumber": 221
}, },
"signature": [ "signature": [
"MetaData | undefined" "MetaData | undefined"
@ -1429,7 +1429,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 216 "lineNumber": 222
}, },
"signature": [ "signature": [
{ {
@ -1449,7 +1449,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 217 "lineNumber": 223
}, },
"signature": [ "signature": [
{ {
@ -1464,7 +1464,7 @@
], ],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 198 "lineNumber": 204
}, },
"initialIsOpen": false "initialIsOpen": false
}, },
@ -1591,7 +1591,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 234 "lineNumber": 240
}, },
"signature": [ "signature": [
"any" "any"
@ -1600,7 +1600,7 @@
], ],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 233 "lineNumber": 239
}, },
"initialIsOpen": false "initialIsOpen": false
}, },
@ -1924,7 +1924,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 110 "lineNumber": 115
}, },
"signature": [ "signature": [
"Record<string, any>" "Record<string, any>"
@ -1933,7 +1933,7 @@
], ],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 109 "lineNumber": 114
}, },
"initialIsOpen": false "initialIsOpen": false
} }
@ -1997,7 +1997,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 142 "lineNumber": 147
}, },
"signature": [ "signature": [
"PreConfiguredActionConnector", "PreConfiguredActionConnector",
@ -2060,7 +2060,7 @@
"description": [], "description": [],
"source": { "source": {
"path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "path": "x-pack/plugins/triggers_actions_ui/public/types.ts",
"lineNumber": 166 "lineNumber": 171
}, },
"signature": [ "signature": [
"AsActionVariables<\"params\" | \"state\"> & Partial<AsActionVariables<\"context\">>" "AsActionVariables<\"params\" | \"state\"> & Partial<AsActionVariables<\"context\">>"

View file

@ -57,6 +57,7 @@ import { partiallyUpdateAlert } from '../saved_objects';
import { markApiKeyForInvalidation } from '../invalidate_pending_api_keys/mark_api_key_for_invalidation'; import { markApiKeyForInvalidation } from '../invalidate_pending_api_keys/mark_api_key_for_invalidation';
import { alertAuditEvent, AlertAuditAction } from './audit_events'; import { alertAuditEvent, AlertAuditAction } from './audit_events';
import { nodeBuilder } from '../../../../../src/plugins/data/common'; import { nodeBuilder } from '../../../../../src/plugins/data/common';
import { mapSortField } from './lib';
export interface RegistryAlertTypeWithAuth extends RegistryAlertType { export interface RegistryAlertTypeWithAuth extends RegistryAlertType {
authorizedConsumers: string[]; authorizedConsumers: string[];
@ -465,6 +466,7 @@ export class AlertsClient {
saved_objects: data, saved_objects: data,
} = await this.unsecuredSavedObjectsClient.find<RawAlert>({ } = await this.unsecuredSavedObjectsClient.find<RawAlert>({
...options, ...options,
sortField: mapSortField(options.sortField),
filter: filter:
(authorizationFilter && options.filter (authorizationFilter && options.filter
? nodeBuilder.and([esKuery.fromKueryExpression(options.filter), authorizationFilter]) ? nodeBuilder.and([esKuery.fromKueryExpression(options.filter), authorizationFilter])

View file

@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { mapSortField } from './map_sort_field';

View file

@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { mapSortField } from './map_sort_field';
describe('mapSortField()', () => {
test('should return undefined when given undefined', () => {
expect(mapSortField(undefined)).toStrictEqual(undefined);
});
test('should return a mapped value when a mapping exists', () => {
expect(mapSortField('name')).toEqual('name.keyword');
});
test(`should return field when a mapping doesn't exist`, () => {
expect(mapSortField('tags')).toEqual('tags');
});
});

View file

@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
const sortFieldMap: Record<string, string> = {
name: 'name.keyword',
};
export function mapSortField(field?: string): string | undefined {
return field ? sortFieldMap[field] || field : undefined;
}

View file

@ -55,6 +55,10 @@ beforeEach(() => {
setGlobalDate(); setGlobalDate();
jest.mock('../lib/map_sort_field', () => ({
mapSortField: jest.fn(),
}));
describe('find()', () => { describe('find()', () => {
const listedTypes = new Set<RegistryAlertType>([ const listedTypes = new Set<RegistryAlertType>([
{ {
@ -172,12 +176,19 @@ describe('find()', () => {
Object { Object {
"fields": undefined, "fields": undefined,
"filter": undefined, "filter": undefined,
"sortField": undefined,
"type": "alert", "type": "alert",
}, },
] ]
`); `);
}); });
test('calls mapSortField', async () => {
const alertsClient = new AlertsClient(alertsClientParams);
await alertsClient.find({ options: { sortField: 'name' } });
expect(jest.requireMock('../lib/map_sort_field').mapSortField).toHaveBeenCalledWith('name');
});
describe('authorization', () => { describe('authorization', () => {
test('ensures user is query filter types down to those the user is authorized to find', async () => { test('ensures user is query filter types down to those the user is authorized to find', async () => {
const filter = esKuery.fromKueryExpression( const filter = esKuery.fromKueryExpression(

View file

@ -22653,7 +22653,7 @@
"xpack.triggersActionsUI.sections.alertsList.alertErrorReasonRunning": "アラートの実行中にエラーが発生しました。", "xpack.triggersActionsUI.sections.alertsList.alertErrorReasonRunning": "アラートの実行中にエラーが発生しました。",
"xpack.triggersActionsUI.sections.alertsList.alertErrorReasonUnknown": "不明な理由でエラーが発生しました。", "xpack.triggersActionsUI.sections.alertsList.alertErrorReasonUnknown": "不明な理由でエラーが発生しました。",
"xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsTex": "アクション", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsTex": "アクション",
"xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsText": "アクション", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsCount": "アクション",
"xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.alertTypeTitle": "型", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.alertTypeTitle": "型",
"xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.intervalTitle": "次の間隔で実行", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.intervalTitle": "次の間隔で実行",
"xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.nameTitle": "名前", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.nameTitle": "名前",

View file

@ -23004,7 +23004,7 @@
"xpack.triggersActionsUI.sections.alertsList.alertErrorReasonRunning": "运行告警时发生错误。", "xpack.triggersActionsUI.sections.alertsList.alertErrorReasonRunning": "运行告警时发生错误。",
"xpack.triggersActionsUI.sections.alertsList.alertErrorReasonUnknown": "由于未知原因发生错误。", "xpack.triggersActionsUI.sections.alertsList.alertErrorReasonUnknown": "由于未知原因发生错误。",
"xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsTex": "操作", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsTex": "操作",
"xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsText": "操作", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsCount": "操作",
"xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.alertTypeTitle": "类型", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.alertTypeTitle": "类型",
"xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.intervalTitle": "运行间隔", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.intervalTitle": "运行间隔",
"xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.nameTitle": "名称", "xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.nameTitle": "名称",

View file

@ -180,7 +180,7 @@ describe('loadAlerts', () => {
"per_page": 10, "per_page": 10,
"search": undefined, "search": undefined,
"search_fields": undefined, "search_fields": undefined,
"sort_field": "name.keyword", "sort_field": "name",
"sort_order": "asc", "sort_order": "asc",
}, },
}, },
@ -210,7 +210,7 @@ describe('loadAlerts', () => {
"per_page": 10, "per_page": 10,
"search": "apples", "search": "apples",
"search_fields": "[\\"name\\",\\"tags\\"]", "search_fields": "[\\"name\\",\\"tags\\"]",
"sort_field": "name.keyword", "sort_field": "name",
"sort_order": "asc", "sort_order": "asc",
}, },
}, },
@ -244,7 +244,7 @@ describe('loadAlerts', () => {
"per_page": 10, "per_page": 10,
"search": "foo", "search": "foo",
"search_fields": "[\\"name\\",\\"tags\\"]", "search_fields": "[\\"name\\",\\"tags\\"]",
"sort_field": "name.keyword", "sort_field": "name",
"sort_order": "asc", "sort_order": "asc",
}, },
}, },
@ -278,7 +278,7 @@ describe('loadAlerts', () => {
"per_page": 10, "per_page": 10,
"search": undefined, "search": undefined,
"search_fields": undefined, "search_fields": undefined,
"sort_field": "name.keyword", "sort_field": "name",
"sort_order": "asc", "sort_order": "asc",
}, },
}, },
@ -313,7 +313,7 @@ describe('loadAlerts', () => {
"per_page": 10, "per_page": 10,
"search": "baz", "search": "baz",
"search_fields": "[\\"name\\",\\"tags\\"]", "search_fields": "[\\"name\\",\\"tags\\"]",
"sort_field": "name.keyword", "sort_field": "name",
"sort_order": "asc", "sort_order": "asc",
}, },
}, },
@ -348,7 +348,7 @@ describe('loadAlerts', () => {
"per_page": 10, "per_page": 10,
"search": "apples, foo, baz", "search": "apples, foo, baz",
"search_fields": "[\\"name\\",\\"tags\\"]", "search_fields": "[\\"name\\",\\"tags\\"]",
"sort_field": "name.keyword", "sort_field": "name",
"sort_order": "asc", "sort_order": "asc",
}, },
}, },

View file

@ -19,6 +19,8 @@ import {
AlertUpdates, AlertUpdates,
AlertTaskState, AlertTaskState,
AlertInstanceSummary, AlertInstanceSummary,
Pagination,
Sorting,
} from '../../types'; } from '../../types';
export async function loadAlertTypes({ http }: { http: HttpSetup }): Promise<AlertType[]> { export async function loadAlertTypes({ http }: { http: HttpSetup }): Promise<AlertType[]> {
@ -103,13 +105,15 @@ export async function loadAlerts({
typesFilter, typesFilter,
actionTypesFilter, actionTypesFilter,
alertStatusesFilter, alertStatusesFilter,
sort = { field: 'name', direction: 'asc' },
}: { }: {
http: HttpSetup; http: HttpSetup;
page: { index: number; size: number }; page: Pagination;
searchText?: string; searchText?: string;
typesFilter?: string[]; typesFilter?: string[];
actionTypesFilter?: string[]; actionTypesFilter?: string[];
alertStatusesFilter?: string[]; alertStatusesFilter?: string[];
sort?: Sorting;
}): Promise<{ }): Promise<{
page: number; page: number;
perPage: number; perPage: number;
@ -125,8 +129,8 @@ export async function loadAlerts({
search: searchText, search: searchText,
filter: filters.length ? filters.join(' and ') : undefined, filter: filters.length ? filters.join(' and ') : undefined,
default_search_operator: 'AND', default_search_operator: 'AND',
sort_field: 'name.keyword', sort_field: sort.field,
sort_order: 'asc', sort_order: sort.direction,
}, },
}); });
} }

View file

@ -363,6 +363,28 @@ describe('alerts_list component with items', () => {
wrapper.find('EuiButton[data-test-subj="confirmModalConfirmButton"]').simulate('click'); wrapper.find('EuiButton[data-test-subj="confirmModalConfirmButton"]').simulate('click');
expect(global.open).toHaveBeenCalled(); expect(global.open).toHaveBeenCalled();
}); });
it('sorts alerts when clicking the name column', async () => {
await setup();
wrapper
.find('[data-test-subj="tableHeaderCell_name_0"] .euiTableHeaderButton')
.first()
.simulate('click');
await act(async () => {
await nextTick();
wrapper.update();
});
expect(loadAlerts).toHaveBeenCalledWith(
expect.objectContaining({
sort: {
field: 'name',
direction: 'desc',
},
})
);
});
}); });
describe('alerts_list component empty with show only capability', () => { describe('alerts_list component empty with show only capability', () => {

View file

@ -26,6 +26,7 @@ import {
EuiHealth, EuiHealth,
EuiText, EuiText,
EuiToolTip, EuiToolTip,
EuiTableSortingType,
} from '@elastic/eui'; } from '@elastic/eui';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
@ -99,6 +100,10 @@ export const AlertsList: React.FunctionComponent = () => {
const [alertStatusesFilter, setAlertStatusesFilter] = useState<string[]>([]); const [alertStatusesFilter, setAlertStatusesFilter] = useState<string[]>([]);
const [alertFlyoutVisible, setAlertFlyoutVisibility] = useState<boolean>(false); const [alertFlyoutVisible, setAlertFlyoutVisibility] = useState<boolean>(false);
const [dismissAlertErrors, setDismissAlertErrors] = useState<boolean>(false); const [dismissAlertErrors, setDismissAlertErrors] = useState<boolean>(false);
const [sort, setSort] = useState<EuiTableSortingType<AlertTableItem>['sort']>({
field: 'name',
direction: 'asc',
});
const [manageLicenseModalOpts, setManageLicenseModalOpts] = useState<{ const [manageLicenseModalOpts, setManageLicenseModalOpts] = useState<{
licenseType: string; licenseType: string;
alertTypeId: string; alertTypeId: string;
@ -194,6 +199,7 @@ export const AlertsList: React.FunctionComponent = () => {
typesFilter, typesFilter,
actionTypesFilter, actionTypesFilter,
alertStatusesFilter, alertStatusesFilter,
sort,
}); });
await loadAlertAggs(); await loadAlertAggs();
setAlertsState({ setAlertsState({
@ -307,7 +313,7 @@ export const AlertsList: React.FunctionComponent = () => {
'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.nameTitle', 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.nameTitle',
{ defaultMessage: 'Name' } { defaultMessage: 'Name' }
), ),
sortable: false, sortable: true,
truncateText: true, truncateText: true,
width: '35%', width: '35%',
'data-test-subj': 'alertsTableCell-name', 'data-test-subj': 'alertsTableCell-name',
@ -325,17 +331,17 @@ export const AlertsList: React.FunctionComponent = () => {
}, },
}, },
{ {
field: 'executionStatus', field: 'executionStatus.status',
name: i18n.translate( name: i18n.translate(
'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.statusTitle', 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.statusTitle',
{ defaultMessage: 'Status' } { defaultMessage: 'Status' }
), ),
sortable: false, sortable: true,
truncateText: false, truncateText: false,
width: '150px', width: '150px',
'data-test-subj': 'alertsTableCell-status', 'data-test-subj': 'alertsTableCell-status',
render: (executionStatus: AlertExecutionStatus, item: AlertTableItem) => { render: (executionStatus: AlertExecutionStatus, item: AlertTableItem) => {
return renderAlertExecutionStatus(executionStatus, item); return renderAlertExecutionStatus(item.executionStatus, item);
}, },
}, },
{ {
@ -348,9 +354,9 @@ export const AlertsList: React.FunctionComponent = () => {
'data-test-subj': 'alertsTableCell-tagsText', 'data-test-subj': 'alertsTableCell-tagsText',
}, },
{ {
field: 'actionsText', field: 'actionsCount',
name: i18n.translate( name: i18n.translate(
'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsText', 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actionsCount',
{ defaultMessage: 'Actions' } { defaultMessage: 'Actions' }
), ),
render: (count: number, item: AlertTableItem) => { render: (count: number, item: AlertTableItem) => {
@ -361,7 +367,7 @@ export const AlertsList: React.FunctionComponent = () => {
); );
}, },
sortable: false, sortable: false,
'data-test-subj': 'alertsTableCell-actionsText', 'data-test-subj': 'alertsTableCell-actionsCount',
}, },
{ {
field: 'alertType', field: 'alertType',
@ -655,6 +661,7 @@ export const AlertsList: React.FunctionComponent = () => {
} }
itemId="id" itemId="id"
columns={alertsTableColumns} columns={alertsTableColumns}
sorting={{ sort }}
rowProps={(item: AlertTableItem) => ({ rowProps={(item: AlertTableItem) => ({
'data-test-subj': 'alert-row', 'data-test-subj': 'alert-row',
className: !alertTypesState.data.get(item.alertTypeId)?.enabledInLicense className: !alertTypesState.data.get(item.alertTypeId)?.enabledInLicense
@ -680,8 +687,19 @@ export const AlertsList: React.FunctionComponent = () => {
setSelectedIds(updatedSelectedItemsList.map((item) => item.id)); setSelectedIds(updatedSelectedItemsList.map((item) => item.id));
}, },
}} }}
onChange={({ page: changedPage }: { page: Pagination }) => { onChange={({
setPage(changedPage); page: changedPage,
sort: changedSort,
}: {
page?: Pagination;
sort?: EuiTableSortingType<AlertTableItem>['sort'];
}) => {
if (changedPage) {
setPage(changedPage);
}
if (changedSort) {
setSort(changedSort);
}
}} }}
/> />
{manageLicenseModalOpts && ( {manageLicenseModalOpts && (
@ -797,7 +815,7 @@ function convertAlertsToTableItems(
) { ) {
return alerts.map((alert) => ({ return alerts.map((alert) => ({
...alert, ...alert,
actionsText: alert.actions.length, actionsCount: alert.actions.length,
tagsText: alert.tags.join(', '), tagsText: alert.tags.join(', '),
alertType: alertTypesIndex.get(alert.alertTypeId)?.name ?? alert.alertTypeId, alertType: alertTypesIndex.get(alert.alertTypeId)?.name ?? alert.alertTypeId,
isEditable: isEditable:

View file

@ -83,6 +83,11 @@ export interface Pagination {
size: number; size: number;
} }
export interface Sorting {
field: string;
direction: string;
}
export interface ActionTypeModel<ActionConfig = any, ActionSecrets = any, ActionParams = any> { export interface ActionTypeModel<ActionConfig = any, ActionSecrets = any, ActionParams = any> {
id: string; id: string;
iconClass: string; iconClass: string;
@ -191,6 +196,7 @@ export type AlertUpdates = Omit<Alert, 'id' | 'executionStatus'>;
export interface AlertTableItem extends Alert { export interface AlertTableItem extends Alert {
alertType: AlertType['name']; alertType: AlertType['name'];
tagsText: string; tagsText: string;
actionsCount: number;
isEditable: boolean; isEditable: boolean;
enabledInLicense: boolean; enabledInLicense: boolean;
} }