diff --git a/public/pages/Dashboard/containers/Dashboard.js b/public/pages/Dashboard/containers/Dashboard.js index 5e4f0f0e3..e9d519f12 100644 --- a/public/pages/Dashboard/containers/Dashboard.js +++ b/public/pages/Dashboard/containers/Dashboard.js @@ -32,9 +32,10 @@ import { EuiBasicTable, EuiButton, EuiHorizontalRule, EuiIcon } from '@elastic/e import ContentPanel from '../../../components/ContentPanel'; import DashboardEmptyPrompt from '../components/DashboardEmptyPrompt'; import DashboardControls from '../components/DashboardControls'; -import { columns } from '../utils/tableUtils'; +import { columns, alertColumns } from '../utils/tableUtils'; import { OPENSEARCH_DASHBOARDS_AD_PLUGIN } from '../../../utils/constants'; import { backendErrorNotification } from '../../../utils/helpers'; +import { groupAlertsByTrigger } from '../utils/helpers'; const DEFAULT_PAGE_SIZE_OPTIONS = [5, 10, 20, 50]; const DEFAULT_QUERY_PARAMS = { @@ -67,6 +68,7 @@ export default class Dashboard extends Component { this.state = { alerts: [], + alertsByTriggers: [], alertState, monitorIds: this.props.monitorIds, page: Math.floor(from / size), @@ -77,6 +79,7 @@ export default class Dashboard extends Component { sortDirection, sortField, totalAlerts: 0, + totalTriggers: 0, }; } @@ -198,9 +201,12 @@ export default class Dashboard extends Component { httpClient.get('../api/alerting/alerts', { query: params }).then((resp) => { if (resp.ok) { const { alerts, totalAlerts } = resp; + const alertsByTriggers = groupAlertsByTrigger(alerts); this.setState({ alerts, totalAlerts, + totalTriggers: alertsByTriggers.length, + alertsByTriggers, }); } else { console.log('error getting alerts:', resp); @@ -301,6 +307,7 @@ export default class Dashboard extends Component { render() { const { alerts, + alertsByTriggers, alertState, page, search, @@ -309,13 +316,15 @@ export default class Dashboard extends Component { sortDirection, sortField, totalAlerts, + totalTriggers, } = this.state; const { monitorIds, detectorIds, onCreateTrigger } = this.props; - + const perAlertView = typeof onCreateTrigger === 'function'; + const totalItems = perAlertView ? totalAlerts : totalTriggers; const pagination = { pageIndex: page, pageSize: size, - totalItemCount: Math.min(MAX_ALERT_COUNT, totalAlerts), + totalItemCount: Math.min(MAX_ALERT_COUNT, totalItems), pageSizeOptions: DEFAULT_PAGE_SIZE_OPTIONS, }; @@ -350,14 +359,14 @@ export default class Dashboard extends Component { return ( `${item.id}-${item.version}`} - columns={columns} + itemId={(item) => `${item.triggerID}-${item.version}`} + columns={perAlertView ? columns : alertColumns} pagination={pagination} sorting={sorting} isSelectable={true} diff --git a/public/pages/Dashboard/utils/constants.js b/public/pages/Dashboard/utils/constants.js new file mode 100644 index 000000000..3d252235f --- /dev/null +++ b/public/pages/Dashboard/utils/constants.js @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +export const EMPTY_ALERT_LIST = { + ACTIVE: 0, + ACKNOWLEDGED: 0, + ERROR: 0, + total: 0, + alerts: [], +}; diff --git a/public/pages/Dashboard/utils/helpers.js b/public/pages/Dashboard/utils/helpers.js new file mode 100644 index 000000000..5aedf66a6 --- /dev/null +++ b/public/pages/Dashboard/utils/helpers.js @@ -0,0 +1,61 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import { EMPTY_ALERT_LIST } from './constants'; + +export function groupAlertsByTrigger(alerts) { + let alertsByTriggers = new Map(); + alerts.map((alert) => { + const triggerID = alert.trigger_id; + // const prevAlertList = alertsByTriggers.has(triggerID) ? alertsByTriggers.get(triggerID) : EMPTY_ALERT_LIST; + const newAlertList = alertsByTriggers.has(triggerID) + ? addAlert(alertsByTriggers.get(triggerID), alert) + : addFirstAlert(alert); + alertsByTriggers.set(triggerID, newAlertList); + }); + + return Array.from(alertsByTriggers, ([triggerID, alerts]) => ({ ...alerts, triggerID })); +} + +export function addFirstAlert(firstAlert) { + const { + state, + version, + trigger_name, + severity, + start_time, + last_notification_time, + monitor_name, + monitor_id, + } = firstAlert; + let newAlertList = _.cloneDeep(EMPTY_ALERT_LIST); + newAlertList[state]++; + newAlertList.total++; + newAlertList.alerts.push(firstAlert); + return { + ...newAlertList, + version, + trigger_name, + severity, + start_time, + last_notification_time, + monitor_name, + monitor_id, + }; +} +export function addAlert(alertList, newAlert) { + const state = newAlert.state; + alertList[state]++; + alertList.total++; + alertList.alerts.push(newAlert); + //Compare start time and last updated time + return alertList; +} diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index a814cff21..f072043c9 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -115,3 +115,70 @@ export const columns = [ render: (content) => (content ? renderAggAlertContent(content.bucket_keys) : '-'), }, ]; + +export const alertColumns = [ + { + field: 'total', + name: 'Alerts', + sortable: true, + truncateText: false, + render: (total) => {`${total} alerts`}, + }, + { + field: 'ACTIVE', + name: 'Active', + sortable: true, + truncateText: false, + }, + { + field: 'ACKNOWLEDGED', + name: 'Acknowledged', + sortable: true, + truncateText: false, + }, + { + field: 'ERROR', + name: 'Errors', + sortable: true, + truncateText: false, + }, + { + field: 'trigger_name', + name: 'Trigger name', + sortable: true, + truncateText: true, + textOnly: true, + }, + { + field: 'start_time', + name: 'Trigger start time', + sortable: true, + truncateText: false, + render: renderTime, + dataType: 'date', + }, + { + field: 'last_notification_time', + name: 'Trigger last updated', + sortable: true, + truncateText: true, + render: renderTime, + dataType: 'date', + }, + { + field: 'severity', + name: 'Severity', + sortable: false, + truncateText: false, + }, + { + field: 'monitor_name', + name: 'Monitor name', + sortable: true, + truncateText: true, + textOnly: true, + render: (name, alert) => ( + {name} + ), + }, +]; diff --git a/public/pages/Home/Home.js b/public/pages/Home/Home.js index 04220bc1b..b89a3fd70 100644 --- a/public/pages/Home/Home.js +++ b/public/pages/Home/Home.js @@ -35,7 +35,7 @@ import DestinationsList from '../Destinations/containers/DestinationsList'; const getSelectedTabId = (pathname) => { if (pathname.includes('monitors')) return 'monitors'; if (pathname.includes('destinations')) return 'destinations'; - return 'dashboard'; + return 'alerts'; }; export default class Home extends Component { @@ -49,8 +49,8 @@ export default class Home extends Component { this.state = { selectedTabId }; this.tabs = [ { - id: 'dashboard', - name: 'Dashboard', + id: 'alerts', + name: 'Alerts', route: 'dashboard', }, {