From a859a98cae540bbc0a7bd92d11eb69233935fc4d Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 28 Sep 2020 17:14:25 -0700 Subject: [PATCH 01/12] Added ui for alert failures banner --- .../alerts_list/components/alerts_list.tsx | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index 7d0354589ecb8..4cad8c5dfad2d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -19,6 +19,8 @@ import { EuiLink, EuiLoadingSpinner, EuiEmptyPrompt, + EuiCallOut, + EuiButtonEmpty, } from '@elastic/eui'; import { useHistory } from 'react-router-dom'; @@ -428,6 +430,24 @@ export const AlertsList: React.FunctionComponent = () => { setAlertsState({ ...alertsState, isLoading }); }} /> + + } + iconType="alert" + > + + + + + + + {loadedItems.length || isFilterApplied ? ( table From e9d8acc1d585831bfceadce3aa0a2df9e7583f04 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 30 Sep 2020 14:11:18 -0700 Subject: [PATCH 02/12] Added UI for alerts statuses --- x-pack/plugins/alerts/common/alert.ts | 13 ++ .../public/application/lib/alert_api.ts | 5 + .../components/alert_status_filter.tsx | 96 ++++++++++ .../alerts_list/components/alerts_list.tsx | 164 ++++++++++++++---- 4 files changed, 240 insertions(+), 38 deletions(-) create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx diff --git a/x-pack/plugins/alerts/common/alert.ts b/x-pack/plugins/alerts/common/alert.ts index 3ff7ed742e810..ec4237fdc711e 100644 --- a/x-pack/plugins/alerts/common/alert.ts +++ b/x-pack/plugins/alerts/common/alert.ts @@ -15,6 +15,19 @@ export interface IntervalSchedule extends SavedObjectAttributes { interval: string; } +// for the `typeof ThingValues[number]` types below, become string types that +// only accept the values in the associated string arrays +export const AlertExecutionStatusValues = ['ok', 'active', 'error', 'unknown'] as const; +export type AlertExecutionStatuses = typeof AlertExecutionStatusValues[number]; + +export const AlertExecutionStatusErrorReasonValues = [ + 'read', + 'decrypt', + 'execute', + 'unknown', +] as const; +export type AlertExecutionStatusErrorReasons = typeof AlertExecutionStatusErrorReasonValues[number]; + export type AlertActionParams = SavedObjectAttributes; export interface AlertAction { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts index 97feea6ba8a0f..4444cb8c959a2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts @@ -70,12 +70,14 @@ export async function loadAlerts({ searchText, typesFilter, actionTypesFilter, + alertStatusesFilter, }: { http: HttpSetup; page: { index: number; size: number }; searchText?: string; typesFilter?: string[]; actionTypesFilter?: string[]; + alertStatusesFilter?: string[]; }): Promise<{ page: number; perPage: number; @@ -97,6 +99,9 @@ export async function loadAlerts({ ].join('') ); } + if (alertStatusesFilter && alertStatusesFilter.length) { + filters.push(`alert.attributes.status:(${alertStatusesFilter.join(' or ')})`); + } return await http.get(`${BASE_ALERT_API_PATH}/_find`, { query: { page: page.index + 1, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx new file mode 100644 index 0000000000000..5fc3c381b4818 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useEffect, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiFilterGroup, + EuiPopover, + EuiFilterButton, + EuiFilterSelectItem, + EuiHealth, +} from '@elastic/eui'; +import { AlertExecutionStatusValues } from '../../../../../../alerts/common'; + +interface AlertStatusFilterProps { + onChange?: (selectedAlertStatusesIds: string[]) => void; +} + +export const AlertStatusFilter: React.FunctionComponent = ({ + onChange, +}: AlertStatusFilterProps) => { + const [selectedValues, setSelectedValues] = useState([]); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + useEffect(() => { + if (onChange) { + onChange(selectedValues); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedValues]); + + return ( + + setIsPopoverOpen(false)} + button={ + 0} + numActiveFilters={selectedValues.length} + numFilters={selectedValues.length} + onClick={() => setIsPopoverOpen(!isPopoverOpen)} + > + + + } + > +
+ {AlertExecutionStatusValues.map((item: string) => { + const healthColor = getHealthColor(item); + return ( + { + const isPreviouslyChecked = selectedValues.includes(item); + if (isPreviouslyChecked) { + setSelectedValues(selectedValues.filter((val) => val !== item)); + } else { + setSelectedValues(selectedValues.concat(item)); + } + }} + checked={selectedValues.includes(item) ? 'on' : undefined} + > + {item} + + ); + })} +
+
+
+ ); +}; + +export function getHealthColor(status: string) { + switch (status) { + case 'active': + return 'success'; + break; + case 'error': + return 'danger'; + break; + case 'ok': + return 'subdued'; + break; + default: + return 'warning'; + } +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index 4cad8c5dfad2d..00a011a26514b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -21,6 +21,8 @@ import { EuiEmptyPrompt, EuiCallOut, EuiButtonEmpty, + EuiHealth, + EuiText, } from '@elastic/eui'; import { useHistory } from 'react-router-dom'; @@ -34,13 +36,14 @@ import { AlertQuickEditButtonsWithApi as AlertQuickEditButtons } from '../../com import { CollapsedItemActionsWithApi as CollapsedItemActions } from './collapsed_item_actions'; import { TypeFilter } from './type_filter'; import { ActionTypeFilter } from './action_type_filter'; +import { AlertStatusFilter, getHealthColor } from './alert_status_filter'; import { loadAlerts, loadAlertTypes, deleteAlerts } from '../../../lib/alert_api'; import { loadActionTypes } from '../../../lib/action_connector_api'; import { hasExecuteActionsCapability } from '../../../lib/capabilities'; import { routeToAlertDetails, DEFAULT_SEARCH_PAGE_SIZE } from '../../../constants'; import { DeleteModalConfirmation } from '../../../components/delete_modal_confirmation'; import { EmptyPrompt } from '../../../components/prompts/empty_prompt'; -import { ALERTS_FEATURE_ID } from '../../../../../../alerts/common'; +import { AlertExecutionStatusValues, ALERTS_FEATURE_ID } from '../../../../../../alerts/common'; import { hasAllPrivilege } from '../../../lib/capabilities'; const ENTER_KEY = 13; @@ -79,7 +82,10 @@ export const AlertsList: React.FunctionComponent = () => { const [inputText, setInputText] = useState(); const [typesFilter, setTypesFilter] = useState([]); const [actionTypesFilter, setActionTypesFilter] = useState([]); + const [alertStatusesFilter, setAlertStatusesFilter] = useState([]); const [alertFlyoutVisible, setAlertFlyoutVisibility] = useState(false); + const [dissmissAlertErrors, setDissmissAlertErrors] = useState(false); + const [alertsStatusesTotal, setAlertsStatusesTotal] = useState>({}); const [alertTypesState, setAlertTypesState] = useState({ isLoading: false, isInitialized: false, @@ -95,7 +101,7 @@ export const AlertsList: React.FunctionComponent = () => { useEffect(() => { loadAlertsData(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [alertTypesState, page, searchText, typesFilter, actionTypesFilter]); + }, [alertTypesState, page, searchText, typesFilter, actionTypesFilter, alertStatusesFilter]); useEffect(() => { (async () => { @@ -148,6 +154,7 @@ export const AlertsList: React.FunctionComponent = () => { searchText, typesFilter, actionTypesFilter, + alertStatusesFilter, }); setAlertsState({ isLoading: false, @@ -172,7 +179,49 @@ export const AlertsList: React.FunctionComponent = () => { } } + async function loadAlertsTotalStatuses() { + const hasAnyAuthorizedAlertType = alertTypesState.data.size > 0; + if (hasAnyAuthorizedAlertType) { + try { + AlertExecutionStatusValues.map(async (status: string) => { + const alertsTotalResponse = await loadAlerts({ + http, + page: { index: 0, size: 0 }, + searchText, + typesFilter, + actionTypesFilter, + alertStatusesFilter: [status], + }); + setAlertsStatusesTotal({ ...alertsStatusesTotal, [status]: alertsTotalResponse.total }); + }); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.unableToLoadAlertsStatusesInfoMessage', + { + defaultMessage: 'Unable to load alert statuses info', + } + ), + }); + } + } + } + const alertsTableColumns = [ + { + field: 'status', + name: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.statusTitle', + { defaultMessage: 'Status' } + ), + sortable: false, + truncateText: false, + 'data-test-subj': 'alertsTableCell-status', + render: (status: string) => { + const healthColor = getHealthColor(status); + return {status}; + }, + }, { field: 'name', name: i18n.translate( @@ -277,24 +326,12 @@ export const AlertsList: React.FunctionComponent = () => { actionTypes={actionTypes} onChange={(ids: string[]) => setActionTypesFilter(ids)} />, + setAlertStatusesFilter(ids)} + />, ]; - if (authorizedToCreateAnyAlerts) { - toolsRight.push( - setAlertFlyoutVisibility(true)} - > - - - ); - } - const authorizedToModifySelectedAlerts = selectedIds.length ? filterAlertsById(alertsState.data, selectedIds).every((selectedAlert) => hasAllPrivilege(selectedAlert, alertTypesState.data.get(selectedAlert.alertTypeId)) @@ -323,6 +360,21 @@ export const AlertsList: React.FunctionComponent = () => { )} + {authorizedToCreateAnyAlerts ? ( + + setAlertFlyoutVisibility(true)} + > + + + + ) : null} { - + + {!dissmissAlertErrors ? ( + + + + } + iconType="alert" + > + setAlertStatusesFilter([AlertExecutionStatusValues[2]])} + > + + + setDissmissAlertErrors(true)}> + + + + + + ) : null} + + + + + + + + + Ok: 1 + + + Active: 0 + + + No data: 0 + + + Errors: 1 + + {/* Large to remain consistent with ActionsList table spacing */} @@ -399,7 +504,8 @@ export const AlertsList: React.FunctionComponent = () => { const isFilterApplied = !( isEmpty(searchText) && isEmpty(typesFilter) && - isEmpty(actionTypesFilter) + isEmpty(actionTypesFilter) && + isEmpty(alertStatusesFilter) ); return ( @@ -430,24 +536,6 @@ export const AlertsList: React.FunctionComponent = () => { setAlertsState({ ...alertsState, isLoading }); }} /> - - } - iconType="alert" - > - - - - - - - {loadedItems.length || isFilterApplied ? ( table From 43c811af241ee97b920a698287e772781752ef39 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 30 Sep 2020 16:19:52 -0700 Subject: [PATCH 03/12] Adjusted form --- .../public/application/lib/alert_api.ts | 2 +- .../alerts_list/components/alerts_list.tsx | 137 ++++++++++++------ 2 files changed, 93 insertions(+), 46 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts index 4444cb8c959a2..888832b339541 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts @@ -100,7 +100,7 @@ export async function loadAlerts({ ); } if (alertStatusesFilter && alertStatusesFilter.length) { - filters.push(`alert.attributes.status:(${alertStatusesFilter.join(' or ')})`); + filters.push(`alert.attributes.executionStatus.status:(${alertStatusesFilter.join(' or ')})`); } return await http.get(`${BASE_ALERT_API_PATH}/_find`, { query: { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index eb704554c750f..207058c84e341 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +/* eslint-disable react-hooks/exhaustive-deps */ + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useEffect, useState, Fragment } from 'react'; @@ -43,7 +45,11 @@ import { hasExecuteActionsCapability } from '../../../lib/capabilities'; import { routeToAlertDetails, DEFAULT_SEARCH_PAGE_SIZE } from '../../../constants'; import { DeleteModalConfirmation } from '../../../components/delete_modal_confirmation'; import { EmptyPrompt } from '../../../components/prompts/empty_prompt'; -import { AlertExecutionStatusValues, ALERTS_FEATURE_ID } from '../../../../../../alerts/common'; +import { + AlertExecutionStatus, + AlertExecutionStatusValues, + ALERTS_FEATURE_ID, +} from '../../../../../../alerts/common'; import { hasAllPrivilege } from '../../../lib/capabilities'; const ENTER_KEY = 13; @@ -85,7 +91,16 @@ export const AlertsList: React.FunctionComponent = () => { const [alertStatusesFilter, setAlertStatusesFilter] = useState([]); const [alertFlyoutVisible, setAlertFlyoutVisibility] = useState(false); const [dissmissAlertErrors, setDissmissAlertErrors] = useState(false); - const [alertsStatusesTotal, setAlertsStatusesTotal] = useState>({}); + const [alertsStatusesTotal, setAlertsStatusesTotal] = useState>( + AlertExecutionStatusValues.reduce( + (prev: Record, status: string) => + ({ + ...prev, + [status]: 0, + } as Record), + {} + ) + ); const [alertTypesState, setAlertTypesState] = useState({ isLoading: false, isInitialized: false, @@ -100,13 +115,14 @@ export const AlertsList: React.FunctionComponent = () => { useEffect(() => { loadAlertsData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [alertTypesState, page, searchText]); - - useEffect(() => { - loadAlertsData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [JSON.stringify(typesFilter), JSON.stringify(actionTypesFilter), JSON.stringify(alertStatusesFilter)]); + }, [ + alertTypesState, + page, + searchText, + JSON.stringify(typesFilter), + JSON.stringify(actionTypesFilter), + JSON.stringify(alertStatusesFilter), + ]); useEffect(() => { (async () => { @@ -128,7 +144,6 @@ export const AlertsList: React.FunctionComponent = () => { setAlertTypesState({ ...alertTypesState, isLoading: false }); } })(); - // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { @@ -145,7 +160,6 @@ export const AlertsList: React.FunctionComponent = () => { }); } })(); - // eslint-disable-next-line react-hooks/exhaustive-deps }, []); async function loadAlertsData() { @@ -161,6 +175,7 @@ export const AlertsList: React.FunctionComponent = () => { actionTypesFilter, alertStatusesFilter, }); + await loadAlertsTotalStatuses(); setAlertsState({ isLoading: false, data: alertsResponse.data, @@ -185,36 +200,35 @@ export const AlertsList: React.FunctionComponent = () => { } async function loadAlertsTotalStatuses() { - const hasAnyAuthorizedAlertType = alertTypesState.data.size > 0; - if (hasAnyAuthorizedAlertType) { - try { - AlertExecutionStatusValues.map(async (status: string) => { - const alertsTotalResponse = await loadAlerts({ - http, - page: { index: 0, size: 0 }, - searchText, - typesFilter, - actionTypesFilter, - alertStatusesFilter: [status], - }); - setAlertsStatusesTotal({ ...alertsStatusesTotal, [status]: alertsTotalResponse.total }); - }); - } catch (e) { - toastNotifications.addDanger({ - title: i18n.translate( - 'xpack.triggersActionsUI.sections.alertsList.unableToLoadAlertsStatusesInfoMessage', - { - defaultMessage: 'Unable to load alert statuses info', - } - ), + let alertsStatuses = {}; + try { + AlertExecutionStatusValues.forEach(async (status: string) => { + const alertsTotalResponse = await loadAlerts({ + http, + page: { index: 0, size: 0 }, + searchText, + typesFilter, + actionTypesFilter, + alertStatusesFilter: [status], }); - } + setAlertsStatusesTotal({ ...alertsStatuses, [status]: alertsTotalResponse.total }); + alertsStatuses = { ...alertsStatuses, [status]: alertsTotalResponse.total }; + }); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.unableToLoadAlertsStatusesInfoMessage', + { + defaultMessage: 'Unable to load alert statuses info', + } + ), + }); } } const alertsTableColumns = [ { - field: 'status', + field: 'executionStatus', name: i18n.translate( 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.statusTitle', { defaultMessage: 'Status' } @@ -222,9 +236,9 @@ export const AlertsList: React.FunctionComponent = () => { sortable: false, truncateText: false, 'data-test-subj': 'alertsTableCell-status', - render: (status: string) => { - const healthColor = getHealthColor(status); - return {status}; + render: (executionStatus: AlertExecutionStatus) => { + const healthColor = getHealthColor(executionStatus.status); + return {executionStatus.status}; }, }, { @@ -408,7 +422,7 @@ export const AlertsList: React.FunctionComponent = () => { - {!dissmissAlertErrors ? ( + {!dissmissAlertErrors && alertsStatusesTotal[AlertExecutionStatusValues[2]] > 0 ? ( { title={ } iconType="alert" @@ -442,23 +461,51 @@ export const AlertsList: React.FunctionComponent = () => { - Ok: 1 + + + - Active: 0 + + + - No data: 0 + + + - Errors: 1 + + + {/* Large to remain consistent with ActionsList table spacing */} From 4dd495cf7c1c8157b5d0645dce83a395535104be Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 1 Oct 2020 12:10:12 -0700 Subject: [PATCH 04/12] Added banned on the details page --- .../components/alert_details.tsx | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx index 6ee7915e2be71..dca8a1dfb8c58 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx @@ -24,9 +24,12 @@ import { EuiSpacer, EuiBetaBadge, EuiButtonEmpty, + EuiButton, + EuiTextColor, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; +import { AlertExecutionStatusValues } from '../../../../../../alerts/common'; import { useAppDependencies } from '../../../app_context'; import { hasAllPrivilege, hasExecuteActionsCapability } from '../../../lib/capabilities'; import { getAlertingSectionBreadcrumb, getAlertDetailsBreadcrumb } from '../../../lib/breadcrumb'; @@ -105,6 +108,7 @@ export const AlertDetails: React.FunctionComponent = ({ const [isEnabled, setIsEnabled] = useState(alert.enabled); const [isMuted, setIsMuted] = useState(alert.muteAll); const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false); + const [dissmissAlertErrors, setDissmissAlertErrors] = useState(false); const setAlert = async () => { history.push(routeToAlertDetails.replace(`:alertId`, alert.id)); @@ -275,6 +279,42 @@ export const AlertDetails: React.FunctionComponent = ({ + {!dissmissAlertErrors && + alert.executionStatus.status === AlertExecutionStatusValues[2] ? ( + + + + } + iconType="alert" + > + +

+ + + +

+
+ + {alert.executionStatus.error?.message} + + + setDissmissAlertErrors(true)}> + + +
+
+
+ ) : null} {alert.enabled ? ( From 2006ca3282d02959ab9f956bb345291257a0f61e Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 1 Oct 2020 13:34:48 -0700 Subject: [PATCH 05/12] Fixed failing intern. check and type checks --- .../components/alert_details.tsx | 12 +++++++--- .../components/alerts_list.test.tsx | 24 +++++++++++++++++++ .../alerts_list/components/alerts_list.tsx | 12 +++++++--- .../triggers_actions_ui/public/types.ts | 2 +- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx index dca8a1dfb8c58..0c16a9909f68c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx @@ -288,7 +288,7 @@ export const AlertDetails: React.FunctionComponent = ({ size="s" title={ = ({

- +

@@ -309,7 +312,10 @@ export const AlertDetails: React.FunctionComponent = ({ setDissmissAlertErrors(true)}> - +
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx index ada881cb93d1e..a151689ce4879 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -168,6 +168,11 @@ describe('alerts_list component with items', () => { throttle: '1m', muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'active', + date: new Date('2020-08-20T19:23:38Z'), + error: null, + }, }, { id: '2', @@ -185,6 +190,14 @@ describe('alerts_list component with items', () => { throttle: '1m', muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'error', + date: new Date('2020-08-20T19:23:38Z'), + error: { + reason: 'unknown', + message: 'test', + }, + }, }, ], }); @@ -246,6 +259,7 @@ describe('alerts_list component with items', () => { await setup(); expect(wrapper.find('EuiBasicTable')).toHaveLength(1); expect(wrapper.find('EuiTableRow')).toHaveLength(2); + expect(wrapper.find('[data-test-subj="alertsTableCell-status"]')).toHaveLength(4); }); }); @@ -351,6 +365,11 @@ describe('alerts_list with show only capability', () => { throttle: '1m', muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'active', + date: new Date('2020-08-20T19:23:38Z'), + error: null, + }, }, { id: '2', @@ -368,6 +387,11 @@ describe('alerts_list with show only capability', () => { throttle: '1m', muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'active', + date: new Date('2020-08-20T19:23:38Z'), + error: null, + }, }, ], }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index 207058c84e341..67fea090bcf89 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -430,7 +430,7 @@ export const AlertsList: React.FunctionComponent = () => { size="s" title={ { color="danger" onClick={() => setAlertStatusesFilter([AlertExecutionStatusValues[2]])} > - + setDissmissAlertErrors(true)}> - + diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index e147f035fbb86..cb297eedd63f7 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -122,7 +122,7 @@ export interface AlertType { export type SanitizedAlertType = Omit; -export type AlertWithoutId = Omit; +export type AlertWithoutId = Omit; export interface AlertTableItem extends Alert { alertType: AlertType['name']; From 9ed9ba5f56b1e1abe7cf6bfbf017e2b6281e7c9d Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 1 Oct 2020 14:00:55 -0700 Subject: [PATCH 06/12] Added unit test for displaying alert error banner --- .../components/alert_details.test.tsx | 37 +++++++++++++++++++ .../components/alert_details.tsx | 3 +- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx index 16d1a5c7c9c65..1212f384f9e4e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx @@ -15,6 +15,7 @@ import { EuiSwitch, EuiBetaBadge, EuiButtonEmpty, + EuiText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ViewInApp } from './view_in_app'; @@ -142,6 +143,38 @@ describe('alert_details', () => { ).toBeTruthy(); }); + it('renders the alert error banner with error message, when alert status is an error', () => { + const alert = mockAlert({ + executionStatus: { + status: 'error', + date: new Date('2020-08-20T19:23:38Z'), + error: { + reason: 'unknown', + message: 'test', + }, + }, + }); + const alertType = { + id: '.noop', + name: 'No Op', + actionGroups: [{ id: 'default', name: 'Default' }], + actionVariables: { context: [], state: [], params: [] }, + defaultActionGroupId: 'default', + producer: ALERTS_FEATURE_ID, + authorizedConsumers, + }; + + expect( + shallow( + + ).containsMatchingElement( + + {'test'} + + ) + ).toBeTruthy(); + }); + describe('actions', () => { it('renders an alert action', () => { const alert = mockAlert({ @@ -757,6 +790,10 @@ function mockAlert(overloads: Partial = {}): Alert { throttle: null, muteAll: false, mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + date: new Date('2020-08-20T19:23:38Z'), + }, ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx index 0c16a9909f68c..4113044fe4583 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx @@ -285,6 +285,7 @@ export const AlertDetails: React.FunctionComponent = ({ = ({ - + {alert.executionStatus.error?.message} From 33bc87bcda99fad88d978338799adbc0d3d5e70a Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 1 Oct 2020 18:37:42 -0700 Subject: [PATCH 07/12] Fixed type check --- .../sections/alert_details/components/alert_details.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx index 67bf65cbe5e7c..51c3e030f44eb 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx @@ -147,7 +147,7 @@ describe('alert_details', () => { const alert = mockAlert({ executionStatus: { status: 'error', - date: new Date('2020-08-20T19:23:38Z'), + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), error: { reason: 'unknown', message: 'test', From f90de57e0cd995e93029c344293b84606e5fc6b5 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 2 Oct 2020 08:29:54 -0700 Subject: [PATCH 08/12] Fixed due to comments --- .../components/alert_details.tsx | 10 ++++----- .../components/alert_status_filter.tsx | 8 ++++++- .../alerts_list/components/alerts_list.tsx | 22 +++++++++++-------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx index 4113044fe4583..fc18af370fb00 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx @@ -29,7 +29,6 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { AlertExecutionStatusValues } from '../../../../../../alerts/common'; import { useAppDependencies } from '../../../app_context'; import { hasAllPrivilege, hasExecuteActionsCapability } from '../../../lib/capabilities'; import { getAlertingSectionBreadcrumb, getAlertDetailsBreadcrumb } from '../../../lib/breadcrumb'; @@ -279,8 +278,7 @@ export const AlertDetails: React.FunctionComponent = ({
- {!dissmissAlertErrors && - alert.executionStatus.status === AlertExecutionStatusValues[2] ? ( + {!dissmissAlertErrors && alert.executionStatus.status === 'error' ? ( = ({ size="s" title={ = ({

@@ -314,7 +312,7 @@ export const AlertDetails: React.FunctionComponent = ({ setDissmissAlertErrors(true)}> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx index 21e4d75d301ef..88fde9ab0cfdc 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx @@ -16,13 +16,15 @@ import { import { AlertExecutionStatusValues } from '../../../../../../alerts/common'; interface AlertStatusFilterProps { + selectedStatuses: string[]; onChange?: (selectedAlertStatusesIds: string[]) => void; } export const AlertStatusFilter: React.FunctionComponent = ({ + selectedStatuses, onChange, }: AlertStatusFilterProps) => { - const [selectedValues, setSelectedValues] = useState([]); + const [selectedValues, setSelectedValues] = useState(selectedStatuses); const [isPopoverOpen, setIsPopoverOpen] = useState(false); useEffect(() => { @@ -32,6 +34,10 @@ export const AlertStatusFilter: React.FunctionComponent // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedValues]); + useEffect(() => { + setSelectedValues(selectedStatuses); + }, [selectedStatuses]); + return ( { />, setAlertStatusesFilter(ids)} />, ]; @@ -422,7 +423,7 @@ export const AlertsList: React.FunctionComponent = () => { - {!dissmissAlertErrors && alertsStatusesTotal[AlertExecutionStatusValues[2]] > 0 ? ( + {!dissmissAlertErrors && alertsStatusesTotal.error > 0 ? ( { id="xpack.triggersActionsUI.sections.alertsList.attentionBannerTitle" defaultMessage="There is {totalStausesError} {totalStausesError, plural, one {{singleTitle}} other {# {multipleTitle}}} with an error." values={{ - totalStausesError: alertsStatusesTotal[AlertExecutionStatusValues[2]], + totalStausesError: alertsStatusesTotal.error, singleTitle: 'alert', multipleTitle: 'alerts', }} @@ -445,7 +446,7 @@ export const AlertsList: React.FunctionComponent = () => { type="primary" size="s" color="danger" - onClick={() => setAlertStatusesFilter([AlertExecutionStatusValues[2]])} + onClick={() => setAlertStatusesFilter(['error'])} > { @@ -479,7 +483,7 @@ export const AlertsList: React.FunctionComponent = () => { id="xpack.triggersActionsUI.sections.alertsList.totalStausesActiveDescription" defaultMessage="Active: {totalStausesActive}" values={{ - totalStausesActive: alertsStatusesTotal[AlertExecutionStatusValues[1]], + totalStausesActive: alertsStatusesTotal.active, }} /> @@ -489,7 +493,7 @@ export const AlertsList: React.FunctionComponent = () => { @@ -498,7 +502,7 @@ export const AlertsList: React.FunctionComponent = () => { @@ -508,7 +512,7 @@ export const AlertsList: React.FunctionComponent = () => { id="xpack.triggersActionsUI.sections.alertsList.totalStausesPendingDescription" defaultMessage="Pending: {totalStausesPending}" values={{ - totalStausesPending: alertsStatusesTotal[AlertExecutionStatusValues[3]], + totalStausesPending: alertsStatusesTotal.pending, }} /> @@ -519,7 +523,7 @@ export const AlertsList: React.FunctionComponent = () => { id="xpack.triggersActionsUI.sections.alertsList.totalStausesUnknownDescription" defaultMessage="Unknown: {totalStausesUnknown}" values={{ - totalStausesUnknown: alertsStatusesTotal[AlertExecutionStatusValues[4]], + totalStausesUnknown: alertsStatusesTotal.unknown, }} /> From c8b85723e2622cf2a6a23902bce485f4674c1d18 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 2 Oct 2020 08:44:20 -0700 Subject: [PATCH 09/12] Changes due to comments --- .../public/application/lib/alert_api.ts | 12 +++--------- .../alerts_list/components/alert_status_filter.tsx | 9 ++++++--- .../sections/alerts_list/components/alerts_list.tsx | 2 +- x-pack/plugins/triggers_actions_ui/public/types.ts | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts index 74a63c4e5f2ca..6dfba82bdf5c9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts @@ -11,13 +11,7 @@ import { fold } from 'fp-ts/lib/Either'; import { pick } from 'lodash'; import { alertStateSchema, AlertingFrameworkHealth } from '../../../../alerts/common'; import { BASE_ALERT_API_PATH } from '../constants'; -import { - Alert, - AlertType, - AlertWithoutId, - AlertTaskState, - AlertInstanceSummary, -} from '../../types'; +import { Alert, AlertType, AlertUpdates, AlertTaskState, AlertInstanceSummary } from '../../types'; export async function loadAlertTypes({ http }: { http: HttpSetup }): Promise { return await http.get(`${BASE_ALERT_API_PATH}/list_alert_types`); @@ -142,7 +136,7 @@ export async function createAlert({ }: { http: HttpSetup; alert: Omit< - AlertWithoutId, + AlertUpdates, 'createdBy' | 'updatedBy' | 'muteAll' | 'mutedInstanceIds' | 'executionStatus' >; }): Promise { @@ -157,7 +151,7 @@ export async function updateAlert({ id, }: { http: HttpSetup; - alert: Pick; + alert: Pick; id: string; }): Promise { return await http.put(`${BASE_ALERT_API_PATH}/alert/${id}`, { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx index 88fde9ab0cfdc..72ca1fc8b090a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx @@ -13,7 +13,10 @@ import { EuiFilterSelectItem, EuiHealth, } from '@elastic/eui'; -import { AlertExecutionStatusValues } from '../../../../../../alerts/common'; +import { + AlertExecutionStatuses, + AlertExecutionStatusValues, +} from '../../../../../../alerts/common'; interface AlertStatusFilterProps { selectedStatuses: string[]; @@ -59,7 +62,7 @@ export const AlertStatusFilter: React.FunctionComponent } >
- {[...AlertExecutionStatusValues].sort().map((item: string) => { + {[...AlertExecutionStatusValues].sort().map((item: AlertExecutionStatuses) => { const healthColor = getHealthColor(item); return ( ); }; -export function getHealthColor(status: string) { +export function getHealthColor(status: AlertExecutionStatuses) { switch (status) { case 'active': return 'primary'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index 776e060c51bca..aefd0f9cbdb3d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -432,7 +432,7 @@ export const AlertsList: React.FunctionComponent = () => { title={ ; -export type AlertWithoutId = Omit; +export type AlertUpdates = Omit; export interface AlertTableItem extends Alert { alertType: AlertType['name']; From 086534b42efbc0deceb84c69317ec259e7a240d9 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 2 Oct 2020 10:48:33 -0700 Subject: [PATCH 10/12] Fixed due to comments --- .../components/alert_details.tsx | 10 +++- .../components/alerts_list.test.tsx | 57 +++++++++++++++++-- .../alerts_list/components/alerts_list.tsx | 11 +++- 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx index fc18af370fb00..8062e5e25478f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx @@ -113,6 +113,14 @@ export const AlertDetails: React.FunctionComponent = ({ history.push(routeToAlertDetails.replace(`:alertId`, alert.id)); }; + const getAlertStatusErrorReason = () => { + if (alert.executionStatus.error) { + return alert.executionStatus.error.reason; + } else { + return 'unknown'; + } + }; + return ( @@ -290,7 +298,7 @@ export const AlertDetails: React.FunctionComponent = ({ id="xpack.triggersActionsUI.sections.alertDetails.attentionBannerTitle" defaultMessage="This alert has an error caused by the {errorReason} reason." values={{ - errorReason: alert.executionStatus.error?.reason, + errorReason: getAlertStatusErrorReason(), }} /> } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx index 9e046fb680fe0..86b9afd9565f8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -150,7 +150,7 @@ describe('alerts_list component with items', () => { loadAlerts.mockResolvedValue({ page: 1, perPage: 10000, - total: 2, + total: 4, data: [ { id: '1', @@ -176,7 +176,51 @@ describe('alerts_list component with items', () => { }, { id: '2', - name: 'test alert 2', + name: 'test alert ok', + tags: ['tag1'], + enabled: true, + alertTypeId: 'test_alert_type', + schedule: { interval: '5d' }, + actions: [], + params: { name: 'test alert type name' }, + scheduledTaskId: null, + createdBy: null, + updatedBy: null, + apiKeyOwner: null, + throttle: '1m', + muteAll: false, + mutedInstanceIds: [], + executionStatus: { + status: 'ok', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + error: null, + }, + }, + { + id: '3', + name: 'test alert pending', + tags: ['tag1'], + enabled: true, + alertTypeId: 'test_alert_type', + schedule: { interval: '5d' }, + actions: [], + params: { name: 'test alert type name' }, + scheduledTaskId: null, + createdBy: null, + updatedBy: null, + apiKeyOwner: null, + throttle: '1m', + muteAll: false, + mutedInstanceIds: [], + executionStatus: { + status: 'pending', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + error: null, + }, + }, + { + id: '4', + name: 'test alert error', tags: ['tag1'], enabled: true, alertTypeId: 'test_alert_type', @@ -258,8 +302,13 @@ describe('alerts_list component with items', () => { it('renders table of alerts', async () => { await setup(); expect(wrapper.find('EuiBasicTable')).toHaveLength(1); - expect(wrapper.find('EuiTableRow')).toHaveLength(2); - expect(wrapper.find('[data-test-subj="alertsTableCell-status"]')).toHaveLength(4); + expect(wrapper.find('EuiTableRow')).toHaveLength(4); + expect(wrapper.find('[data-test-subj="alertsTableCell-status"]').length).toBeGreaterThan(0); + expect(wrapper.find('[data-test-subj="alertStatus-active"]').length).toBeGreaterThan(0); + expect(wrapper.find('[data-test-subj="alertStatus-error"]').length).toBeGreaterThan(0); + expect(wrapper.find('[data-test-subj="alertStatus-ok"]').length).toBeGreaterThan(0); + expect(wrapper.find('[data-test-subj="alertStatus-pending"]').length).toBeGreaterThan(0); + expect(wrapper.find('[data-test-subj="alertStatus-unknown"]').length).toBe(0); }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index aefd0f9cbdb3d..263360ee893e1 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -238,7 +238,11 @@ export const AlertsList: React.FunctionComponent = () => { 'data-test-subj': 'alertsTableCell-status', render: (executionStatus: AlertExecutionStatus) => { const healthColor = getHealthColor(executionStatus.status); - return {executionStatus.status}; + return ( + + {executionStatus.status} + + ); }, }, { @@ -482,6 +486,7 @@ export const AlertsList: React.FunctionComponent = () => { { @@ -501,6 +507,7 @@ export const AlertsList: React.FunctionComponent = () => { @@ -510,6 +517,7 @@ export const AlertsList: React.FunctionComponent = () => { { Date: Fri, 2 Oct 2020 13:11:32 -0700 Subject: [PATCH 11/12] Fixed text on banners --- .../components/alert_details.tsx | 34 ++++++------------- .../alerts_list/components/alerts_list.tsx | 2 +- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx index 8062e5e25478f..e983c9260d667 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx @@ -25,7 +25,6 @@ import { EuiBetaBadge, EuiButtonEmpty, EuiButton, - EuiTextColor, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; @@ -113,11 +112,11 @@ export const AlertDetails: React.FunctionComponent = ({ history.push(routeToAlertDetails.replace(`:alertId`, alert.id)); }; - const getAlertStatusErrorReason = () => { - if (alert.executionStatus.error) { - return alert.executionStatus.error.reason; + const getAlertStatusErrorReasonText = () => { + if (alert.executionStatus.error && alert.executionStatus.error.reason !== 'unknown') { + return `An error occurred when ${alert.executionStatus.error.reason} the alert.`; } else { - return 'unknown'; + return 'An error occurred for unknown reasons.'; } }; @@ -293,27 +292,14 @@ export const AlertDetails: React.FunctionComponent = ({ color="danger" data-test-subj="alertErrorBanner" size="s" - title={ - - } + title={i18n.translate( + 'xpack.triggersActionsUI.sections.alertDetails.attentionBannerTitle', + { + defaultMessage: `${getAlertStatusErrorReasonText()}`, + } + )} iconType="alert" > - -

- - - -

-
{alert.executionStatus.error?.message} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index 263360ee893e1..b9f7a31fc1b32 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -436,7 +436,7 @@ export const AlertsList: React.FunctionComponent = () => { title={ Date: Fri, 2 Oct 2020 14:15:18 -0700 Subject: [PATCH 12/12] Added i18n translations --- .../components/alert_details.tsx | 14 ++- .../components/alert_status_filter.tsx | 3 +- .../alerts_list/components/alerts_list.tsx | 5 +- .../sections/alerts_list/translations.ts | 85 +++++++++++++++++++ 4 files changed, 95 insertions(+), 12 deletions(-) create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/translations.ts diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx index e983c9260d667..42a25b399ddd3 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx @@ -43,6 +43,7 @@ import { PLUGIN } from '../../../constants/plugin'; import { AlertEdit } from '../../alert_form'; import { AlertsContextProvider } from '../../../context/alerts_context'; import { routeToAlertDetails } from '../../../constants'; +import { alertsErrorReasonTranslationsMapping } from '../../alerts_list/translations'; type AlertDetailsProps = { alert: Alert; @@ -113,10 +114,10 @@ export const AlertDetails: React.FunctionComponent = ({ }; const getAlertStatusErrorReasonText = () => { - if (alert.executionStatus.error && alert.executionStatus.error.reason !== 'unknown') { - return `An error occurred when ${alert.executionStatus.error.reason} the alert.`; + if (alert.executionStatus.error && alert.executionStatus.error.reason) { + return alertsErrorReasonTranslationsMapping[alert.executionStatus.error.reason]; } else { - return 'An error occurred for unknown reasons.'; + return alertsErrorReasonTranslationsMapping.unknown; } }; @@ -292,12 +293,7 @@ export const AlertDetails: React.FunctionComponent = ({ color="danger" data-test-subj="alertErrorBanner" size="s" - title={i18n.translate( - 'xpack.triggersActionsUI.sections.alertDetails.attentionBannerTitle', - { - defaultMessage: `${getAlertStatusErrorReasonText()}`, - } - )} + title={getAlertStatusErrorReasonText()} iconType="alert" > diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx index 72ca1fc8b090a..87e7a82cd8f23 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alert_status_filter.tsx @@ -17,6 +17,7 @@ import { AlertExecutionStatuses, AlertExecutionStatusValues, } from '../../../../../../alerts/common'; +import { alertsStatusesTranslationsMapping } from '../translations'; interface AlertStatusFilterProps { selectedStatuses: string[]; @@ -78,7 +79,7 @@ export const AlertStatusFilter: React.FunctionComponent }} checked={selectedValues.includes(item) ? 'on' : undefined} > - {item} + {alertsStatusesTranslationsMapping[item]}
); })} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index b9f7a31fc1b32..95082bc6ca99f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -51,6 +51,7 @@ import { ALERTS_FEATURE_ID, } from '../../../../../../alerts/common'; import { hasAllPrivilege } from '../../../lib/capabilities'; +import { alertsStatusesTranslationsMapping } from '../translations'; const ENTER_KEY = 13; @@ -240,7 +241,7 @@ export const AlertsList: React.FunctionComponent = () => { const healthColor = getHealthColor(executionStatus.status); return ( - {executionStatus.status} + {alertsStatusesTranslationsMapping[executionStatus.status]} ); }, @@ -498,7 +499,7 @@ export const AlertsList: React.FunctionComponent = () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/translations.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/translations.ts new file mode 100644 index 0000000000000..dbcf2d6854af5 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/translations.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const ALERT_STATUS_OK = i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.alertStatusOk', + { + defaultMessage: 'Ok', + } +); + +export const ALERT_STATUS_ACTIVE = i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.alertStatusActive', + { + defaultMessage: 'Active', + } +); + +export const ALERT_STATUS_ERROR = i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.alertStatusError', + { + defaultMessage: 'Error', + } +); + +export const ALERT_STATUS_PENDING = i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.alertStatusPending', + { + defaultMessage: 'Pending', + } +); + +export const ALERT_STATUS_UNKNOWN = i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.alertStatusUnknown', + { + defaultMessage: 'Unknown', + } +); + +export const alertsStatusesTranslationsMapping = { + ok: ALERT_STATUS_OK, + active: ALERT_STATUS_ACTIVE, + error: ALERT_STATUS_ERROR, + pending: ALERT_STATUS_PENDING, + unknown: ALERT_STATUS_UNKNOWN, +}; + +export const ALERT_ERROR_UNKNOWN_REASON = i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.alertErrorReasonUnknown', + { + defaultMessage: 'An error occurred for unknown reasons.', + } +); + +export const ALERT_ERROR_READING_REASON = i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.alertErrorReasonReading', + { + defaultMessage: 'An error occurred when reading the alert.', + } +); + +export const ALERT_ERROR_DECRYPTING_REASON = i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.alertErrorReasonDecrypting', + { + defaultMessage: 'An error occurred when decrypting the alert.', + } +); + +export const ALERT_ERROR_EXECUTION_REASON = i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.alertErrorReasonRunning', + { + defaultMessage: 'An error occurred when running the alert.', + } +); + +export const alertsErrorReasonTranslationsMapping = { + read: ALERT_ERROR_READING_REASON, + decrypt: ALERT_ERROR_DECRYPTING_REASON, + execute: ALERT_ERROR_EXECUTION_REASON, + unknown: ALERT_ERROR_UNKNOWN_REASON, +};