Skip to content

Commit

Permalink
adds pagination on Alert Instances list on Alert Details page (#57524)
Browse files Browse the repository at this point in the history
* added pagination on alert instances page

* extracted default page size to a constant for alerting UI as a whole

* Fix test failure

Co-authored-by: Elastic Machine <[email protected]>
Co-authored-by: Mike Côté <[email protected]>
  • Loading branch information
3 people committed Feb 19, 2020
1 parent 2366d0d commit 0e967a3
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ export enum SORT_ORDERS {
ASCENDING = 'asc',
DESCENDING = 'desc',
}

export const DEFAULT_SEARCH_PAGE_SIZE: number = 10;
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { Fragment } from 'react';
import React, { Fragment, useState } from 'react';
import moment, { Duration } from 'moment';
import { i18n } from '@kbn/i18n';
import { EuiBasicTable, EuiButtonToggle, EuiBadge, EuiHealth } from '@elastic/eui';
// @ts-ignore
import { RIGHT_ALIGNMENT, CENTER_ALIGNMENT } from '@elastic/eui/lib/services';
import { padLeft, difference } from 'lodash';
import { padLeft, difference, chunk } from 'lodash';
import { FormattedMessage } from '@kbn/i18n/react';
import { Alert, AlertTaskState, RawAlertInstance } from '../../../../types';
import { Alert, AlertTaskState, RawAlertInstance, Pagination } from '../../../../types';
import {
ComponentOpts as AlertApis,
withBulkAlertOperations,
} from '../../common/components/with_bulk_alert_api_operations';
import { DEFAULT_SEARCH_PAGE_SIZE } from '../../../constants';

type AlertInstancesProps = {
alert: Alert;
Expand Down Expand Up @@ -134,22 +135,39 @@ export function AlertInstances({
unmuteAlertInstance,
requestRefresh,
}: AlertInstancesProps) {
const [pagination, setPagination] = useState<Pagination>({
index: 0,
size: DEFAULT_SEARCH_PAGE_SIZE,
});

const mergedAlertInstances = [
...Object.entries(alertInstances).map(([instanceId, instance]) =>
alertInstanceToListItem(alert, instanceId, instance)
),
...difference(alert.mutedInstanceIds, Object.keys(alertInstances)).map(instanceId =>
alertInstanceToListItem(alert, instanceId)
),
];
const pageOfAlertInstances = getPage(mergedAlertInstances, pagination);

const onMuteAction = async (instance: AlertInstanceListItem) => {
await (instance.isMuted
? unmuteAlertInstance(alert, instance.instance)
: muteAlertInstance(alert, instance.instance));
requestRefresh();
};

return (
<EuiBasicTable
items={[
...Object.entries(alertInstances).map(([instanceId, instance]) =>
alertInstanceToListItem(alert, instanceId, instance)
),
...difference(alert.mutedInstanceIds, Object.keys(alertInstances)).map(instanceId =>
alertInstanceToListItem(alert, instanceId)
),
]}
items={pageOfAlertInstances}
pagination={{
pageIndex: pagination.index,
pageSize: pagination.size,
totalItemCount: mergedAlertInstances.length,
}}
onChange={({ page: changedPage }: { page: Pagination }) => {
setPagination(changedPage);
}}
rowProps={() => ({
'data-test-subj': 'alert-instance-row',
})}
Expand All @@ -163,6 +181,10 @@ export function AlertInstances({
}
export const AlertInstancesWithApi = withBulkAlertOperations(AlertInstances);

function getPage(items: any[], pagination: Pagination) {
return chunk(items, pagination.size)[pagination.index] || [];
}

interface AlertInstanceListItemStatus {
label: string;
healthColor: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { ActionTypeFilter } from './action_type_filter';
import { loadAlerts, loadAlertTypes } from '../../../lib/alert_api';
import { loadActionTypes } from '../../../lib/action_connector_api';
import { hasDeleteAlertsCapability, hasSaveAlertsCapability } from '../../../lib/capabilities';
import { routeToAlertDetails } from '../../../constants';
import { routeToAlertDetails, DEFAULT_SEARCH_PAGE_SIZE } from '../../../constants';

const ENTER_KEY = 13;

Expand Down Expand Up @@ -67,7 +67,7 @@ export const AlertsList: React.FunctionComponent = () => {
const [actionTypes, setActionTypes] = useState<ActionType[]>([]);
const [selectedIds, setSelectedIds] = useState<string[]>([]);
const [isPerformingAction, setIsPerformingAction] = useState<boolean>(false);
const [page, setPage] = useState<Pagination>({ index: 0, size: 10 });
const [page, setPage] = useState<Pagination>({ index: 0, size: DEFAULT_SEARCH_PAGE_SIZE });
const [searchText, setSearchText] = useState<string | undefined>();
const [inputText, setInputText] = useState<string | undefined>();
const [typesFilter, setTypesFilter] = useState<string[]>([]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import expect from '@kbn/expect';
import uuid from 'uuid';
import { omit, mapValues } from 'lodash';
import { omit, mapValues, range, flatten } from 'lodash';
import moment from 'moment';
import { FtrProviderContext } from '../../ftr_provider_context';

Expand Down Expand Up @@ -331,5 +331,96 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await pageObjects.alertDetailsUI.ensureAlertInstanceExistance('eu-east', false);
});
});

describe('Alert Instance Pagination', function() {
const testRunUuid = uuid.v4();
let alert: any;

before(async () => {
await pageObjects.common.navigateToApp('triggersActions');

const actions = await Promise.all([
alerting.actions.createAction({
name: `server-log-${testRunUuid}-${0}`,
actionTypeId: '.server-log',
config: {},
secrets: {},
}),
alerting.actions.createAction({
name: `server-log-${testRunUuid}-${1}`,
actionTypeId: '.server-log',
config: {},
secrets: {},
}),
]);

const instances = flatten(
range(10).map(index => [
{ id: `us-central-${index}` },
{ id: `us-east-${index}` },
{ id: `us-west-${index}` },
])
);
alert = await alerting.alerts.createAlwaysFiringWithActions(
`test-alert-${testRunUuid}`,
actions.map(action => ({
id: action.id,
group: 'default',
params: {
message: 'from alert 1s',
level: 'warn',
},
})),
{
instances,
}
);

// refresh to see alert
await browser.refresh();

await pageObjects.header.waitUntilLoadingHasFinished();

// Verify content
await testSubjects.existOrFail('alertsList');

// click on first alert
await pageObjects.triggersActionsUI.clickOnAlertInAlertsList(alert.name);

// await first run to complete so we have an initial state
await retry.try(async () => {
const { alertInstances } = await alerting.alerts.getAlertState(alert.id);
expect(Object.keys(alertInstances).length).to.eql(instances.length);
});
});

const PAGE_SIZE = 10;
it('renders the first page', async () => {
// Verify content
await testSubjects.existOrFail('alertInstancesList');

const { alertInstances } = await alerting.alerts.getAlertState(alert.id);

const items = await pageObjects.alertDetailsUI.getAlertInstancesList();
expect(items.length).to.eql(PAGE_SIZE);

const [firstItem] = items;
expect(firstItem.instance).to.eql(Object.keys(alertInstances)[0]);
});

it('navigates to the next page', async () => {
// Verify content
await testSubjects.existOrFail('alertInstancesList');

const { alertInstances } = await alerting.alerts.getAlertState(alert.id);

await pageObjects.alertDetailsUI.clickPaginationNextPage();

await retry.try(async () => {
const [firstItem] = await pageObjects.alertDetailsUI.getAlertInstancesList();
expect(firstItem.instance).to.eql(Object.keys(alertInstances)[PAGE_SIZE]);
});
});
});
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,9 @@ export function AlertDetailsPageProvider({ getService }: FtrProviderContext) {
).to.eql(shouldExist ? 1 : 0);
});
},
async clickPaginationNextPage() {
const nextButton = await testSubjects.find(`pagination-button-next`);
nextButton.click();
},
};
}

0 comments on commit 0e967a3

Please sign in to comment.