From f90bf811f880b0dd39e6395ebf628fa49afc17b6 Mon Sep 17 00:00:00 2001 From: Alexi Doak <109488926+doakalexi@users.noreply.github.com> Date: Thu, 2 Feb 2023 15:59:46 -0500 Subject: [PATCH] [ResponseOps][Alert Summaries] Add default summary message (#148749) Resolves https://github.com/elastic/kibana/issues/148537 ## Summary Added the capability for rule types to provide a default message for summary actions. This default message gets pre-populated within the rule action form whenever a user adds an action to a rule. Also added a default framework summary message. ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### To verify - Create a rule and add an action and select `notify on custom action intervals` - Verify that the default message is populated ``` The system has detected {{alerts.new.count}} new, {{alerts.ongoing.count}} ongoing, and {{alerts.recovered.count}} alerts. ``` --- packages/kbn-optimizer/limits.yml | 2 +- .../public/application/constants/index.ts | 8 + .../application/lib/action_variables.test.ts | 78 ++++++ .../application/lib/action_variables.ts | 183 ++++++++++--- .../action_connector_form/action_form.tsx | 3 + .../action_type_form.test.tsx | 252 +++++++++++++----- .../action_type_form.tsx | 22 +- .../sections/rule_form/rule_form.tsx | 3 +- .../triggers_actions_ui/public/types.ts | 1 + 9 files changed, 439 insertions(+), 113 deletions(-) diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index b7439d781675b..79670e025b8dc 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -125,7 +125,7 @@ pageLoadAssetSize: threatIntelligence: 44299 timelines: 327300 transform: 41007 - triggersActionsUi: 120000 + triggersActionsUi: 135613 uiActions: 35121 uiActionsEnhanced: 38494 unifiedFieldList: 65500 diff --git a/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts b/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts index 2ce268be6c58e..e3540feb36c28 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts @@ -30,6 +30,14 @@ export const recoveredActionGroupMessage = i18n.translate( } ); +export const summaryMessage = i18n.translate( + 'xpack.triggersActionsUI.sections.actionForm.SummaryMessage', + { + defaultMessage: + 'The system has detected \\{\\{alerts.new.count\\}\\} new, \\{\\{alerts.ongoing.count\\}\\} ongoing, and \\{\\{alerts.recovered.count\\}\\} alerts.', + } +); + export { TIME_UNITS } from './time_units'; export enum SORT_ORDERS { ASCENDING = 'asc', diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.test.ts index 843996fe5f0ce..c7641d3437a2c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.test.ts @@ -143,6 +143,78 @@ const expectedParamsTransformResult = (withBraces: boolean = false) => [ }, ]; +const expectedSummaryTransformResult = [ + { + description: 'The configured server.publicBaseUrl value or empty string if not configured.', + name: 'kibanaBaseUrl', + }, + { + description: 'The date the rule scheduled the action.', + name: 'date', + }, + { + description: 'The params of the rule.', + name: 'rule.params', + }, + { + description: 'The ID of the rule.', + name: 'rule.id', + }, + { + description: 'The name of the rule.', + name: 'rule.name', + }, + { + description: 'The type of rule.', + name: 'rule.type', + }, + { + description: + 'The URL to the Stack Management rule page that generated the alert. This will be an empty string if the server.publicBaseUrl is not configured.', + name: 'rule.url', + }, + { + description: 'The tags of the rule.', + name: 'rule.tags', + }, + { + description: 'The space ID of the rule.', + name: 'rule.spaceId', + }, + { + description: 'The count of new alerts.', + name: 'alerts.new.count', + }, + { + description: 'An array of objects for new alerts.', + name: 'alerts.new.data', + }, + { + description: 'The count of ongoing alerts.', + name: 'alerts.ongoing.count', + }, + { + description: 'An array of objects for ongoing alerts.', + name: 'alerts.ongoing.data', + }, + { + description: 'The count of recovered alerts.', + name: 'alerts.recovered.count', + }, + { + description: 'An array of objects for recovered alerts.', + name: 'alerts.recovered.data', + }, + { + description: 'The count of all alerts.', + name: 'alerts.all.count', + }, + { + description: 'An array of objects for all alerts.', + name: 'alerts.all.data', + }, +]; + describe('transformActionVariables', () => { test('should return correct variables when no state, no context, no params provided', async () => { const alertType = getAlertType({ context: [], state: [], params: [] }); @@ -225,6 +297,12 @@ describe('transformActionVariables', () => { ...expectedParamsTransformResult(), ]); }); + test('should return correct variables when isAlertSummary = true', async () => { + const alertType = getAlertType({ context: [], state: [], params: [] }); + expect(transformActionVariables(alertType.actionVariables, undefined, true)).toEqual( + expectedSummaryTransformResult + ); + }); }); function getAlertType(actionVariables: ActionVariables): RuleType { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.ts index 58942aa069403..cc85d4adbb068 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.ts @@ -15,8 +15,13 @@ export type OmitMessageVariablesType = 'all' | 'keepContext'; // return a "flattened" list of action variables for an alertType export function transformActionVariables( actionVariables: ActionVariables, - omitMessageVariables?: OmitMessageVariablesType + omitMessageVariables?: OmitMessageVariablesType, + isSummaryAction?: boolean ): ActionVariable[] { + if (isSummaryAction) { + return getSummaryAlertActionVariables(); + } + const filteredActionVariables: ActionVariables = omitMessageVariables ? omitMessageVariables === 'all' ? pick(actionVariables, REQUIRED_ACTION_VARIABLES) @@ -48,6 +53,7 @@ export enum AlertProvidedActionVariables { alertActionGroupName = 'alert.actionGroupName', alertActionSubgroup = 'alert.actionSubgroup', alertFlapping = 'alert.flapping', + kibanaBaseUrl = 'kibanaBaseUrl', } export enum LegacyAlertProvidedActionVariables { @@ -61,66 +67,95 @@ export enum LegacyAlertProvidedActionVariables { spaceId = 'spaceId', } -function prefixKeys(actionVariables: ActionVariable[], prefix: string): ActionVariable[] { - return actionVariables.map((actionVariable) => { - return { ...actionVariable, name: `${prefix}${actionVariable.name}` }; - }); +export enum SummaryAlertProvidedActionVariables { + ruleParams = 'rule.params', + newAlertsCount = 'alerts.new.count', + newAlertsData = 'alerts.new.data', + ongoingAlertsCount = 'alerts.ongoing.count', + ongoingAlertsData = 'alerts.ongoing.data', + recoveredAlertsCount = 'alerts.recovered.count', + recoveredAlertsData = 'alerts.recovered.data', + allAlertsCount = 'alerts.all.count', + allAlertsData = 'alerts.all.data', } -// this list should be the same as in: -// x-pack/plugins/alerting/server/task_runner/transform_action_params.ts -function getAlwaysProvidedActionVariables(): ActionVariable[] { - const result: ActionVariable[] = []; - - result.push({ +const AlertProvidedActionVariableDescriptions = { + [AlertProvidedActionVariables.ruleId]: { name: AlertProvidedActionVariables.ruleId, description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleIdLabel', { defaultMessage: 'The ID of the rule.', }), - }); - - result.push({ + }, + [AlertProvidedActionVariables.ruleName]: { name: AlertProvidedActionVariables.ruleName, description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleNameLabel', { defaultMessage: 'The name of the rule.', }), - }); - - result.push({ + }, + [AlertProvidedActionVariables.ruleSpaceId]: { name: AlertProvidedActionVariables.ruleSpaceId, description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleSpaceIdLabel', { defaultMessage: 'The space ID of the rule.', }), - }); - - result.push({ + }, + [AlertProvidedActionVariables.ruleTags]: { name: AlertProvidedActionVariables.ruleTags, description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleTagsLabel', { defaultMessage: 'The tags of the rule.', }), - }); - - result.push({ + }, + [AlertProvidedActionVariables.ruleType]: { name: AlertProvidedActionVariables.ruleType, description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleTypeLabel', { defaultMessage: 'The type of rule.', }), - }); - - result.push({ + }, + [AlertProvidedActionVariables.ruleUrl]: { name: AlertProvidedActionVariables.ruleUrl, description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleUrlLabel', { defaultMessage: 'The URL to the Stack Management rule page that generated the alert. This will be an empty string if the server.publicBaseUrl is not configured.', }), - }); - - result.push({ + }, + [AlertProvidedActionVariables.date]: { name: AlertProvidedActionVariables.date, description: i18n.translate('xpack.triggersActionsUI.actionVariables.dateLabel', { defaultMessage: 'The date the rule scheduled the action.', }), + }, + [AlertProvidedActionVariables.kibanaBaseUrl]: { + name: AlertProvidedActionVariables.kibanaBaseUrl, + description: i18n.translate('xpack.triggersActionsUI.actionVariables.kibanaBaseUrlLabel', { + defaultMessage: + 'The configured server.publicBaseUrl value or empty string if not configured.', + }), + }, +}; + +function prefixKeys(actionVariables: ActionVariable[], prefix: string): ActionVariable[] { + return actionVariables.map((actionVariable) => { + return { ...actionVariable, name: `${prefix}${actionVariable.name}` }; }); +} + +// this list should be the same as in: +// x-pack/plugins/alerting/server/task_runner/transform_action_params.ts +function getAlwaysProvidedActionVariables(): ActionVariable[] { + const result: ActionVariable[] = []; + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.ruleId]); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.ruleName]); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.ruleSpaceId]); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.ruleTags]); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.ruleType]); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.ruleUrl]); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.date]); result.push({ name: AlertProvidedActionVariables.alertId, @@ -165,13 +200,7 @@ function getAlwaysProvidedActionVariables(): ActionVariable[] { }), }); - result.push({ - name: 'kibanaBaseUrl', - description: i18n.translate('xpack.triggersActionsUI.actionVariables.kibanaBaseUrlLabel', { - defaultMessage: - 'The configured server.publicBaseUrl value or empty string if not configured.', - }), - }); + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.kibanaBaseUrl]); result.push({ name: LegacyAlertProvidedActionVariables.alertId, @@ -275,3 +304,85 @@ function getAlwaysProvidedActionVariables(): ActionVariable[] { return result; } +function getSummaryAlertActionVariables(): ActionVariable[] { + const result: ActionVariable[] = []; + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.kibanaBaseUrl]); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.date]); + + result.push({ + name: SummaryAlertProvidedActionVariables.ruleParams, + description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleParamsLabel', { + defaultMessage: 'The params of the rule.', + }), + }); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.ruleId]); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.ruleName]); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.ruleType]); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.ruleUrl]); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.ruleTags]); + + result.push(AlertProvidedActionVariableDescriptions[AlertProvidedActionVariables.ruleSpaceId]); + + result.push({ + name: SummaryAlertProvidedActionVariables.newAlertsCount, + description: i18n.translate('xpack.triggersActionsUI.actionVariables.newAlertsCountLabel', { + defaultMessage: 'The count of new alerts.', + }), + }); + result.push({ + name: SummaryAlertProvidedActionVariables.newAlertsData, + description: i18n.translate('xpack.triggersActionsUI.actionVariables.newAlertsDataLabel', { + defaultMessage: 'An array of objects for new alerts.', + }), + }); + result.push({ + name: SummaryAlertProvidedActionVariables.ongoingAlertsCount, + description: i18n.translate('xpack.triggersActionsUI.actionVariables.ongoingAlertsCountLabel', { + defaultMessage: 'The count of ongoing alerts.', + }), + }); + result.push({ + name: SummaryAlertProvidedActionVariables.ongoingAlertsData, + description: i18n.translate('xpack.triggersActionsUI.actionVariables.ongoingAlertsDataLabel', { + defaultMessage: 'An array of objects for ongoing alerts.', + }), + }); + result.push({ + name: SummaryAlertProvidedActionVariables.recoveredAlertsCount, + description: i18n.translate( + 'xpack.triggersActionsUI.actionVariables.recoveredAlertsCountLabel', + { + defaultMessage: 'The count of recovered alerts.', + } + ), + }); + result.push({ + name: SummaryAlertProvidedActionVariables.recoveredAlertsData, + description: i18n.translate( + 'xpack.triggersActionsUI.actionVariables.recoveredAlertsDataLabel', + { + defaultMessage: 'An array of objects for recovered alerts.', + } + ), + }); + result.push({ + name: SummaryAlertProvidedActionVariables.allAlertsCount, + description: i18n.translate('xpack.triggersActionsUI.actionVariables.allAlertsCountLabel', { + defaultMessage: 'The count of all alerts.', + }), + }); + result.push({ + name: SummaryAlertProvidedActionVariables.allAlertsData, + description: i18n.translate('xpack.triggersActionsUI.actionVariables.allAlertsDataLabel', { + defaultMessage: 'An array of objects for all alerts.', + }), + }); + + return result; +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx index d75ff43eddd6c..900d2339ec87e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx @@ -69,6 +69,7 @@ export interface ActionAccordionFormProps { isActionGroupDisabledForActionType?: (actionGroupId: string, actionTypeId: string) => boolean; hideActionHeader?: boolean; hideNotifyWhen?: boolean; + defaultSummaryMessage?: string; hasSummary?: boolean; minimumThrottleInterval?: [number | undefined, string]; } @@ -97,6 +98,7 @@ export const ActionForm = ({ isActionGroupDisabledForActionType, hideActionHeader, hideNotifyWhen, + defaultSummaryMessage, hasSummary, minimumThrottleInterval, }: ActionAccordionFormProps) => { @@ -401,6 +403,7 @@ export const ActionForm = ({ setActiveActionItem(undefined); }} hideNotifyWhen={hideNotifyWhen} + defaultSummaryMessage={defaultSummaryMessage} hasSummary={hasSummary} minimumThrottleInterval={minimumThrottleInterval} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx index 3d51b918c7e4e..445e983d7fb02 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx @@ -14,15 +14,29 @@ import { RuleAction, GenericValidationResult, ActionConnectorMode, + ActionVariables, } from '../../../types'; import { act } from 'react-dom/test-utils'; import { EuiFieldText } from '@elastic/eui'; -import { I18nProvider } from '@kbn/i18n-react'; +import { I18nProvider, __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render, waitFor, screen } from '@testing-library/react'; +import { + DEFAULT_FREQUENCY_WITHOUT_SUMMARY, + DEFAULT_FREQUENCY_WITH_SUMMARY, +} from '../../../common/constants'; +import { transformActionVariables } from '../../lib/action_variables'; jest.mock('../../../common/lib/kibana'); const actionTypeRegistry = actionTypeRegistryMock.create(); +jest.mock('../../lib/action_variables', () => { + const original = jest.requireActual('../../lib/action_variables'); + return { + ...original, + transformActionVariables: jest.fn(), + }; +}); + describe('action_type_form', () => { const mockedActionParamsFields = React.lazy(async () => ({ default() { @@ -76,20 +90,23 @@ describe('action_type_form', () => { actionTypeRegistry.get.mockReturnValue(actionType); const wrapper = mountWithIntl( - getActionTypeForm(1, undefined, { - id: '123', - actionTypeId: '.pagerduty', - group: 'recovered', - params: { - eventAction: 'recovered', - dedupKey: undefined, - summary: '2323', - source: 'source', - severity: '1', - timestamp: new Date().toISOString(), - component: 'test', - group: 'group', - class: 'test class', + getActionTypeForm({ + index: 1, + actionItem: { + id: '123', + actionTypeId: '.pagerduty', + group: 'recovered', + params: { + eventAction: 'recovered', + dedupKey: undefined, + summary: '2323', + source: 'source', + severity: '1', + timestamp: new Date().toISOString(), + component: 'test', + group: 'group', + class: 'test class', + }, }, }) ); @@ -127,20 +144,23 @@ describe('action_type_form', () => { render( - {getActionTypeForm(1, undefined, { - id: '123', - actionTypeId: '.pagerduty', - group: 'recovered', - params: { - eventAction: 'recovered', - dedupKey: undefined, - summary: '2323', - source: 'source', - severity: '1', - timestamp: new Date().toISOString(), - component: 'test', - group: 'group', - class: 'test class', + {getActionTypeForm({ + index: 1, + actionItem: { + id: '123', + actionTypeId: '.pagerduty', + group: 'recovered', + params: { + eventAction: 'recovered', + dedupKey: undefined, + summary: '2323', + source: 'source', + severity: '1', + timestamp: new Date().toISOString(), + component: 'test', + group: 'group', + class: 'test class', + }, }, })} @@ -172,20 +192,23 @@ describe('action_type_form', () => { actionTypeRegistry.get.mockReturnValue(actionType); const wrapper = mountWithIntl( - getActionTypeForm(1, undefined, { - id: '123', - actionTypeId: '.pagerduty', - group: 'recovered', - params: { - eventAction: 'recovered', - dedupKey: '232323', - summary: '2323', - source: 'source', - severity: '1', - timestamp: new Date().toISOString(), - component: 'test', - group: 'group', - class: 'test class', + getActionTypeForm({ + index: 1, + actionItem: { + id: '123', + actionTypeId: '.pagerduty', + group: 'recovered', + params: { + eventAction: 'recovered', + dedupKey: '232323', + summary: '2323', + source: 'source', + severity: '1', + timestamp: new Date().toISOString(), + component: 'test', + group: 'group', + class: 'test class', + }, }, }) ); @@ -221,20 +244,23 @@ describe('action_type_form', () => { actionTypeRegistry.get.mockReturnValue(actionType); const wrapper = mountWithIntl( - getActionTypeForm(1, undefined, { - id: '123', - actionTypeId: '.pagerduty', - group: 'recovered', - params: { - eventAction: 'recovered', - dedupKey: '232323', - summary: '2323', - source: 'source', - severity: '1', - timestamp: new Date().toISOString(), - component: 'test', - group: 'group', - class: 'test class', + getActionTypeForm({ + index: 1, + actionItem: { + id: '123', + actionTypeId: '.pagerduty', + group: 'recovered', + params: { + eventAction: 'recovered', + dedupKey: '232323', + summary: '2323', + source: 'source', + severity: '1', + timestamp: new Date().toISOString(), + component: 'test', + group: 'group', + class: 'test class', + }, }, }) ); @@ -262,19 +288,103 @@ describe('action_type_form', () => { // Clearing all mocks will also reset fake timers. jest.clearAllMocks(); }); + + it('resets action variables when the actionItem.frequency.summary changes', async () => { + const mockTransformActionVariables = transformActionVariables as jest.Mock; + const actionType = actionTypeRegistryMock.createMockActionTypeModel({ + id: '.pagerduty', + iconClass: 'test', + selectMessage: 'test', + validateParams: (): Promise> => { + const validationResult = { errors: {} }; + return Promise.resolve(validationResult); + }, + actionConnectorFields: null, + actionParamsFields: mockedActionParamsFields, + defaultActionParams: { + dedupKey: 'test', + eventAction: 'resolve', + }, + }); + actionTypeRegistry.get.mockReturnValue(actionType); + const actionItem = { + id: '123', + actionTypeId: '.pagerduty', + group: 'default', + params: {}, + frequency: DEFAULT_FREQUENCY_WITHOUT_SUMMARY, + }; + const wrapper = render( + + {getActionTypeForm({ + index: 1, + actionItem, + setActionFrequencyProperty: () => { + actionItem.frequency = DEFAULT_FREQUENCY_WITH_SUMMARY; + }, + })} + + ); + + const summaryOrPerRuleSelect = wrapper.getByTestId('summaryOrPerRuleSelect'); + expect(summaryOrPerRuleSelect).toBeTruthy(); + + const button = wrapper.getByText('For each alert'); + button.click(); + await act(async () => { + wrapper.getByText('Summary of alerts').click(); + }); + + expect(mockTransformActionVariables.mock.calls).toEqual([ + [ + { + context: [], + params: [], + state: [], + }, + undefined, + false, + ], + [ + { + context: [], + params: [], + state: [], + }, + undefined, + true, + ], + ]); + }); }); -function getActionTypeForm( - index?: number, - actionConnector?: ActionConnector, Record>, - actionItem?: RuleAction, - defaultActionGroupId?: string, - connectors?: Array, Record>>, - actionTypeIndex?: Record, - onAddConnector?: () => void, - onDeleteAction?: () => void, - onConnectorSelected?: (id: string) => void -) { +function getActionTypeForm({ + index, + actionConnector, + actionItem, + defaultActionGroupId, + connectors, + actionTypeIndex, + onAddConnector, + onDeleteAction, + onConnectorSelected, + setActionFrequencyProperty, + hasSummary = true, + messageVariables = { context: [], state: [], params: [] }, +}: { + index?: number; + actionConnector?: ActionConnector, Record>; + actionItem?: RuleAction; + defaultActionGroupId?: string; + connectors?: Array, Record>>; + actionTypeIndex?: Record; + onAddConnector?: () => void; + onDeleteAction?: () => void; + onConnectorSelected?: (id: string) => void; + setActionFrequencyProperty?: () => void; + hasSummary?: boolean; + messageVariables?: ActionVariables; +}) { const actionConnectorDefault = { actionTypeId: '.pagerduty', config: { @@ -287,7 +397,7 @@ function getActionTypeForm( secrets: {}, }; - const actionItemDefault = { + const actionItemDefault: RuleAction = { id: '123', actionTypeId: '.pagerduty', group: 'trigger', @@ -351,10 +461,12 @@ function getActionTypeForm( onConnectorSelected={onConnectorSelected ?? jest.fn()} defaultActionGroupId={defaultActionGroupId ?? 'default'} setActionParamsProperty={jest.fn()} - setActionFrequencyProperty={jest.fn()} + setActionFrequencyProperty={setActionFrequencyProperty ?? jest.fn()} index={index ?? 1} actionTypesIndex={actionTypeIndex ?? actionTypeIndexDefault} actionTypeRegistry={actionTypeRegistry} + hasSummary={hasSummary} + messageVariables={messageVariables} /> ); } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx index c3271a0a05324..4615dae4780cb 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx @@ -78,6 +78,7 @@ export type ActionTypeFormProps = { | 'setActionParamsProperty' | 'messageVariables' | 'defaultActionMessage' + | 'defaultSummaryMessage' >; const preconfiguredMessage = i18n.translate( @@ -107,6 +108,7 @@ export const ActionTypeForm = ({ isActionGroupDisabledForActionType, recoveryActionGroup, hideNotifyWhen = false, + defaultSummaryMessage, hasSummary, minimumThrottleInterval, }: ActionTypeFormProps) => { @@ -135,6 +137,7 @@ export const ActionTypeForm = ({ -1, 's', ]; + const isSummaryAction = actionItem.frequency?.summary; const getDefaultParams = async () => { const connectorType = await actionTypeRegistry.get(actionItem.actionTypeId); @@ -172,7 +175,9 @@ export const ActionTypeForm = ({ useEffect(() => { (async () => { setAvailableActionVariables( - messageVariables ? getAvailableActionVariables(messageVariables, selectedActionGroup) : [] + messageVariables + ? getAvailableActionVariables(messageVariables, selectedActionGroup, isSummaryAction) + : [] ); const defaultParams = await getDefaultParams(); @@ -185,7 +190,7 @@ export const ActionTypeForm = ({ } })(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [actionItem.group]); + }, [actionItem.group, actionItem.frequency?.summary]); useEffect(() => { (async () => { @@ -376,7 +381,12 @@ export const ActionTypeForm = ({ errors={actionParamsErrors.errors} editAction={setActionParamsProperty} messageVariables={availableActionVariables} - defaultMessage={selectedActionGroup?.defaultActionMessage ?? defaultActionMessage} + defaultMessage={ + // if action is a summary action, show the default summary message + isSummaryAction + ? defaultSummaryMessage + : selectedActionGroup?.defaultActionMessage ?? defaultActionMessage + } actionConnector={actionConnector} executionMode={ActionConnectorMode.ActionForm} /> @@ -518,11 +528,13 @@ export const ActionTypeForm = ({ function getAvailableActionVariables( actionVariables: ActionVariables, - actionGroup?: ActionGroupWithMessageVariables + actionGroup?: ActionGroupWithMessageVariables, + isSummaryAction?: boolean ) { const transformedActionVariables: ActionVariable[] = transformActionVariables( actionVariables, - actionGroup?.omitMessageVariables + actionGroup?.omitMessageVariables, + isSummaryAction ); // partition deprecated items so they show up last diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx index 291e81fc14e51..40a8d7f5722e8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx @@ -67,7 +67,7 @@ import { hasAllPrivilege, hasShowActionsCapability } from '../../lib/capabilitie import { SolutionFilter } from './solution_filter'; import './rule_form.scss'; import { useKibana } from '../../../common/lib/kibana'; -import { recoveredActionGroupMessage } from '../../constants'; +import { recoveredActionGroupMessage, summaryMessage } from '../../constants'; import { IsEnabledResult, IsDisabledResult } from '../../lib/check_rule_type_enabled'; import { checkRuleTypeEnabled } from '../../lib/check_rule_type_enabled'; import { ruleTypeCompare, ruleTypeGroupCompare } from '../../lib/rule_type_compare'; @@ -673,6 +673,7 @@ export const RuleForm = ({ setActionParamsProperty={setActionParamsProperty} actionTypeRegistry={actionTypeRegistry} setActionFrequencyProperty={setActionFrequencyProperty} + defaultSummaryMessage={ruleTypeModel?.defaultSummaryMessage || summaryMessage} minimumThrottleInterval={[ruleInterval, ruleIntervalUnit]} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index 109a88b6b5a1e..813b18f9ae444 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -379,6 +379,7 @@ export interface RuleTypeModel { requiresAppContext: boolean; defaultActionMessage?: string; defaultRecoveryMessage?: string; + defaultSummaryMessage?: string; alertDetailsAppSection?: | React.FunctionComponent | React.LazyExoticComponent>;