From 950ae1e43bc95536cadea3d67efa12ae3545b268 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 10 Apr 2020 14:55:03 -0700 Subject: [PATCH] Added UI for pre-configured connectors. (#63074) * Added UI for pre-configured connectors. * fixed due to comments * Fixed jest tests * Fixed due to comments and added some functional tests * test fix * Fixed failed checks * Fixed functional tests failing --- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - .../components/add_message_variables.tsx | 3 +- .../action_connector_form/action_form.tsx | 15 +- .../connector_edit_flyout.test.tsx | 56 +++++++ .../connector_edit_flyout.tsx | 137 +++++++++++++----- .../actions_connectors_list.test.tsx | 16 +- .../components/actions_connectors_list.tsx | 78 +++++++--- .../apps/triggers_actions_ui/alerts.ts | 22 ++- .../apps/triggers_actions_ui/connectors.ts | 25 ++++ x-pack/test/functional_with_es_ssl/config.ts | 10 ++ 11 files changed, 286 insertions(+), 78 deletions(-) diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 9bef5c25fdad8e..60c6166e5f5bd1 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -16117,7 +16117,6 @@ "xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.userTextFieldLabel": "ユーザー名", "xpack.triggersActionsUI.sections.editConnectorForm.betaBadgeTooltipContent": "{pluginName} はベータ段階で、変更される可能性があります。デザインとコードはオフィシャル GA 機能よりも完成度が低く、現状のまま保証なしで提供されています。ベータ機能にはオフィシャル GA 機能の SLA が適用されません。", "xpack.triggersActionsUI.sections.editConnectorForm.cancelButtonLabel": "キャンセル", - "xpack.triggersActionsUI.sections.editConnectorForm.flyoutTitle": "コネクターを編集", "xpack.triggersActionsUI.sections.editConnectorForm.saveButtonLabel": "保存", "xpack.triggersActionsUI.sections.editConnectorForm.updateErrorNotificationText": "コネクターを更新できません。", "xpack.triggersActionsUI.sections.editConnectorForm.updateSuccessNotificationText": "「{connectorName}」を更新しました", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 8dd0bdff295d63..899c440c5f2044 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -16122,7 +16122,6 @@ "xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.userTextFieldLabel": "用户名", "xpack.triggersActionsUI.sections.editConnectorForm.betaBadgeTooltipContent": "{pluginName} 为公测版,可能会进行更改。设计和代码相对于正式发行版功能还不够成熟,将按原样提供,且不提供任何保证。公测版功能不受正式发行版功能支持 SLA 的约束。", "xpack.triggersActionsUI.sections.editConnectorForm.cancelButtonLabel": "取消", - "xpack.triggersActionsUI.sections.editConnectorForm.flyoutTitle": "编辑连接器", "xpack.triggersActionsUI.sections.editConnectorForm.saveButtonLabel": "保存", "xpack.triggersActionsUI.sections.editConnectorForm.updateErrorNotificationText": "无法更新连接器。", "xpack.triggersActionsUI.sections.editConnectorForm.updateSuccessNotificationText": "已更新“{connectorName}”", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.tsx index ab9b5c2586c177..957c79a5c51239 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/add_message_variables.tsx @@ -22,9 +22,10 @@ export const AddMessageVariables: React.FunctionComponent = ({ const [isVariablesPopoverOpen, setIsVariablesPopoverOpen] = useState(false); const getMessageVariables = () => - messageVariables?.map((variable: string) => ( + messageVariables?.map((variable: string, i: number) => ( { onSelectEventHandler(variable); 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 6b011ac84bc6f1..5890d9fe07f0ea 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 @@ -141,15 +141,22 @@ export const ActionForm = ({ }); } } + const preconfiguredMessage = i18n.translate( + 'xpack.triggersActionsUI.sections.actionForm.preconfiguredTitleMessage', + { + defaultMessage: '(pre-configured)', + } + ); const getSelectedOptions = (actionItemId: string) => { const val = connectors.find(connector => connector.id === actionItemId); if (!val) { return []; } + const optionTitle = `${val.name} ${val.isPreconfigured ? preconfiguredMessage : ''}`; return [ { - label: val.name, - value: val.name, + label: optionTitle, + value: optionTitle, id: actionItemId, }, ]; @@ -264,7 +271,9 @@ export const ActionForm = ({ defaultMessage="{actionConnectorName}" id="xpack.triggersActionsUI.sections.alertForm.selectAlertActionTypeEditTitle" values={{ - actionConnectorName: actionConnector.name, + actionConnectorName: `${actionConnector.name} ${ + actionConnector.isPreconfigured ? preconfiguredMessage : '' + }`, }} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx index 2c063ea6b4fa64..66598887976795 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx @@ -95,4 +95,60 @@ describe('connector_edit_flyout', () => { expect(connectorNameField.exists()).toBeTruthy(); expect(connectorNameField.first().prop('value')).toBe('action-connector'); }); + + test('if pre-configured connector rendered correct in the edit form', () => { + const connector = { + secrets: {}, + id: 'test', + actionTypeId: 'test-action-type-id', + actionType: 'test-action-type-name', + name: 'pre-configured-connector', + isPreconfigured: true, + referencedByCount: 0, + config: {}, + }; + + const actionType = { + id: 'test-action-type-id', + iconClass: 'test', + selectMessage: 'test', + validateConnector: (): ValidationResult => { + return { errors: {} }; + }, + validateParams: (): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, + actionConnectorFields: null, + actionParamsFields: null, + }; + actionTypeRegistry.get.mockReturnValue(actionType); + actionTypeRegistry.has.mockReturnValue(true); + + const wrapper = mountWithIntl( + + { + return new Promise(() => {}); + }, + }} + > + {}} + /> + + + ); + + const preconfiguredBadge = wrapper.find('[data-test-subj="preconfiguredBadge"]'); + expect(preconfiguredBadge.exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="saveEditedActionButton"]').exists()).toBeFalsy(); + }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.tsx index ed8811d26331b9..a81d6c285f460b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { useCallback, useReducer, useState } from 'react'; +import React, { useCallback, useReducer, useState, Fragment } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiTitle, @@ -17,6 +17,8 @@ import { EuiButtonEmpty, EuiButton, EuiBetaBadge, + EuiText, + EuiLink, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ActionConnectorForm, validateBaseProperties } from './action_connector_form'; @@ -91,8 +93,77 @@ export const ConnectorEditFlyout = ({ return undefined; }); + const flyoutTitle = connector.isPreconfigured ? ( + + +

+ +   + +   + +

+
+ + + +
+ ) : ( + +

+ +   + +

+
+ ); + return ( - + {actionTypeModel ? ( @@ -100,41 +171,37 @@ export const ConnectorEditFlyout = ({ ) : null} - - -

- -   - -

-
-
+ {flyoutTitle}
- + {!connector.isPreconfigured ? ( + + ) : ( + + + {i18n.translate( + 'xpack.triggersActionsUI.sections.editConnectorForm.descriptionText', + { + defaultMessage: 'This connector is readonly.', + } + )} + + + + + + )} @@ -148,7 +215,7 @@ export const ConnectorEditFlyout = ({ )} - {canSave && actionTypeModel ? ( + {canSave && actionTypeModel && !connector.isPreconfigured ? ( { id: '1', actionTypeId: 'test', description: 'My test', + isPreconfigured: false, referencedByCount: 1, config: {}, }, @@ -119,6 +120,15 @@ describe('actions_connectors_list component with items', () => { actionTypeId: 'test2', description: 'My test 2', referencedByCount: 1, + isPreconfigured: false, + config: {}, + }, + { + id: '3', + actionTypeId: 'test2', + description: 'My preconfigured test 2', + referencedByCount: 1, + isPreconfigured: true, config: {}, }, ]); @@ -185,7 +195,11 @@ describe('actions_connectors_list component with items', () => { it('renders table of connectors', () => { expect(wrapper.find('EuiInMemoryTable')).toHaveLength(1); - expect(wrapper.find('EuiTableRow')).toHaveLength(2); + expect(wrapper.find('EuiTableRow')).toHaveLength(3); + }); + + it('renders table with preconfigured connectors', () => { + expect(wrapper.find('[data-test-subj="preConfiguredTitleMessage"]')).toHaveLength(2); }); test('if select item for edit should render ConnectorEditFlyout', () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 47e058f4739463..043a644489d82c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -15,6 +15,9 @@ import { EuiIconTip, EuiFlexGroup, EuiFlexItem, + EuiBetaBadge, + EuiToolTip, + EuiButtonIcon, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -200,31 +203,58 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { }, }, { - field: '', + field: 'isPreconfigured', name: '', - actions: [ - { - enabled: () => canDelete, - 'data-test-subj': 'deleteConnector', - name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionName', - { defaultMessage: 'Delete' } - ), - description: canDelete - ? i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionDescription', - { defaultMessage: 'Delete this connector' } - ) - : i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionDisabledDescription', - { defaultMessage: 'Unable to delete connectors' } - ), - type: 'icon', - icon: 'trash', - color: 'danger', - onClick: (item: ActionConnectorTableItem) => setConnectorsToDelete([item.id]), - }, - ], + render: (value: number, item: ActionConnectorTableItem) => { + if (item.isPreconfigured) { + return ( + + + + + + ); + } + return ( + + + + setConnectorsToDelete([item.id])} + iconType={'trash'} + /> + + + + ); + }, }, ]; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts index 6316c89c1d4e6f..0277ae471bb4bc 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts @@ -65,23 +65,21 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // need this two out of popup clicks to close them await nameInput.click(); + // test for normal connector + await testSubjects.click('.webhook-ActionTypeSelectOption'); + const webhookBodyInput = await find.byCssSelector('.ace_text-input'); + await webhookBodyInput.focus(); + await webhookBodyInput.type('{\\"test\\":1}'); + + await testSubjects.click('addAlertActionButton'); + // pre-configured connector is loaded an displayed correctly await testSubjects.click('.slack-ActionTypeSelectOption'); - await testSubjects.click('createActionConnectorButton'); - const connectorNameInput = await testSubjects.find('nameInput'); - await connectorNameInput.click(); - await connectorNameInput.clearValue(); - const connectorName = generateUniqueKey(); - await connectorNameInput.type(connectorName); - const slackWebhookUrlInput = await testSubjects.find('slackWebhookUrlInput'); - await slackWebhookUrlInput.click(); - await slackWebhookUrlInput.clearValue(); - await slackWebhookUrlInput.type('https://test'); - await find.clickByCssSelector('[data-test-subj="saveActionButtonModal"]:not(disabled)'); + expect(await (await find.byCssSelector('#my-slack1')).isDisplayed()).to.be(true); const loggingMessageInput = await testSubjects.find('slackMessageTextArea'); await loggingMessageInput.click(); await loggingMessageInput.clearValue(); await loggingMessageInput.type('test message'); - await testSubjects.click('slackAddVariableButton'); + await testSubjects.click('messageAddVariableButton'); const variableMenuButton = await testSubjects.find('variableMenuButton-0'); await variableMenuButton.click(); await testSubjects.click('saveAlertButton'); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index b5bcd33c3b9ab1..0e6f991be24d0c 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -184,5 +184,30 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const searchResultsAfterDelete = await pageObjects.triggersActionsUI.getConnectorsList(); expect(searchResultsAfterDelete.length).to.eql(0); }); + + it('should not be able to delete a pre-configured connector', async () => { + const preconfiguredConnectorName = 'xyz'; + await pageObjects.triggersActionsUI.searchConnectors(preconfiguredConnectorName); + + const searchResults = await pageObjects.triggersActionsUI.getConnectorsList(); + expect(searchResults.length).to.eql(1); + + expect(await testSubjects.exists('deleteConnector')).to.be(false); + expect(await testSubjects.exists('preConfiguredTitleMessage')).to.be(true); + }); + + it('should not be able to edit a pre-configured connector', async () => { + const preconfiguredConnectorName = 'xyz'; + + await pageObjects.triggersActionsUI.searchConnectors(preconfiguredConnectorName); + + const searchResultsBeforeEdit = await pageObjects.triggersActionsUI.getConnectorsList(); + expect(searchResultsBeforeEdit.length).to.eql(1); + + await find.clickByCssSelector('[data-test-subj="connectorsTableCell-name"] button'); + + expect(await testSubjects.exists('preconfiguredBadge')).to.be(true); + expect(await testSubjects.exists('saveEditedActionButton')).to.be(false); + }); }); }; diff --git a/x-pack/test/functional_with_es_ssl/config.ts b/x-pack/test/functional_with_es_ssl/config.ts index 538817bd9d14c9..a620b1d9533767 100644 --- a/x-pack/test/functional_with_es_ssl/config.ts +++ b/x-pack/test/functional_with_es_ssl/config.ts @@ -52,6 +52,16 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { `--plugin-path=${join(__dirname, 'fixtures', 'plugins', 'alerts')}`, '--xpack.actions.enabled=true', '--xpack.alerting.enabled=true', + `--xpack.actions.preconfigured=${JSON.stringify([ + { + id: 'my-slack1', + actionTypeId: '.slack', + name: 'Slack#xyz', + config: { + webhookUrl: 'https://hooks.slack.com/services/abcd/efgh/ijklmnopqrstuvwxyz', + }, + }, + ])}`, ], }, };