Skip to content

Commit

Permalink
Fix Watcher stuck firing state (#138563)
Browse files Browse the repository at this point in the history
* Update WATCH_STATES by replacing DISABLED with INACTIVE and OK/FIRING with ACTIVE. Update ACTION_STATES by replacing FIRING with OK.
- Refactor isAckable logic to directly translate value provided by ES.
- Replace WatchStatus component with ActionStateBadge and WatchStateBadge components.

* Change WatchListPage 'Last fired' column to 'Condition last met' and 'Last triggered' column to 'Last checked'.
- Add tooltips to both.
- Add tooltips to State and Comment headers.

* Rename Watch Status Model's lastFired -> lastExecution for consistency. Remove unused properties from client WatchStatus model.

* Add Condition Met column and tooltips to State and Comment headers on Execution History Panel.

* Add tooltip to State header in Execution History flyout. Add Last executed header to Action Statuses Panel and tooltips. Update tests.

* Use EUI types instead of hand-rolling them.

* Remove unused ACTION_STATES.FIRING and references to WATCH_STATES.FIRING.

* Use dots to denote states, similar to Index Management.

* Refactor deriveComment to use early exits.
  • Loading branch information
CJ Cenizal authored Aug 16, 2022
1 parent 1adabbc commit f77afae
Show file tree
Hide file tree
Showing 31 changed files with 492 additions and 386 deletions.
4 changes: 0 additions & 4 deletions x-pack/plugins/translations/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -31249,7 +31249,6 @@
"xpack.watcher.constants.actionStates.acknowledgedStateText": "Reconnu",
"xpack.watcher.constants.actionStates.configErrorStateText": "Erreur de config",
"xpack.watcher.constants.actionStates.errorStateText": "Erreur",
"xpack.watcher.constants.actionStates.firingStateText": "Déclenchement",
"xpack.watcher.constants.actionStates.okStateText": "OK",
"xpack.watcher.constants.actionStates.throttledStateText": "Contraint",
"xpack.watcher.constants.actionStates.unknownStateText": "Inconnu",
Expand All @@ -31259,10 +31258,7 @@
"xpack.watcher.constants.watchStateComments.partiallyThrottledStateCommentText": "Partiellement contraint",
"xpack.watcher.constants.watchStateComments.throttledStateCommentText": "Contraint",
"xpack.watcher.constants.watchStates.configErrorStateText": "Erreur de config",
"xpack.watcher.constants.watchStates.disabledStateText": "Désactivé",
"xpack.watcher.constants.watchStates.errorStateText": "Erreur",
"xpack.watcher.constants.watchStates.firingStateText": "Déclenchement",
"xpack.watcher.constants.watchStates.okStateText": "OK",
"xpack.watcher.data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "Intervalle de calendrier non valide : {interval}, la valeur doit être 1",
"xpack.watcher.data.parseEsInterval.invalidEsIntervalFormatErrorMessage": "Format d'intervalle non valide : {interval}",
"xpack.watcher.deleteSelectedWatchesConfirmModal.cancelButtonLabel": "Annuler",
Expand Down
4 changes: 0 additions & 4 deletions x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -31325,7 +31325,6 @@
"xpack.watcher.constants.actionStates.acknowledgedStateText": "承認済み",
"xpack.watcher.constants.actionStates.configErrorStateText": "構成エラー",
"xpack.watcher.constants.actionStates.errorStateText": "エラー",
"xpack.watcher.constants.actionStates.firingStateText": "実行中",
"xpack.watcher.constants.actionStates.okStateText": "OK",
"xpack.watcher.constants.actionStates.throttledStateText": "スロットル",
"xpack.watcher.constants.actionStates.unknownStateText": "不明",
Expand All @@ -31335,10 +31334,7 @@
"xpack.watcher.constants.watchStateComments.partiallyThrottledStateCommentText": "部分スロットル",
"xpack.watcher.constants.watchStateComments.throttledStateCommentText": "スロットル",
"xpack.watcher.constants.watchStates.configErrorStateText": "構成エラー",
"xpack.watcher.constants.watchStates.disabledStateText": "無効",
"xpack.watcher.constants.watchStates.errorStateText": "エラー",
"xpack.watcher.constants.watchStates.firingStateText": "実行中",
"xpack.watcher.constants.watchStates.okStateText": "OK",
"xpack.watcher.data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "無効なカレンダー間隔:{interval}、1よりも大きな値が必要です",
"xpack.watcher.data.parseEsInterval.invalidEsIntervalFormatErrorMessage": "無効な間隔形式:{interval}",
"xpack.watcher.deleteSelectedWatchesConfirmModal.cancelButtonLabel": "キャンセル",
Expand Down
4 changes: 0 additions & 4 deletions x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -31354,7 +31354,6 @@
"xpack.watcher.constants.actionStates.acknowledgedStateText": "已确认",
"xpack.watcher.constants.actionStates.configErrorStateText": "配置错误",
"xpack.watcher.constants.actionStates.errorStateText": "错误",
"xpack.watcher.constants.actionStates.firingStateText": "正在发送",
"xpack.watcher.constants.actionStates.okStateText": "确定",
"xpack.watcher.constants.actionStates.throttledStateText": "已限制",
"xpack.watcher.constants.actionStates.unknownStateText": "未知",
Expand All @@ -31364,10 +31363,7 @@
"xpack.watcher.constants.watchStateComments.partiallyThrottledStateCommentText": "已部分限制",
"xpack.watcher.constants.watchStateComments.throttledStateCommentText": "已限制",
"xpack.watcher.constants.watchStates.configErrorStateText": "配置错误",
"xpack.watcher.constants.watchStates.disabledStateText": "已禁用",
"xpack.watcher.constants.watchStates.errorStateText": "错误",
"xpack.watcher.constants.watchStates.firingStateText": "正在发送",
"xpack.watcher.constants.watchStates.okStateText": "确定",
"xpack.watcher.data.parseEsInterval.invalidEsCalendarIntervalErrorMessage": "无效的日历时间间隔:{interval},值必须为 1",
"xpack.watcher.data.parseEsInterval.invalidEsIntervalFormatErrorMessage": "时间间隔格式无效:{interval}",
"xpack.watcher.deleteSelectedWatchesConfirmModal.cancelButtonLabel": "取消",
Expand Down
49 changes: 49 additions & 0 deletions x-pack/plugins/watcher/__fixtures__/get_watch_history.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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 moment, { Moment } from 'moment';
import { ACTION_STATES, WATCH_STATES } from '../common/constants';
import { ClientWatchStatusModel, ClientActionStatusModel } from '../common/types';

interface WatchHistory {
id: string;
watchId: string;
startTime: Moment;
watchStatus: {
state: ClientWatchStatusModel['state'];
comment?: string;
lastExecution: Moment;
actionStatuses?: Array<{
id: string;
state: ClientActionStatusModel['state'];
}>;
};
details?: object;
}

export const getWatchHistory = ({
id,
startTime,
}: {
id: string;
startTime: string;
}): WatchHistory => ({
id,
startTime: moment(startTime),
watchId: id,
watchStatus: {
state: WATCH_STATES.OK,
lastExecution: moment('2019-06-03T19:44:11.088Z'),
actionStatuses: [
{
id: 'a',
state: ACTION_STATES.OK,
},
],
},
details: {},
});
2 changes: 1 addition & 1 deletion x-pack/plugins/watcher/__fixtures__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
*/

export * from './watch';
export * from './watch_history';
export * from './get_watch_history';
export * from './execute_details';
19 changes: 9 additions & 10 deletions x-pack/plugins/watcher/__fixtures__/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
* 2.0.
*/

import { Moment } from 'moment';
import { getRandomString } from '@kbn/test-jest-helpers';
import { ClientWatchStatusModel } from '../common/types';
import { WATCH_STATES, WATCH_STATE_COMMENTS } from '../common/constants';

interface Watch {
id: string;
Expand All @@ -22,14 +23,7 @@ interface Watch {
timeWindowUnit?: string;
threshold?: number[];
isSystemWatch: boolean;
watchStatus: {
state: 'OK' | 'Firing' | 'Error' | 'Config error' | 'Disabled';
comment?: string;
lastMetCondition?: Moment;
lastChecked?: Moment;
isActive: boolean;
actionStatuses?: any[];
};
watchStatus: ClientWatchStatusModel;
}

export const getWatch = ({
Expand All @@ -47,8 +41,13 @@ export const getWatch = ({
threshold,
isSystemWatch = false,
watchStatus = {
state: 'OK',
id: 'a',
state: WATCH_STATES.OK,
isActive: true,
lastChecked: null,
lastMetCondition: null,
comment: WATCH_STATE_COMMENTS.OK,
actionStatuses: [],
},
}: Partial<Watch> = {}): Watch => ({
id,
Expand Down
39 changes: 0 additions & 39 deletions x-pack/plugins/watcher/__fixtures__/watch_history.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,17 @@ describe('<WatchListPage />', () => {
// Expect "watch1" is only visible in the table
expect(tableCellsValues.length).toEqual(1);
const row = tableCellsValues[0];
const { name, id, watchStatus } = watch1;
const { name, id } = watch1;

const expectedRow = [
'', // checkbox
id,
name,
watchStatus.state,
'', // comment
'', // state
'', // lastMetCondition
'', // lastChecked
'', // actions
'', // comment
'', // row actions
];

expect(row).toEqual(expectedRow);
Expand Down Expand Up @@ -128,7 +128,7 @@ describe('<WatchListPage />', () => {
const { table } = testBed;
const { tableCellsValues } = table.getMetaData('watchesTable');

const getExpectedValue = (value: any) => (typeof value === 'undefined' ? '' : value);
const getExpectedValue = (value: any) => value ?? '';

tableCellsValues.forEach((row, i) => {
const watch = watches[i];
Expand All @@ -138,11 +138,11 @@ describe('<WatchListPage />', () => {
'',
id, // required value
getExpectedValue(name),
watchStatus.state, // required value
getExpectedValue(watchStatus.comment),
'', // state
getExpectedValue(watchStatus.lastMetCondition),
getExpectedValue(watchStatus.lastChecked),
'',
getExpectedValue(watchStatus.comment),
'', // row actions
]);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { API_BASE_PATH } from '../../common/constants';

const { setup } = pageHelpers.watchStatusPage;

const watchHistory1 = getWatchHistory({ startTime: '2019-06-04T01:11:11.294' });
const watchHistory2 = getWatchHistory({ startTime: '2019-06-04T01:10:10.987Z' });
const watchHistory1 = getWatchHistory({ id: 'a', startTime: '2019-06-04T01:11:11.294' });
const watchHistory2 = getWatchHistory({ id: 'b', startTime: '2019-06-04T01:10:10.987Z' });

const watchHistoryItems = { watchHistoryItems: [watchHistory1, watchHistory2] };

Expand All @@ -26,13 +26,15 @@ const ACTION_ID = 'my_logging_action_1';
const watch = {
...WATCH.watch,
watchStatus: {
state: WATCH_STATES.FIRING,
state: WATCH_STATES.ACTIVE,
isActive: true,
lastExecution: moment('2019-06-03T19:44:11.088Z'),
actionStatuses: [
{
id: ACTION_ID,
state: ACTION_STATES.FIRING,
state: ACTION_STATES.OK,
isAckable: true,
lastExecution: moment('2019-06-03T19:44:11.088Z'),
},
],
},
Expand Down Expand Up @@ -100,7 +102,8 @@ describe('<WatchStatusPage />', () => {
expect(row).toEqual([
getExpectedValue(moment(startTime).format()),
getExpectedValue(watchStatus.state),
getExpectedValue(watchStatus.comment),
'',
'',
]);
});
});
Expand All @@ -112,11 +115,11 @@ describe('<WatchStatusPage />', () => {
...watchHistory1,
watchId: watch.id,
watchStatus: {
state: WATCH_STATES.FIRING,
state: WATCH_STATES.ACTIVE,
actionStatuses: [
{
id: 'my_logging_action_1',
state: ACTION_STATES.FIRING,
state: ACTION_STATES.OK,
isAckable: true,
},
],
Expand Down Expand Up @@ -204,7 +207,7 @@ describe('<WatchStatusPage />', () => {

httpRequestsMockHelpers.setActivateWatchResponse(WATCH_ID, {
watchStatus: {
state: WATCH_STATES.FIRING,
state: WATCH_STATES.ACTIVE,
isActive: true,
},
});
Expand All @@ -231,29 +234,36 @@ describe('<WatchStatusPage />', () => {

tableCellsValues.forEach((row, i) => {
const action = watch.watchStatus.actionStatuses[i];
const { id, state, isAckable } = action;
const { id, state, lastExecution, isAckable } = action;

expect(row).toEqual([id, state, isAckable ? 'Acknowledge' : '']);
expect(row).toEqual([
id, // Name
state, // State
lastExecution.format(), // Last executed
isAckable ? 'Acknowledge' : '', // Row actions
]);
});
});

test('should allow an action to be acknowledged', async () => {
const { actions, table } = testBed;

httpRequestsMockHelpers.setAcknowledgeWatchResponse(WATCH_ID, ACTION_ID, {
const watchHistoryItem = {
watchStatus: {
state: WATCH_STATES.FIRING,
state: WATCH_STATES.ACTIVE,
isActive: true,
comment: 'Acked',
actionStatuses: [
{
id: ACTION_ID,
state: ACTION_STATES.ACKNOWLEDGED,
isAckable: false,
lastExecution: moment('2019-06-03T19:44:11.088Z'),
},
],
},
});
};

httpRequestsMockHelpers.setAcknowledgeWatchResponse(WATCH_ID, ACTION_ID, watchHistoryItem);

await actions.clickAcknowledgeButton(0);

Expand All @@ -268,7 +278,12 @@ describe('<WatchStatusPage />', () => {
const { tableCellsValues } = table.getMetaData('watchActionStatusTable');

tableCellsValues.forEach((row) => {
expect(row).toEqual([ACTION_ID, ACTION_STATES.ACKNOWLEDGED, '']);
expect(row).toEqual([
ACTION_ID, // Name
ACTION_STATES.ACKNOWLEDGED, // State
watchHistoryItem.watchStatus.actionStatuses[0].lastExecution.format(), // Last executed
'', // Row actions
]);
});
});
});
Expand Down
7 changes: 1 addition & 6 deletions x-pack/plugins/watcher/common/constants/action_states.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,14 @@ export const ACTION_STATES: { [key: string]: string } = {

// Action has been acknowledged by user
ACKNOWLEDGED: i18n.translate('xpack.watcher.constants.actionStates.acknowledgedStateText', {
defaultMessage: 'Acked',
defaultMessage: 'Acknowledged',
}),

// Action has been throttled (time-based) by the system
THROTTLED: i18n.translate('xpack.watcher.constants.actionStates.throttledStateText', {
defaultMessage: 'Throttled',
}),

// Action has been completed
FIRING: i18n.translate('xpack.watcher.constants.actionStates.firingStateText', {
defaultMessage: 'Firing',
}),

// Action has failed
ERROR: i18n.translate('xpack.watcher.constants.actionStates.errorStateText', {
defaultMessage: 'Error',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ export const WATCH_STATE_COMMENTS: { [key: string]: string } = {
PARTIALLY_ACKNOWLEDGED: i18n.translate(
'xpack.watcher.constants.watchStateComments.partiallyAcknowledgedStateCommentText',
{
defaultMessage: 'Partially acked',
defaultMessage: 'Partially acknowledged',
}
),

ACKNOWLEDGED: i18n.translate(
'xpack.watcher.constants.watchStateComments.acknowledgedStateCommentText',
{
defaultMessage: 'Acked',
defaultMessage: 'Acknowledged',
}
),

Expand Down
Loading

0 comments on commit f77afae

Please sign in to comment.