Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mikecote committed Mar 3, 2021
1 parent 16a3780 commit 005d2e3
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 21 deletions.
2 changes: 2 additions & 0 deletions x-pack/plugins/alerts/server/alerts_client/alerts_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import { partiallyUpdateAlert } from '../saved_objects';
import { markApiKeyForInvalidation } from '../invalidate_pending_api_keys/mark_api_key_for_invalidation';
import { alertAuditEvent, AlertAuditAction } from './audit_events';
import { nodeBuilder } from '../../../../../src/plugins/data/common';
import { mapSortField } from './lib';

export interface RegistryAlertTypeWithAuth extends RegistryAlertType {
authorizedConsumers: string[];
Expand Down Expand Up @@ -465,6 +466,7 @@ export class AlertsClient {
saved_objects: data,
} = await this.unsecuredSavedObjectsClient.find<RawAlert>({
...options,
sortField: mapSortField(options.sortField),
filter:
(authorizationFilter && options.filter
? nodeBuilder.and([esKuery.fromKueryExpression(options.filter), authorizationFilter])
Expand Down
8 changes: 8 additions & 0 deletions x-pack/plugins/alerts/server/alerts_client/lib/index.ts
Original file line number Diff line number Diff line change
@@ -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';
Original file line number Diff line number Diff line change
@@ -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');
});
});
14 changes: 14 additions & 0 deletions x-pack/plugins/alerts/server/alerts_client/lib/map_sort_field.ts
Original file line number Diff line number Diff line change
@@ -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;
}
11 changes: 11 additions & 0 deletions x-pack/plugins/alerts/server/alerts_client/tests/find.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ beforeEach(() => {

setGlobalDate();

jest.mock('../lib/map_sort_field', () => ({
mapSortField: jest.fn(),
}));

describe('find()', () => {
const listedTypes = new Set<RegistryAlertType>([
{
Expand Down Expand Up @@ -172,12 +176,19 @@ describe('find()', () => {
Object {
"fields": undefined,
"filter": undefined,
"sortField": undefined,
"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', () => {
test('ensures user is query filter types down to those the user is authorized to find', async () => {
const filter = esKuery.fromKueryExpression(
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -21295,7 +21295,7 @@
"xpack.triggersActionsUI.sections.alertsList.alertErrorReasonRunning": "アラートの実行中にエラーが発生しました。",
"xpack.triggersActionsUI.sections.alertsList.alertErrorReasonUnknown": "不明な理由でエラーが発生しました。",
"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.intervalTitle": "次の間隔で実行",
"xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.nameTitle": "名前",
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -21345,7 +21345,7 @@
"xpack.triggersActionsUI.sections.alertsList.alertErrorReasonRunning": "运行告警时发生错误。",
"xpack.triggersActionsUI.sections.alertsList.alertErrorReasonUnknown": "由于未知原因发生错误。",
"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.intervalTitle": "运行间隔",
"xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.nameTitle": "名称",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ describe('loadAlerts', () => {
"per_page": 10,
"search": undefined,
"search_fields": undefined,
"sort_field": "name.keyword",
"sort_field": "name",
"sort_order": "asc",
},
},
Expand Down Expand Up @@ -210,7 +210,7 @@ describe('loadAlerts', () => {
"per_page": 10,
"search": "apples",
"search_fields": "[\\"name\\",\\"tags\\"]",
"sort_field": "name.keyword",
"sort_field": "name",
"sort_order": "asc",
},
},
Expand Down Expand Up @@ -244,7 +244,7 @@ describe('loadAlerts', () => {
"per_page": 10,
"search": "foo",
"search_fields": "[\\"name\\",\\"tags\\"]",
"sort_field": "name.keyword",
"sort_field": "name",
"sort_order": "asc",
},
},
Expand Down Expand Up @@ -278,7 +278,7 @@ describe('loadAlerts', () => {
"per_page": 10,
"search": undefined,
"search_fields": undefined,
"sort_field": "name.keyword",
"sort_field": "name",
"sort_order": "asc",
},
},
Expand Down Expand Up @@ -313,7 +313,7 @@ describe('loadAlerts', () => {
"per_page": 10,
"search": "baz",
"search_fields": "[\\"name\\",\\"tags\\"]",
"sort_field": "name.keyword",
"sort_field": "name",
"sort_order": "asc",
},
},
Expand Down Expand Up @@ -348,7 +348,7 @@ describe('loadAlerts', () => {
"per_page": 10,
"search": "apples, foo, baz",
"search_fields": "[\\"name\\",\\"tags\\"]",
"sort_field": "name.keyword",
"sort_field": "name",
"sort_order": "asc",
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
AlertUpdates,
AlertTaskState,
AlertInstanceSummary,
Pagination,
Sorting,
} from '../../types';

export async function loadAlertTypes({ http }: { http: HttpSetup }): Promise<AlertType[]> {
Expand Down Expand Up @@ -103,13 +105,15 @@ export async function loadAlerts({
typesFilter,
actionTypesFilter,
alertStatusesFilter,
sort = { field: 'name', direction: 'asc' },
}: {
http: HttpSetup;
page: { index: number; size: number };
page: Pagination;
searchText?: string;
typesFilter?: string[];
actionTypesFilter?: string[];
alertStatusesFilter?: string[];
sort?: Sorting;
}): Promise<{
page: number;
perPage: number;
Expand All @@ -125,8 +129,8 @@ export async function loadAlerts({
search: searchText,
filter: filters.length ? filters.join(' and ') : undefined,
default_search_operator: 'AND',
sort_field: 'name.keyword',
sort_order: 'asc',
sort_field: sort.field,
sort_order: sort.direction,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,28 @@ describe('alerts_list component with items', () => {
wrapper.find('EuiButton[data-test-subj="confirmModalConfirmButton"]').simulate('click');
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', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
EuiHealth,
EuiText,
EuiToolTip,
EuiTableSortingType,
} from '@elastic/eui';
import { useHistory } from 'react-router-dom';

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

export interface Sorting {
field: string;
direction: string;
}

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

0 comments on commit 005d2e3

Please sign in to comment.