From 751615e8b280eed2646374a0f5ab3ae18a588517 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Wed, 27 Jul 2022 12:01:49 -0600 Subject: [PATCH] pr fixes --- .../action_form.test.tsx | 471 +++++++----------- .../action_connector_form/action_form.tsx | 5 + .../action_type_form.tsx | 1 + .../action_type_menu.test.tsx | 40 ++ .../connector_add_modal.scss | 4 + .../connector_add_modal.tsx | 2 +- .../create_connector_flyout/index.test.tsx | 14 + .../create_connector_flyout/index.tsx | 1 + 8 files changed, 255 insertions(+), 283 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.test.tsx index 3001717fb023eb..dc66f0cb594c99 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.test.tsx @@ -180,173 +180,181 @@ describe('action_form', () => { const useKibanaMock = useKibana as jest.Mocked; - describe('action_form in alert', () => { - async function setup(customActions?: RuleAction[], customRecoveredActionGroup?: string) { - const actionTypeRegistry = actionTypeRegistryMock.create(); - - const { loadAllActions } = jest.requireMock('../../lib/action_connector_api'); - loadAllActions.mockResolvedValueOnce(allActions); - const mocks = coreMock.createSetup(); - const [ - { - application: { capabilities }, - }, - ] = await mocks.getStartServices(); - // eslint-disable-next-line react-hooks/rules-of-hooks - useKibanaMock().services.application.capabilities = { - ...capabilities, - actions: { - show: true, - save: true, - delete: true, - }, - }; - actionTypeRegistry.list.mockReturnValue([ - actionType, - disabledByConfigActionType, - disabledByLicenseActionType, - disabledByActionType, - preconfiguredOnly, - ]); - actionTypeRegistry.has.mockReturnValue(true); - actionTypeRegistry.get.mockReturnValue(actionType); - const initialAlert = { - name: 'test', - params: {}, - consumer: 'alerts', - alertTypeId: alertType.id, - schedule: { - interval: '1m', - }, - actions: customActions - ? customActions - : [ - { - group: 'default', - id: 'test', - actionTypeId: actionType.id, - params: { - message: '', - }, - }, - ], - tags: [], - muteAll: false, - enabled: false, - mutedInstanceIds: [], - } as unknown as Rule; - - loadActionTypes.mockResolvedValue([ - { - id: actionType.id, - name: 'Test', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'basic', - supportedFeatureIds: ['alerting'], - }, - { - id: '.index', - name: 'Index', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'basic', - supportedFeatureIds: ['alerting'], - }, - { - id: 'preconfigured', - name: 'Preconfigured only', - enabled: true, - enabledInConfig: false, - enabledInLicense: true, - minimumLicenseRequired: 'basic', - supportedFeatureIds: ['alerting'], - }, - { - id: 'disabled-by-config', - name: 'Disabled by config', - enabled: false, - enabledInConfig: false, - enabledInLicense: true, - minimumLicenseRequired: 'gold', - supportedFeatureIds: ['alerting'], - }, - { - id: 'disabled-by-license', - name: 'Disabled by license', - enabled: false, - enabledInConfig: true, - enabledInLicense: false, - minimumLicenseRequired: 'gold', - supportedFeatureIds: ['alerting'], - }, - { - id: '.jira', - name: 'Disabled by action type', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'basic', - supportedFeatureIds: ['alerting'], - }, - ]); - - const defaultActionMessage = 'Alert [{{context.metadata.name}}] has exceeded the threshold'; - const wrapper = mountWithIntl( - { - const recoveryActionGroupId = customRecoveredActionGroup - ? customRecoveredActionGroup - : 'recovered'; - return isActionGroupDisabledForActionTypeId( - actionGroupId === recoveryActionGroupId ? RecoveredActionGroup.id : actionGroupId, - actionTypeId - ); - }} - setActionIdByIndex={(id: string, index: number) => { - initialAlert.actions[index].id = id; - }} - actionGroups={[ - { id: 'default', name: 'Default', defaultActionMessage }, + async function setup( + customActions?: RuleAction[], + customRecoveredActionGroup?: string, + isExperimental?: boolean + ) { + const actionTypeRegistry = actionTypeRegistryMock.create(); + + const { loadAllActions } = jest.requireMock('../../lib/action_connector_api'); + loadAllActions.mockResolvedValueOnce(allActions); + const mocks = coreMock.createSetup(); + const [ + { + application: { capabilities }, + }, + ] = await mocks.getStartServices(); + // eslint-disable-next-line react-hooks/rules-of-hooks + useKibanaMock().services.application.capabilities = { + ...capabilities, + actions: { + show: true, + save: true, + delete: true, + }, + }; + const newActionType = { + ...actionType, + isExperimental, + }; + actionTypeRegistry.list.mockReturnValue([ + newActionType, + disabledByConfigActionType, + disabledByLicenseActionType, + disabledByActionType, + preconfiguredOnly, + ]); + actionTypeRegistry.has.mockReturnValue(true); + actionTypeRegistry.get.mockReturnValue(newActionType); + const initialAlert = { + name: 'test', + params: {}, + consumer: 'alerts', + alertTypeId: alertType.id, + schedule: { + interval: '1m', + }, + actions: customActions + ? customActions + : [ { - id: customRecoveredActionGroup ? customRecoveredActionGroup : 'recovered', - name: customRecoveredActionGroup ? 'I feel better' : 'Recovered', + group: 'default', + id: 'test', + actionTypeId: newActionType.id, + params: { + message: '', + }, }, - ]} - setActionGroupIdByIndex={(group: string, index: number) => { - initialAlert.actions[index].group = group; - }} - setActions={(_updatedActions: RuleAction[]) => {}} - setActionParamsProperty={(key: string, value: any, index: number) => - (initialAlert.actions[index] = { ...initialAlert.actions[index], [key]: value }) - } - actionTypeRegistry={actionTypeRegistry} - setHasActionsWithBrokenConnector={setHasActionsWithBrokenConnector} - /> - ); - - // Wait for active space to resolve before requesting the component to update - await act(async () => { - await nextTick(); - wrapper.update(); - }); + ], + tags: [], + muteAll: false, + enabled: false, + mutedInstanceIds: [], + } as unknown as Rule; + + loadActionTypes.mockResolvedValue([ + { + id: newActionType.id, + name: 'Test', + enabled: true, + enabledInConfig: true, + enabledInLicense: true, + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + }, + { + id: '.index', + name: 'Index', + enabled: true, + enabledInConfig: true, + enabledInLicense: true, + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + }, + { + id: 'preconfigured', + name: 'Preconfigured only', + enabled: true, + enabledInConfig: false, + enabledInLicense: true, + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + }, + { + id: 'disabled-by-config', + name: 'Disabled by config', + enabled: false, + enabledInConfig: false, + enabledInLicense: true, + minimumLicenseRequired: 'gold', + supportedFeatureIds: ['alerting'], + }, + { + id: 'disabled-by-license', + name: 'Disabled by license', + enabled: false, + enabledInConfig: true, + enabledInLicense: false, + minimumLicenseRequired: 'gold', + supportedFeatureIds: ['alerting'], + }, + { + id: '.jira', + name: 'Disabled by action type', + enabled: true, + enabledInConfig: true, + enabledInLicense: true, + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + }, + ]); + + const defaultActionMessage = 'Alert [{{context.metadata.name}}] has exceeded the threshold'; + const wrapper = mountWithIntl( + { + const recoveryActionGroupId = customRecoveredActionGroup + ? customRecoveredActionGroup + : 'recovered'; + return isActionGroupDisabledForActionTypeId( + actionGroupId === recoveryActionGroupId ? RecoveredActionGroup.id : actionGroupId, + actionTypeId + ); + }} + setActionIdByIndex={(id: string, index: number) => { + initialAlert.actions[index].id = id; + }} + actionGroups={[ + { id: 'default', name: 'Default', defaultActionMessage }, + { + id: customRecoveredActionGroup ? customRecoveredActionGroup : 'recovered', + name: customRecoveredActionGroup ? 'I feel better' : 'Recovered', + }, + ]} + setActionGroupIdByIndex={(group: string, index: number) => { + initialAlert.actions[index].group = group; + }} + setActions={(_updatedActions: RuleAction[]) => {}} + setActionParamsProperty={(key: string, value: any, index: number) => + (initialAlert.actions[index] = { ...initialAlert.actions[index], [key]: value }) + } + actionTypeRegistry={actionTypeRegistry} + setHasActionsWithBrokenConnector={setHasActionsWithBrokenConnector} + /> + ); + + // Wait for active space to resolve before requesting the component to update + await act(async () => { + await nextTick(); + wrapper.update(); + }); - return wrapper; - } + return wrapper; + } + describe('action_form in alert', () => { it('renders available action cards', async () => { const wrapper = await setup(); const actionOption = wrapper.find( @@ -607,127 +615,26 @@ describe('action_form', () => { }); describe('beta badge (action_type_form)', () => { - async function setup(isExperimental: boolean) { - const actionTypeRegistry = actionTypeRegistryMock.create(); - - const { loadAllActions } = jest.requireMock('../../lib/action_connector_api'); - loadAllActions.mockResolvedValueOnce(allActions); - const mocks = coreMock.createSetup(); - const [ - { - application: { capabilities }, - }, - ] = await mocks.getStartServices(); - // eslint-disable-next-line react-hooks/rules-of-hooks - useKibanaMock().services.application.capabilities = { - ...capabilities, - actions: { - show: true, - save: true, - delete: true, - }, - }; - const newActionType = { - ...actionType, - isExperimental, - }; - actionTypeRegistry.list.mockReturnValue([newActionType]); - actionTypeRegistry.has.mockReturnValue(true); - actionTypeRegistry.get.mockReturnValue(newActionType); - const initialAlert = { - name: 'test', - params: {}, - consumer: 'alerts', - alertTypeId: alertType.id, - schedule: { - interval: '1m', - }, - actions: [ - { - group: 'default', - id: 'test', - actionTypeId: actionType.id, - params: { - message: '', - }, - }, - ], - tags: [], - muteAll: false, - enabled: false, - mutedInstanceIds: [], - } as unknown as Rule; - - loadActionTypes.mockResolvedValue([ - { - id: actionType.id, - name: 'Test', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'basic', - supportedFeatureIds: ['alerting'], - }, - ]); - - const defaultActionMessage = 'Alert [{{context.metadata.name}}] has exceeded the threshold'; - const wrapper = mountWithIntl( - { - const recoveryActionGroupId = 'recovered'; - return isActionGroupDisabledForActionTypeId( - actionGroupId === recoveryActionGroupId ? RecoveredActionGroup.id : actionGroupId, - actionTypeId - ); - }} - setActionIdByIndex={(id: string, index: number) => { - initialAlert.actions[index].id = id; - }} - actionGroups={[ - { id: 'default', name: 'Default', defaultActionMessage }, - { - id: 'recovered', - name: 'Recovered', - }, - ]} - setActionGroupIdByIndex={(group: string, index: number) => { - initialAlert.actions[index].group = group; - }} - setActions={(_updatedActions: RuleAction[]) => {}} - setActionParamsProperty={(key: string, value: any, index: number) => - (initialAlert.actions[index] = { ...initialAlert.actions[index], [key]: value }) - } - actionTypeRegistry={actionTypeRegistry} - setHasActionsWithBrokenConnector={setHasActionsWithBrokenConnector} - /> - ); - - // Wait for active space to resolve before requesting the component to update - await act(async () => { - await nextTick(); - wrapper.update(); - }); - - return wrapper; - } + it(`does not render beta badge when isExperimental=undefined`, async () => { + const wrapper = await setup(); + expect(wrapper.find('EuiKeyPadMenuItem EuiBetaBadge').exists()).toBeFalsy(); + expect( + wrapper.find('EuiBetaBadge[data-test-subj="action-type-form-beta-badge"]').exists() + ).toBeFalsy(); + }); it(`does not render beta badge when isExperimental=false`, async () => { - const wrapper = await setup(false); - expect(wrapper.find('EuiBetaBadge').exists()).toBeFalsy(); + const wrapper = await setup(undefined, undefined, false); + expect(wrapper.find('EuiKeyPadMenuItem EuiBetaBadge').exists()).toBeFalsy(); + expect( + wrapper.find('EuiBetaBadge[data-test-subj="action-type-form-beta-badge"]').exists() + ).toBeFalsy(); }); - it(`renders beta badge when isExperimental=tru`, async () => { - const wrapper = await setup(true); - expect(wrapper.find('EuiBetaBadge').exists()).toBeTruthy(); + it(`renders beta badge when isExperimental=true`, async () => { + const wrapper = await setup(undefined, undefined, true); + expect(wrapper.find('EuiKeyPadMenuItem EuiBetaBadge').exists()).toBeTruthy(); + expect( + wrapper.find('EuiBetaBadge[data-test-subj="action-type-form-beta-badge"]').exists() + ).toBeTruthy(); }); }); }); 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 391b0b60350004..06978dc8c13eab 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 @@ -20,6 +20,7 @@ import { EuiLink, } from '@elastic/eui'; import { ActionGroup, RuleActionParam } from '@kbn/alerting-plugin/common'; +import { betaBadgeProps } from './beta_badge_props'; import { loadActionTypes, loadAllActions as loadConnectors } from '../../lib/action_connector_api'; import { ActionTypeModel, @@ -256,6 +257,10 @@ export const ActionForm = ({ isDisabled={!checkEnabledResult.isEnabled} data-test-subj={`${item.id}-${featureId}-ActionTypeSelectOption`} label={actionTypesIndex[item.id].name} + betaBadgeLabel={item.isExperimental ? betaBadgeProps.label : undefined} + betaBadgeTooltipContent={ + item.isExperimental ? betaBadgeProps.tooltipContent : undefined + } onClick={() => addActionType(item)} > diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_menu.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_menu.test.tsx index 702ee340d57f84..370e61b9fe5dce 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_menu.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_menu.test.tsx @@ -168,6 +168,46 @@ describe('connector_add_flyout', () => { }); describe('beta badge', () => { + it(`does not render beta badge when isExperimental=undefined`, async () => { + const onActionTypeChange = jest.fn(); + const actionType = actionTypeRegistryMock.createMockActionTypeModel({ + id: 'my-action-type', + iconClass: 'test', + selectMessage: 'test', + validateParams: (): Promise> => { + const validationResult = { errors: {} }; + return Promise.resolve(validationResult); + }, + actionConnectorFields: null, + }); + actionTypeRegistry.get.mockReturnValueOnce(actionType); + loadActionTypes.mockResolvedValueOnce([ + { + id: actionType.id, + enabled: false, + name: 'Test', + enabledInConfig: true, + enabledInLicense: false, + minimumLicenseRequired: 'gold', + supportedFeatureIds: ['alerting'], + }, + ]); + + const wrapper = mountWithIntl( + + ); + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect( + wrapper.find('EuiToolTip [data-test-subj="my-action-type-card"] EuiBetaBadge').exists() + ).toBeFalsy(); + }); it(`does not render beta badge when isExperimental=false`, async () => { const onActionTypeChange = jest.fn(); const actionType = actionTypeRegistryMock.createMockActionTypeModel({ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.scss b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.scss index 7f56c220db4bb4..76f4843bfbc77f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.scss +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.scss @@ -5,3 +5,7 @@ .euiComboBoxOptionsList { z-index: 9001; } +.betaBadgeFlexItem.euiFlexItem.euiFlexItem--flexGrowZero { + margin-top: 10px; + margin-bottom: 3px; +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.tsx index 5aa31056e1355a..3c73acfc69118a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.tsx @@ -156,7 +156,7 @@ const ConnectorAddModal = ({ {actionTypeModel && actionTypeModel.isExperimental && ( - + { expect(getByText(`selectMessage-${actionTypeModel.id}`)).toBeInTheDocument(); }); + it('does not show beta badge when isExperimental is undefined', async () => { + const { queryByText } = appMockRenderer.render( + + ); + await act(() => Promise.resolve()); + expect(queryByText(betaBadgeProps.label)).not.toBeInTheDocument(); + }); + it('does not show beta badge when isExperimental is false', async () => { + actionTypeRegistry.get.mockReturnValue({ ...actionTypeModel, isExperimental: false }); const { queryByText } = appMockRenderer.render( = ({ isMounted.current = false; }; }, []); + return (