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>;