Skip to content

Commit

Permalink
Added ability to assign alert actions to resolved action group in UI
Browse files Browse the repository at this point in the history
  • Loading branch information
YulNaumenko committed Nov 10, 2020
1 parent d66ca49 commit 6e44558
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 22 deletions.
18 changes: 18 additions & 0 deletions x-pack/plugins/alerts/common/builtin_action_groups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* 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';
import { ActionGroup } from './alert_type';

export const ResolvedActionGroup: ActionGroup = {
id: 'resolved',
name: i18n.translate('xpack.alerts.builtinActionGroups.resolved', {
defaultMessage: 'Resolved',
}),
};

export function getBuiltinActionGroups(): ActionGroup[] {
return [ResolvedActionGroup];
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ActionParamsProps } from '../../../../types';
import { EmailActionParams } from '../types';
import { TextFieldWithMessageVariables } from '../../text_field_with_message_variables';
import { TextAreaWithMessageVariables } from '../../text_area_with_message_variables';
import { resolvedActionGroupMessage } from '../../../constants';

export const EmailParamsFields = ({
actionParams,
Expand All @@ -28,11 +29,18 @@ export const EmailParamsFields = ({
const [addBCC, setAddBCC] = useState<boolean>(false);

useEffect(() => {
if (!message && defaultMessage && defaultMessage.length > 0) {
if (defaultMessage === resolvedActionGroupMessage) {
editAction('message', defaultMessage, index);
} else if (
(!message || message === resolvedActionGroupMessage) &&
defaultMessage &&
defaultMessage.length > 0
) {
editAction('message', defaultMessage, index);
}

// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [defaultMessage]);

return (
<Fragment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { EuiSelect, EuiFormRow } from '@elastic/eui';
import { ActionParamsProps } from '../../../../types';
import { ServerLogActionParams } from '.././types';
import { TextAreaWithMessageVariables } from '../../text_area_with_message_variables';
import { resolvedActionGroupMessage } from '../../../constants';

export const ServerLogParamsFields: React.FunctionComponent<ActionParamsProps<
ServerLogActionParams
Expand All @@ -25,11 +26,22 @@ export const ServerLogParamsFields: React.FunctionComponent<ActionParamsProps<

useEffect(() => {
editAction('level', 'info', index);
if (!message && defaultMessage && defaultMessage.length > 0) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
if (defaultMessage === resolvedActionGroupMessage) {
editAction('message', defaultMessage, index);
} else if (
(!message || message === resolvedActionGroupMessage) &&
defaultMessage &&
defaultMessage.length > 0
) {
editAction('message', defaultMessage, index);
}

// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [defaultMessage]);

return (
<Fragment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { i18n } from '@kbn/i18n';
import { ActionParamsProps } from '../../../../types';
import { SlackActionParams } from '../types';
import { TextAreaWithMessageVariables } from '../../text_area_with_message_variables';
import { resolvedActionGroupMessage } from '../../../constants';

const SlackParamsFields: React.FunctionComponent<ActionParamsProps<SlackActionParams>> = ({
actionParams,
Expand All @@ -19,11 +20,18 @@ const SlackParamsFields: React.FunctionComponent<ActionParamsProps<SlackActionPa
}) => {
const { message } = actionParams;
useEffect(() => {
if (!message && defaultMessage && defaultMessage.length > 0) {
if (defaultMessage === resolvedActionGroupMessage) {
editAction('message', defaultMessage, index);
} else if (
(!message || message === resolvedActionGroupMessage) &&
defaultMessage &&
defaultMessage.length > 0
) {
editAction('message', defaultMessage, index);
}

// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [defaultMessage]);

return (
<TextAreaWithMessageVariables
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { i18n } from '@kbn/i18n';

export { BASE_ALERT_API_PATH } from '../../../../alerts/common';
export { BASE_ACTION_API_PATH } from '../../../../actions/common';

Expand All @@ -14,6 +16,13 @@ export const routeToConnectors = `/connectors`;
export const routeToAlerts = `/alerts`;
export const routeToAlertDetails = `/alert/:alertId`;

export const resolvedActionGroupMessage = i18n.translate(
'xpack.triggersActionsUI.sections.actionForm.ResolvedMessage',
{
defaultMessage: 'Resolved',
}
);

export { TIME_UNITS } from './time_units';
export enum SORT_ORDERS {
ASCENDING = 'asc',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
*/

import { i18n } from '@kbn/i18n';
import { AlertType, ActionVariable } from '../../types';
import { ActionVariable, ActionVariables } from '../../types';

// return a "flattened" list of action variables for an alertType
export function actionVariablesFromAlertType(alertType: AlertType): ActionVariable[] {
export function actionVariablesFromAlertType(actionVariables: ActionVariables): ActionVariable[] {
const alwaysProvidedVars = getAlwaysProvidedActionVariables();
const contextVars = prefixKeys(alertType.actionVariables.context, 'context.');
const paramsVars = prefixKeys(alertType.actionVariables.params, 'params.');
const stateVars = prefixKeys(alertType.actionVariables.state, 'state.');
const contextVars = actionVariables.context
? prefixKeys(actionVariables.context, 'context.')
: [];
const paramsVars = prefixKeys(actionVariables.params, 'params.');
const stateVars = prefixKeys(actionVariables.state, 'state.');

return alwaysProvidedVars.concat(contextVars, paramsVars, stateVars);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
ActionTypeIndex,
ActionConnector,
ActionType,
ActionVariable,
ActionVariables,
} from '../../../types';
import { SectionLoading } from '../../components/section_loading';
import { ConnectorAddModal } from './connector_add_modal';
Expand All @@ -51,7 +51,7 @@ export interface ActionAccordionFormProps {
toastNotifications: ToastsSetup;
docLinks: DocLinksStart;
actionTypes?: ActionType[];
messageVariables?: ActionVariable[];
messageVariables?: ActionVariables;
defaultActionMessage?: string;
setHasActionsDisabled?: (value: boolean) => void;
setHasActionsWithBrokenConnector?: (value: boolean) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { Fragment, Suspense, useState } from 'react';
import React, { Fragment, Suspense, useEffect, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import {
Expand All @@ -25,10 +25,20 @@ import {
EuiLoadingSpinner,
EuiBadge,
} from '@elastic/eui';
import { IErrorObject, AlertAction, ActionTypeIndex, ActionConnector } from '../../../types';
import { ResolvedActionGroup } from '../../../../../alerts/common';
import {
IErrorObject,
AlertAction,
ActionTypeIndex,
ActionConnector,
ActionVariables,
ActionVariable,
} from '../../../types';
import { checkActionFormActionTypeEnabled } from '../../lib/check_action_type_enabled';
import { hasSaveActionsCapability } from '../../lib/capabilities';
import { ActionAccordionFormProps } from './action_form';
import { actionVariablesFromAlertType } from '../../lib/action_variables';
import { resolvedActionGroupMessage } from '../../constants';

export type ActionTypeFormProps = {
actionItem: AlertAction;
Expand Down Expand Up @@ -88,6 +98,21 @@ export const ActionTypeForm = ({
setActionGroupIdByIndex,
}: ActionTypeFormProps) => {
const [isOpen, setIsOpen] = useState(true);
const [availableActionVariables, setAvailableActionVariables] = useState<ActionVariable[]>([]);
const [availableDefaultActionMessage, setAvailableDefaultActionMessage] = useState<
string | undefined
>(undefined);

useEffect(() => {
setAvailableActionVariables(getAvailableActionVariables(messageVariables, actionItem.group));
const res =
actionItem.group === ResolvedActionGroup.id
? resolvedActionGroupMessage
: defaultActionMessage;
setAvailableDefaultActionMessage(res);
// setActionParamsProperty('message', res, index);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [actionItem.group]);

const canSave = hasSaveActionsCapability(capabilities);
const getSelectedOptions = (actionItemId: string) => {
Expand Down Expand Up @@ -244,8 +269,8 @@ export const ActionTypeForm = ({
index={index}
errors={actionParamsErrors.errors}
editAction={setActionParamsProperty}
messageVariables={messageVariables}
defaultMessage={defaultActionMessage ?? undefined}
messageVariables={availableActionVariables}
defaultMessage={availableDefaultActionMessage}
docLinks={docLinks}
http={http}
toastNotifications={toastNotifications}
Expand Down Expand Up @@ -337,3 +362,20 @@ export const ActionTypeForm = ({
</Fragment>
);
};

function getAvailableActionVariables(
actionVariables: ActionVariables | undefined,
actionGroup: string
) {
if (!actionVariables) {
return [];
}
const filteredActionVariables =
actionGroup === ResolvedActionGroup.id
? { params: actionVariables.params, state: actionVariables.state }
: actionVariables;

return actionVariablesFromAlertType(filteredActionVariables).sort((a, b) =>
a.name.toUpperCase().localeCompare(b.name.toUpperCase())
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import {
getDurationUnitValue,
} from '../../../../../alerts/common/parse_duration';
import { loadAlertTypes } from '../../lib/alert_api';
import { actionVariablesFromAlertType } from '../../lib/action_variables';
import { AlertReducerAction } from './alert_reducer';
import {
AlertTypeModel,
Expand Down Expand Up @@ -458,9 +457,7 @@ export const AlertForm = ({
actions={alert.actions}
setHasActionsDisabled={setHasActionsDisabled}
setHasActionsWithBrokenConnector={setHasActionsWithBrokenConnector}
messageVariables={actionVariablesFromAlertType(
alertTypesIndex.get(alert.alertTypeId)!
).sort((a, b) => a.name.toUpperCase().localeCompare(b.name.toUpperCase()))}
messageVariables={alertTypesIndex.get(alert.alertTypeId)!.actionVariables}
defaultActionGroupId={defaultActionGroupId}
actionGroups={alertTypesIndex.get(alert.alertTypeId)!.actionGroups}
setActionIdByIndex={(id: string, index: number) => setActionProperty('id', id, index)}
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/triggers_actions_ui/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export interface ActionVariable {
}

export interface ActionVariables {
context: ActionVariable[];
context?: ActionVariable[];
state: ActionVariable[];
params: ActionVariable[];
}
Expand Down

0 comments on commit 6e44558

Please sign in to comment.