From 84ecea0ab7204c5c6eedbaf99a1e8fb5b28f5379 Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Thu, 10 Sep 2020 11:07:31 +0100 Subject: [PATCH 01/15] extract delete operation into its own component --- .../components/actions_connectors_list.tsx | 103 ++++++++++-------- 1 file changed, 57 insertions(+), 46 deletions(-) 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 837529bfc938d1..65db82dc014eb7 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 @@ -194,55 +194,15 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { truncateText: true, }, { - field: 'isPreconfigured', name: '', - render: (value: number, item: ActionConnectorTableItem) => { - if (item.isPreconfigured) { - return ( - - - - - - ); - } + render: (item: ActionConnectorTableItem) => { return ( - - - setConnectorsToDelete([item.id])} - iconType={'trash'} - /> - - + setConnectorsToDelete([item.id])} + /> ); }, @@ -442,3 +402,54 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { function getActionsCountByActionType(actions: ActionConnector[], actionTypeId: string) { return actions.filter((action) => action.actionTypeId === actionTypeId).length; } + +const DeleteOperation: React.FunctionComponent<{ + item: ActionConnectorTableItem; + canDelete: boolean; + onDelete: () => void; +}> = ({ item, canDelete, onDelete }) => { + if (item.isPreconfigured) { + return ( + + + + ); + } + return ( + + + + + + ); +}; From bc8d4414924c9feb9a291c5a798082c6d9b95ef2 Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Thu, 10 Sep 2020 11:17:06 +0100 Subject: [PATCH 02/15] extracted no permissions component --- .../components/actions_connectors_list.tsx | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) 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 65db82dc014eb7..352c9a67bbee2a 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 @@ -304,28 +304,6 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { /> ); - const noPermissionPrompt = ( - - - - } - body={ -

- -

- } - /> - ); - return (
{ {data.length === 0 && canSave && !isLoadingActions && !isLoadingActionTypes && ( setAddFlyoutVisibility(true)} /> )} - {data.length === 0 && !canSave && noPermissionPrompt} + {data.length === 0 && !canSave && } ); }; + +const NoPermissionPrompt: React.FunctionComponent<{}> = () => ( + + + + } + body={ +

+ +

+ } + /> +); From b1f327b7bb4261d789327a7efdf82062ae8b401c Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Mon, 14 Sep 2020 16:49:13 +0100 Subject: [PATCH 03/15] added test connector tab --- x-pack/plugins/actions/common/types.ts | 10 + .../builtin_action_types/es_index.test.ts | 43 ++++ .../server/builtin_action_types/es_index.ts | 18 +- .../plugins/actions/server/routes/execute.ts | 3 +- x-pack/plugins/actions/server/types.ts | 12 +- .../components/add_message_variables.tsx | 1 + .../lib/action_connector_api.test.ts | 30 +++ .../application/lib/action_connector_api.ts | 15 ++ .../connector_edit_flyout.test.tsx | 2 +- .../connector_edit_flyout.tsx | 221 +++++++++++----- .../test_connector_form.test.tsx | 212 ++++++++++++++++ .../test_connector_form.tsx | 235 ++++++++++++++++++ .../apps/triggers_actions_ui/connectors.ts | 26 ++ 13 files changed, 747 insertions(+), 81 deletions(-) create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.test.tsx create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx diff --git a/x-pack/plugins/actions/common/types.ts b/x-pack/plugins/actions/common/types.ts index 49e8f3e80b14a0..41ec4d2a88e9f4 100644 --- a/x-pack/plugins/actions/common/types.ts +++ b/x-pack/plugins/actions/common/types.ts @@ -24,3 +24,13 @@ export interface ActionResult { config: Record; isPreconfigured: boolean; } + +// the result returned from an action type executor function +export interface ActionTypeExecutorResult { + actionId: string; + status: 'ok' | 'error'; + message?: string; + serviceMessage?: string; + data?: Data; + retry?: null | boolean | Date; +} diff --git a/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts b/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts index 7a0e24521a1c6e..3d92d5ebf33fc2 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts @@ -284,4 +284,47 @@ describe('execute()', () => { ] `); }); + + test('resolves with an error when an error occurs in the indexing operation', async () => { + const secrets = {}; + // minimal params + const config = { index: 'index-value', refresh: false, executionTimeField: null }; + const params = { + documents: [{ '': 'bob' }], + }; + + const actionId = 'some-id'; + + services.callCluster.mockResolvedValue({ + took: 0, + errors: true, + items: [ + { + index: { + _index: 'indexme', + _id: '7buTjHQB0SuNSiS9Hayt', + status: 400, + error: { + type: 'mapper_parsing_exception', + reason: 'failed to parse', + caused_by: { + type: 'illegal_argument_exception', + reason: 'field name cannot be an empty string', + }, + }, + }, + }, + ], + }); + + expect(await actionType.executor({ actionId, config, secrets, params, services })) + .toMatchInlineSnapshot(` + Object { + "actionId": "some-id", + "message": "error indexing documents", + "serviceMessage": "failed to parse (field name cannot be an empty string)", + "status": "error", + } + `); + }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/es_index.ts b/x-pack/plugins/actions/server/builtin_action_types/es_index.ts index 53bf75651b1e5b..e652f82c280095 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/es_index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/es_index.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { curry } from 'lodash'; +import { curry, find } from 'lodash'; import { i18n } from '@kbn/i18n'; import { schema, TypeOf } from '@kbn/config-schema'; @@ -85,9 +85,19 @@ async function executor( refresh: config.refresh, }; - let result; try { - result = await services.callCluster('bulk', bulkParams); + const result = await services.callCluster('bulk', bulkParams); + + const err = find(result.items, 'index.error.reason'); + if (err) { + throw new Error( + `${err.index.error!.reason}${ + err.index.error?.caused_by ? ` (${err.index.error?.caused_by?.reason})` : '' + }` + ); + } + + return { status: 'ok', data: result, actionId }; } catch (err) { const message = i18n.translate('xpack.actions.builtin.esIndex.errorIndexingErrorMessage', { defaultMessage: 'error indexing documents', @@ -100,6 +110,4 @@ async function executor( serviceMessage: err.message, }; } - - return { status: 'ok', data: result, actionId }; } diff --git a/x-pack/plugins/actions/server/routes/execute.ts b/x-pack/plugins/actions/server/routes/execute.ts index f15a117106210a..e89a6f5d7debec 100644 --- a/x-pack/plugins/actions/server/routes/execute.ts +++ b/x-pack/plugins/actions/server/routes/execute.ts @@ -13,8 +13,7 @@ import { } from 'kibana/server'; import { ILicenseState, verifyApiAccess, isErrorThatHandlesItsOwnResponse } from '../lib'; -import { ActionTypeExecutorResult } from '../types'; -import { BASE_ACTION_API_PATH } from '../../common'; +import { BASE_ACTION_API_PATH, ActionTypeExecutorResult } from '../../common'; const paramSchema = schema.object({ id: schema.string(), diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index 3e92ca331bb93e..a23a2b08932613 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -15,6 +15,8 @@ import { SavedObjectsClientContract, SavedObjectAttributes, } from '../../../../src/core/server'; +import { ActionTypeExecutorResult } from '../common'; +export { ActionTypeExecutorResult } from '../common'; export type WithoutQueryAndParams = Pick>; export type GetServicesFunction = (request: KibanaRequest) => Services; @@ -80,16 +82,6 @@ export interface FindActionResult extends ActionResult { referencedByCount: number; } -// the result returned from an action type executor function -export interface ActionTypeExecutorResult { - actionId: string; - status: 'ok' | 'error'; - message?: string; - serviceMessage?: string; - data?: Data; - retry?: null | boolean | Date; -} - // signature of the action type executor function export type ExecutorType = ( options: ActionTypeExecutorOptions 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 0742ed8a778efb..2bcd87830901b3 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 @@ -61,6 +61,7 @@ export const AddMessageVariables: React.FunctionComponent = ({ setIsVariablesPopoverOpen(true)} iconType="indexOpen" diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api.test.ts index 43b22361aea36f..ad3a5b40bd00de 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api.test.ts @@ -12,6 +12,7 @@ import { loadActionTypes, loadAllActions, updateActionConnector, + executeAction, } from './action_connector_api'; const http = httpServiceMock.createStartContract(); @@ -128,3 +129,32 @@ describe('deleteActions', () => { `); }); }); + +describe('executeAction', () => { + test('should call execute API', async () => { + const id = '123'; + const params = { + stringParams: 'someString', + numericParams: 123, + }; + + http.post.mockResolvedValueOnce({ + actionId: id, + status: 'ok', + }); + + const result = await executeAction({ id, http, params }); + expect(result).toEqual({ + actionId: id, + status: 'ok', + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/actions/action/123/_execute", + Object { + "body": "{\\"params\\":{\\"stringParams\\":\\"someString\\",\\"numericParams\\":123}}", + }, + ] + `); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api.ts index 46a676ac06539e..c2c7139d13bf0f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api.ts @@ -7,6 +7,7 @@ import { HttpSetup } from 'kibana/public'; import { BASE_ACTION_API_PATH } from '../constants'; import { ActionConnector, ActionConnectorWithoutId, ActionType } from '../../types'; +import { ActionTypeExecutorResult } from '../../../../../plugins/actions/common'; export async function loadActionTypes({ http }: { http: HttpSetup }): Promise { return await http.get(`${BASE_ACTION_API_PATH}/list_action_types`); @@ -65,3 +66,17 @@ export async function deleteActions({ ); return { successes, errors }; } + +export async function executeAction({ + id, + params, + http, +}: { + id: string; + http: HttpSetup; + params: Record; +}): Promise> { + return await http.post(`${BASE_ACTION_API_PATH}/action/${id}/_execute`, { + body: JSON.stringify({ params }), + }); +} 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 dd9eeae2669874..0c2f4df0ca52b1 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 @@ -152,6 +152,6 @@ describe('connector_edit_flyout', () => { const preconfiguredBadge = wrapper.find('[data-test-subj="preconfiguredBadge"]'); expect(preconfiguredBadge.exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="saveEditedActionButton"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test-subj="saveAndCloseEditedActionButton"]').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 ca75e730062ab2..0a2c4fb8c9d0b7 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 @@ -19,15 +19,21 @@ import { EuiBetaBadge, EuiText, EuiLink, + EuiTabs, + EuiSpacer, + EuiTab, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { Option, none, some } from 'fp-ts/lib/Option'; import { ActionConnectorForm, validateBaseProperties } from './action_connector_form'; +import { TestConnectorForm } from './test_connector_form'; import { ActionConnectorTableItem, ActionConnector, IErrorObject } from '../../../types'; import { connectorReducer } from './connector_reducer'; -import { updateActionConnector } from '../../lib/action_connector_api'; +import { updateActionConnector, executeAction } from '../../lib/action_connector_api'; import { hasSaveActionsCapability } from '../../lib/capabilities'; import { useActionsConnectorsContext } from '../../context/actions_connectors_context'; import { PLUGIN } from '../../constants/plugin'; +import { ActionTypeExecutorResult } from '../../../../../actions/common'; export interface ConnectorEditProps { initialConnector: ActionConnectorTableItem; @@ -40,7 +46,6 @@ export const ConnectorEditFlyout = ({ editFlyoutVisible, setEditFlyoutVisibility, }: ConnectorEditProps) => { - let hasErrors = false; const { http, toastNotifications, @@ -56,10 +61,21 @@ export const ConnectorEditFlyout = ({ connector: { ...initialConnector, secrets: {} }, }); const [isSaving, setIsSaving] = useState(false); + const [selectedTab, setTab] = useState<'config' | 'test'>('config'); + + const [hasChanges, setHasChanges] = useState(false); const setConnector = (key: string, value: any) => { dispatch({ command: { type: 'setConnector' }, payload: { key, value } }); }; + const [testExecutionActionParams, setTestExecutionActionParams] = useState< + Record + >({}); + const [testExecutionResult, setTestExecutionResult] = useState< + Option> + >(none); + const [isExecutingAction, setIsExecutinAction] = useState(false); + const closeFlyout = useCallback(() => { setEditFlyoutVisibility(false); setConnector('connector', { ...initialConnector, secrets: {} }); @@ -71,11 +87,13 @@ export const ConnectorEditFlyout = ({ } const actionTypeModel = actionTypeRegistry.get(connector.actionTypeId); - const errors = { + const errorsInConnectorConfig = { ...actionTypeModel?.validateConnector(connector).errors, ...validateBaseProperties(connector).errors, } as IErrorObject; - hasErrors = !!Object.keys(errors).find((errorKey) => errors[errorKey].length >= 1); + const hasErrorsInConnectorConfig = !!Object.keys(errorsInConnectorConfig).find( + (errorKey) => errorsInConnectorConfig[errorKey].length >= 1 + ); const onActionConnectorSave = async (): Promise => await updateActionConnector({ http, connector, id: connector.id }) @@ -173,6 +191,32 @@ export const ConnectorEditFlyout = ({ ); + const onExecutAction = () => { + setIsExecutinAction(true); + return executeAction({ id: connector.id, params: testExecutionActionParams, http }).then( + (result) => { + setIsExecutinAction(false); + setTestExecutionResult(some(result)); + return result; + } + ); + }; + + const onSaveClicked = async (closeAfterSave: boolean = true) => { + setIsSaving(true); + const savedAction = await onActionConnectorSave(); + setIsSaving(false); + if (savedAction) { + setHasChanges(false); + if (closeAfterSave) { + closeFlyout(); + } + if (reloadConnectors) { + reloadConnectors(); + } + } + }; + return ( @@ -186,38 +230,74 @@ export const ConnectorEditFlyout = ({ - {!connector.isPreconfigured ? ( - + setTab('config')} + data-test-subj="configureConnectorTab" + isSelected={'config' === selectedTab} + > + {i18n.translate('xpack.triggersActionsUI.sections.editConnectorForm.tabText', { + defaultMessage: 'configuration', + })} + + setTab('test')} + data-test-subj="testConnectorTab" + isSelected={'test' === selectedTab} + > + {i18n.translate('xpack.triggersActionsUI.sections.testConnectorForm.tabText', { + defaultMessage: 'test', + })} + + + + {selectedTab === 'config' ? ( + !connector.isPreconfigured ? ( + { + setHasChanges(true); + dispatch(changes); + }} + actionTypeRegistry={actionTypeRegistry} + http={http} + docLinks={docLinks} + capabilities={capabilities} + consumer={consumer} + /> + ) : ( + + + {i18n.translate( + 'xpack.triggersActionsUI.sections.editConnectorForm.descriptionText', + { + defaultMessage: 'This connector is readonly.', + } + )} + + + + + + ) + ) : ( + - ) : ( - - - {i18n.translate( - 'xpack.triggersActionsUI.sections.editConnectorForm.descriptionText', - { - defaultMessage: 'This connector is readonly.', - } - )} - - - - - )} @@ -232,35 +312,50 @@ export const ConnectorEditFlyout = ({ )} - {canSave && actionTypeModel && !connector.isPreconfigured ? ( - - { - setIsSaving(true); - const savedAction = await onActionConnectorSave(); - setIsSaving(false); - if (savedAction) { - closeFlyout(); - if (reloadConnectors) { - reloadConnectors(); - } - } - }} - > - - - - ) : null} + + + {canSave && actionTypeModel && !connector.isPreconfigured ? ( + + + { + await onSaveClicked(false); + }} + > + + + + + { + await onSaveClicked(); + }} + > + + + + + ) : null} + + diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.test.tsx new file mode 100644 index 00000000000000..482bccb5517f1b --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.test.tsx @@ -0,0 +1,212 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { lazy } from 'react'; +import { I18nProvider } from '@kbn/i18n/react'; +import { coreMock } from '../../../../../../../src/core/public/mocks'; +import TestConnectorForm from './test_connector_form'; +import { none, some } from 'fp-ts/lib/Option'; +import { ActionConnector, ValidationResult } from '../../../types'; +import { actionTypeRegistryMock } from '../../action_type_registry.mock'; +import { ActionsConnectorsContextProvider } from '../../context/actions_connectors_context'; +import { EuiFormRow, EuiFieldText, EuiText, EuiLink, EuiForm, EuiSelect } from '@elastic/eui'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; + +const mockedActionParamsFields = lazy(async () => ({ + default() { + return ( + + + + + + + Link to some help + + } + > + + + + ); + }, +})); + +const actionType = { + id: 'my-action-type', + iconClass: 'test', + selectMessage: 'test', + validateConnector: (): ValidationResult => { + return { errors: {} }; + }, + validateParams: (): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, + actionConnectorFields: null, + actionParamsFields: mockedActionParamsFields, +}; + +describe('test_connector_form', () => { + let deps: any; + let actionTypeRegistry; + beforeAll(async () => { + actionTypeRegistry = actionTypeRegistryMock.create(); + + const mocks = coreMock.createSetup(); + const [ + { + application: { capabilities }, + }, + ] = await mocks.getStartServices(); + deps = { + http: mocks.http, + toastNotifications: mocks.notifications.toasts, + docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' }, + actionTypeRegistry, + capabilities, + }; + actionTypeRegistry.get.mockReturnValue(actionType); + }); + + it('renders initially as the action form and execute button and no result', async () => { + const connector = { + actionTypeId: actionType.id, + config: {}, + secrets: {}, + } as ActionConnector; + const wrapper = mountWithIntl( + + { + return new Promise(() => {}); + }, + docLinks: deps!.docLinks, + }} + > + {}} + isExecutingAction={false} + onExecutAction={async () => ({ + actionId: '', + status: 'ok', + })} + executionResult={none} + /> + + + ); + const executeActionButton = wrapper?.find('[data-test-subj="executeActionButton"]'); + expect(executeActionButton?.exists()).toBeTruthy(); + expect(executeActionButton?.first().prop('isDisabled')).toBe(false); + + const result = wrapper?.find('[data-test-subj="executionAwaiting"]'); + expect(result?.exists()).toBeTruthy(); + }); + + it('renders successful results', async () => { + const connector = { + actionTypeId: actionType.id, + config: {}, + secrets: {}, + } as ActionConnector; + const wrapper = mountWithIntl( + + { + return new Promise(() => {}); + }, + docLinks: deps!.docLinks, + }} + > + {}} + isExecutingAction={false} + onExecutAction={async () => ({ + actionId: '', + status: 'ok', + })} + executionResult={some({ + actionId: '', + status: 'ok', + })} + /> + + + ); + const result = wrapper?.find('[data-test-subj="executionSuccessfulResult"]'); + expect(result?.exists()).toBeTruthy(); + }); + + it('renders failure results', async () => { + const connector = { + actionTypeId: actionType.id, + config: {}, + secrets: {}, + } as ActionConnector; + const wrapper = mountWithIntl( + + { + return new Promise(() => {}); + }, + docLinks: deps!.docLinks, + }} + > + {}} + isExecutingAction={false} + onExecutAction={async () => ({ + actionId: '', + status: 'error', + message: 'Error Message', + })} + executionResult={some({ + actionId: '', + status: 'error', + message: 'Error Message', + })} + /> + + + ); + const result = wrapper?.find('[data-test-subj="executionFailureResult"]'); + expect(result?.exists()).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx new file mode 100644 index 00000000000000..8562be64224a9b --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx @@ -0,0 +1,235 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { Suspense } from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiText, + EuiButton, + EuiSteps, + EuiLoadingSpinner, + EuiDescriptionList, + EuiCallOut, +} from '@elastic/eui'; +import { isEmpty } from 'lodash'; +import { Option, map, getOrElse } from 'fp-ts/lib/Option'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { ActionConnector } from '../../../types'; +import { useActionsConnectorsContext } from '../../context/actions_connectors_context'; +import { ActionTypeExecutorResult } from '../../../../../actions/common'; + +export interface ConnectorAddFlyoutProps { + connector: ActionConnector; + executeEnabled: boolean; + isExecutingAction: boolean; + setActionParams: (params: Record) => void; + actionParams: Record; + onExecutAction: () => Promise>; + executionResult: Option>; +} + +export const TestConnectorForm = ({ + connector, + executeEnabled, + executionResult, + actionParams, + setActionParams, + onExecutAction, + isExecutingAction, +}: ConnectorAddFlyoutProps) => { + const { actionTypeRegistry, docLinks } = useActionsConnectorsContext(); + const actionTypeModel = actionTypeRegistry.get(connector.actionTypeId); + const ParamsFieldsComponent = actionTypeModel.actionParamsFields; + + const actionErrors = actionTypeModel?.validateParams(actionParams); + const hasErrors = !!Object.values(actionErrors.errors).find((errors) => errors.length > 0); + + const steps = [ + { + title: 'Fill out an example action', + children: ParamsFieldsComponent ? ( + + + + + + } + > + + setActionParams({ + ...actionParams, + [field]: value, + }) + } + messageVariables={[]} + docLinks={docLinks} + actionConnector={connector} + /> + + ) : ( + +

This Connector does not require any Action Parameter.

+
+ ), + }, + { + title: 'Execute the example action', + children: ( + + + + + + + + + {executeEnabled ? null : ( + + +

+ +

+
+
+ )} +
+ ), + }, + { + title: 'Execution Result', + children: pipe( + executionResult, + map((result) => + result.status === 'ok' ? ( + + ) : ( + + ) + ), + getOrElse(() => ) + ), + }, + ]; + + return ; +}; + +const AwaitingExecution = () => ( + +

+ +

+
+); + +const SuccessfulExecution = () => ( + +

+ +

+
+); +const FailedExecussion = ({ + executionResult: { message, serviceMessage }, +}: { + executionResult: ActionTypeExecutorResult; +}) => { + const items = [ + { + title: i18n.translate( + 'xpack.triggersActionsUI.sections.testConnectorForm.executionFailureDescription', + { + defaultMessage: + 'This action has failed to execute and has resulted in the following message:', + } + ), + description: + message ?? + i18n.translate( + 'xpack.triggersActionsUI.sections.testConnectorForm.executionFailureUnknownReason', + { + defaultMessage: 'Unknown reason', + } + ), + }, + ]; + if (serviceMessage) { + items.push({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.testConnectorForm.executionFailureAdditionalDetails', + { + defaultMessage: 'Some additional details have been provided by the action:', + } + ), + description: serviceMessage, + }); + } + return ( + + + + ); +}; + +// eslint-disable-next-line import/no-default-export +export { TestConnectorForm as default }; 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 86e355988da0b0..e74fcfd94b56e8 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 @@ -17,6 +17,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const testSubjects = getService('testSubjects'); const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); const find = getService('find'); + const retry = getService('retry'); describe('Connectors', function () { before(async () => { @@ -92,6 +93,31 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ]); }); + it('should test a connector', async () => { + const connectorName = generateUniqueKey(); + await createConnector(connectorName); + + await pageObjects.triggersActionsUI.searchConnectors(connectorName); + + const searchResultsBeforeEdit = await pageObjects.triggersActionsUI.getConnectorsList(); + expect(searchResultsBeforeEdit.length).to.eql(1); + + await find.clickByCssSelector('[data-test-subj="connectorsTableCell-name"] button'); + + await find.clickByCssSelector('[data-test-subj="testConnectorTab"]'); + + await testSubjects.setValue('messageTextArea', 'some message'); + + await find.clickByCssSelector('[data-test-subj="executeActionButton"]:not(disabled)'); + + await retry.try(async () => { + const executionFailureResultCallout = await testSubjects.find('executionFailureResult'); + expect(await executionFailureResultCallout.getVisibleText()).to.match( + /error posting slack message/ + ); + }); + }); + it('should reset connector when canceling an edit', async () => { const connectorName = generateUniqueKey(); await createConnector(connectorName); From 181d284bd9342f6263b2620da33edf4f0931b19d Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Mon, 14 Sep 2020 18:24:24 +0100 Subject: [PATCH 04/15] test success case --- .../es_index/es_index_params.tsx | 79 +++++++++---------- .../test_connector_form.tsx | 1 - .../apps/triggers_actions_ui/connectors.ts | 33 +++++++- 3 files changed, 69 insertions(+), 44 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index/es_index_params.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index/es_index_params.tsx index 495707db4975cf..0a04db1b5ddfa2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index/es_index_params.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index/es_index_params.tsx @@ -32,48 +32,47 @@ export const IndexParamsFields = ({ }; return ( - <> - 0 ? ((documents[0] as unknown) as string) : undefined + 0 ? ((documents[0] as unknown) as string) : undefined + } + label={i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.indexAction.documentsFieldLabel', + { + defaultMessage: 'Document to index', } - label={i18n.translate( - 'xpack.triggersActionsUI.components.builtinActionTypes.indexAction.documentsFieldLabel', - { - defaultMessage: 'Document to index', - } - )} - aria-label={i18n.translate( - 'xpack.triggersActionsUI.components.builtinActionTypes.indexAction.jsonDocAriaLabel', - { - defaultMessage: 'Code editor', - } - )} - errors={errors.documents as string[]} - onDocumentsChange={onDocumentsChange} - helpText={ - - - + )} + aria-label={i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.indexAction.jsonDocAriaLabel', + { + defaultMessage: 'Code editor', } - onBlur={() => { - if ( - !(documents && documents.length > 0 ? ((documents[0] as unknown) as string) : undefined) - ) { - // set document as empty to turn on the validation for non empty valid JSON object - onDocumentsChange('{}'); - } - }} - /> - + )} + errors={errors.documents as string[]} + onDocumentsChange={onDocumentsChange} + helpText={ + + + + } + onBlur={() => { + if ( + !(documents && documents.length > 0 ? ((documents[0] as unknown) as string) : undefined) + ) { + // set document as empty to turn on the validation for non empty valid JSON object + onDocumentsChange('{}'); + } + }} + /> ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx index 8562be64224a9b..abe5824553563b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx @@ -14,7 +14,6 @@ import { EuiDescriptionList, EuiCallOut, } from '@elastic/eui'; -import { isEmpty } from 'lodash'; import { Option, map, getOrElse } from 'fp-ts/lib/Option'; import { pipe } from 'fp-ts/lib/pipeable'; import { FormattedMessage } from '@kbn/i18n/react'; 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 e74fcfd94b56e8..0d82886460a1ff 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 @@ -18,6 +18,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); const find = getService('find'); const retry = getService('retry'); + const comboBox = getService('comboBox'); describe('Connectors', function () { before(async () => { @@ -95,7 +96,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should test a connector', async () => { const connectorName = generateUniqueKey(); - await createConnector(connectorName); + const indexName = generateUniqueKey(); + await createIndexConnector(connectorName, indexName); await pageObjects.triggersActionsUI.searchConnectors(connectorName); @@ -106,14 +108,26 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await find.clickByCssSelector('[data-test-subj="testConnectorTab"]'); - await testSubjects.setValue('messageTextArea', 'some message'); + // test success + await testSubjects.setValue('documentsJsonEditor', '{ "key": "value" }'); + + await find.clickByCssSelector('[data-test-subj="executeActionButton"]:not(disabled)'); + + await retry.try(async () => { + await testSubjects.find('executionSuccessfulResult'); + }); + + // test failure + await testSubjects.setValue('documentsJsonEditor', '{ "": "value" }', { + clearWithKeyboard: true, + }); await find.clickByCssSelector('[data-test-subj="executeActionButton"]:not(disabled)'); await retry.try(async () => { const executionFailureResultCallout = await testSubjects.find('executionFailureResult'); expect(await executionFailureResultCallout.getVisibleText()).to.match( - /error posting slack message/ + /error indexing documents/ ); }); }); @@ -235,4 +249,17 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await find.clickByCssSelector('[data-test-subj="saveNewActionButton"]:not(disabled)'); await pageObjects.common.closeToast(); } + + async function createIndexConnector(connectorName: string, indexName: string) { + await pageObjects.triggersActionsUI.clickCreateConnectorButton(); + + await testSubjects.click('.index-card'); + + await testSubjects.setValue('nameInput', connectorName); + + await comboBox.set('connectorIndexesComboBox', indexName); + + await find.clickByCssSelector('[data-test-subj="saveNewActionButton"]:not(disabled)'); + await pageObjects.common.closeToast(); + } }; From 8ff0457b02c275e08736889701990d771e685192 Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Tue, 15 Sep 2020 09:31:42 +0100 Subject: [PATCH 05/15] fix flaky tests in connector testing --- .../apps/triggers_actions_ui/connectors.ts | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) 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 0d82886460a1ff..151c8376402282 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 @@ -78,7 +78,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.setValue('slackWebhookUrlInput', 'https://test'); - await find.clickByCssSelector('[data-test-subj="saveEditedActionButton"]:not(disabled)'); + await find.clickByCssSelector( + '[data-test-subj="saveAndCloseEditedActionButton"]:not(disabled)' + ); const toastTitle = await pageObjects.common.closeToast(); expect(toastTitle).to.eql(`Updated '${updatedConnectorName}'`); @@ -94,7 +96,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ]); }); - it('should test a connector', async () => { + it('should test a connector and display a successful result', async () => { const connectorName = generateUniqueKey(); const indexName = generateUniqueKey(); await createIndexConnector(connectorName, indexName); @@ -117,10 +119,26 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.find('executionSuccessfulResult'); }); - // test failure - await testSubjects.setValue('documentsJsonEditor', '{ "": "value" }', { - clearWithKeyboard: true, - }); + await find.clickByCssSelector( + '[data-test-subj="cancelSaveEditedConnectorButton"]:not(disabled)' + ); + }); + + it('should test a connector and display a failure result', async () => { + const connectorName = generateUniqueKey(); + const indexName = generateUniqueKey(); + await createIndexConnector(connectorName, indexName); + + await pageObjects.triggersActionsUI.searchConnectors(connectorName); + + const searchResultsBeforeEdit = await pageObjects.triggersActionsUI.getConnectorsList(); + expect(searchResultsBeforeEdit.length).to.eql(1); + + await find.clickByCssSelector('[data-test-subj="connectorsTableCell-name"] button'); + + await find.clickByCssSelector('[data-test-subj="testConnectorTab"]'); + + await testSubjects.setValue('documentsJsonEditor', '{ "": "value" }'); await find.clickByCssSelector('[data-test-subj="executeActionButton"]:not(disabled)'); @@ -130,6 +148,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { /error indexing documents/ ); }); + + await find.clickByCssSelector( + '[data-test-subj="cancelSaveEditedConnectorButton"]:not(disabled)' + ); }); it('should reset connector when canceling an edit', async () => { @@ -233,7 +255,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { 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); + expect(await testSubjects.exists('saveAndCloseEditedActionButton')).to.be(false); }); }); From 4f8f113b044a1957f280bc0c9f79ae9b4454ea5c Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Tue, 15 Sep 2020 12:42:47 +0100 Subject: [PATCH 06/15] forget execution runs when flyotu is closed --- .../sections/action_connector_form/connector_edit_flyout.tsx | 5 +++++ 1 file changed, 5 insertions(+) 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 0a2c4fb8c9d0b7..90500e7722d434 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 @@ -79,6 +79,8 @@ export const ConnectorEditFlyout = ({ const closeFlyout = useCallback(() => { setEditFlyoutVisibility(false); setConnector('connector', { ...initialConnector, secrets: {} }); + hasChanges(false); + setTestExecutionResult(none); // eslint-disable-next-line react-hooks/exhaustive-deps }, [setEditFlyoutVisibility]); @@ -259,6 +261,9 @@ export const ConnectorEditFlyout = ({ actionTypeName={connector.actionType} dispatch={(changes) => { setHasChanges(true); + // if the user changes the connector, "forget" the last execution + // so the user comes back to a clean form ready to run a fresh test + setTestExecutionResult(none); dispatch(changes); }} actionTypeRegistry={actionTypeRegistry} From 21a37b640377cea3ee1b7d62f202114a97accee4 Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Tue, 15 Sep 2020 14:37:20 +0100 Subject: [PATCH 07/15] corrected setting of setHasChanges --- .../sections/action_connector_form/connector_edit_flyout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 90500e7722d434..4235028d4906bc 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 @@ -79,7 +79,7 @@ export const ConnectorEditFlyout = ({ const closeFlyout = useCallback(() => { setEditFlyoutVisibility(false); setConnector('connector', { ...initialConnector, secrets: {} }); - hasChanges(false); + setHasChanges(false); setTestExecutionResult(none); // eslint-disable-next-line react-hooks/exhaustive-deps }, [setEditFlyoutVisibility]); From acfa049b5f47f88720475ec844414ae2a87534dd Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Tue, 15 Sep 2020 17:54:52 +0100 Subject: [PATCH 08/15] design changes --- .../connector_edit_flyout.scss | 3 ++ .../connector_edit_flyout.tsx | 15 +++--- .../test_connector_form.tsx | 48 +++++++++---------- 3 files changed, 33 insertions(+), 33 deletions(-) create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.scss diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.scss b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.scss new file mode 100644 index 00000000000000..873a3ceb762cdf --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.scss @@ -0,0 +1,3 @@ +.connectorEditFlyoutTabs { + margin-bottom: '-25px'; +} 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 4235028d4906bc..fc902a4fabcd84 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 @@ -20,7 +20,6 @@ import { EuiText, EuiLink, EuiTabs, - EuiSpacer, EuiTab, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -34,6 +33,7 @@ import { hasSaveActionsCapability } from '../../lib/capabilities'; import { useActionsConnectorsContext } from '../../context/actions_connectors_context'; import { PLUGIN } from '../../constants/plugin'; import { ActionTypeExecutorResult } from '../../../../../actions/common'; +import './connector_edit_flyout.scss'; export interface ConnectorEditProps { initialConnector: ActionConnectorTableItem; @@ -230,16 +230,14 @@ export const ConnectorEditFlyout = ({ ) : null} {flyoutTitle} - - - + setTab('config')} data-test-subj="configureConnectorTab" isSelected={'config' === selectedTab} > {i18n.translate('xpack.triggersActionsUI.sections.editConnectorForm.tabText', { - defaultMessage: 'configuration', + defaultMessage: 'Configuration', })} {i18n.translate('xpack.triggersActionsUI.sections.testConnectorForm.tabText', { - defaultMessage: 'test', + defaultMessage: 'Test', })} - + + {selectedTab === 'config' ? ( !connector.isPreconfigured ? ( { @@ -344,7 +342,6 @@ export const ConnectorEditFlyout = ({ color="secondary" data-test-subj="saveAndCloseEditedActionButton" type="submit" - iconType="check" isDisabled={hasErrorsInConnectorConfig || !hasChanges} isLoading={isSaving || isExecutingAction} onClick={async () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx index abe5824553563b..07c764a83b8d8a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.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, { Suspense } from 'react'; +import React, { Fragment, Suspense } from 'react'; import { EuiFlexGroup, EuiFlexItem, @@ -13,6 +13,7 @@ import { EuiLoadingSpinner, EuiDescriptionList, EuiCallOut, + EuiSpacer, } from '@elastic/eui'; import { Option, map, getOrElse } from 'fp-ts/lib/Option'; import { pipe } from 'fp-ts/lib/pipeable'; @@ -85,26 +86,10 @@ export const TestConnectorForm = ({ { title: 'Execute the example action', children: ( - - - - - - - - + {executeEnabled ? null : ( - - + +

-
+ +
)} -
+ + + + + + ), }, { @@ -146,7 +146,7 @@ const AwaitingExecution = () => ( } )} data-test-subj="executionAwaiting" - iconType="search" + iconType="iInCircle" >

( )} color="success" data-test-subj="executionSuccessfulResult" - iconType="play" + iconType="check" >

Date: Wed, 16 Sep 2020 13:53:26 +0100 Subject: [PATCH 09/15] updated copy --- .../server/builtin_action_types/es_index.ts | 34 +++++++++++------- .../test_connector_form.tsx | 36 +++++++------------ 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/x-pack/plugins/actions/server/builtin_action_types/es_index.ts b/x-pack/plugins/actions/server/builtin_action_types/es_index.ts index e652f82c280095..868c07b775c78f 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/es_index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/es_index.ts @@ -90,24 +90,34 @@ async function executor( const err = find(result.items, 'index.error.reason'); if (err) { - throw new Error( + return wrapErr( `${err.index.error!.reason}${ err.index.error?.caused_by ? ` (${err.index.error?.caused_by?.reason})` : '' - }` + }`, + actionId, + logger ); } return { status: 'ok', data: result, actionId }; } catch (err) { - const message = i18n.translate('xpack.actions.builtin.esIndex.errorIndexingErrorMessage', { - defaultMessage: 'error indexing documents', - }); - logger.error(`error indexing documents: ${err.message}`); - return { - status: 'error', - actionId, - message, - serviceMessage: err.message, - }; + return wrapErr(err.message, actionId, logger); } } + +function wrapErr( + errMessage: string, + actionId: string, + logger: Logger +): ActionTypeExecutorResult { + const message = i18n.translate('xpack.actions.builtin.esIndex.errorIndexingErrorMessage', { + defaultMessage: 'error indexing documents', + }); + logger.error(`error indexing documents: ${errMessage}`); + return { + status: 'error', + actionId, + message, + serviceMessage: errMessage, + }; +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx index 07c764a83b8d8a..a73fd4e22e6371 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx @@ -51,7 +51,7 @@ export const TestConnectorForm = ({ const steps = [ { - title: 'Fill out an example action', + title: 'Create an action', children: ParamsFieldsComponent ? ( {executeEnabled ? null : ( @@ -92,7 +92,7 @@ export const TestConnectorForm = ({

@@ -109,7 +109,7 @@ export const TestConnectorForm = ({ onClick={onExecutAction} > @@ -118,7 +118,7 @@ export const TestConnectorForm = ({ ), }, { - title: 'Execution Result', + title: 'Results', children: pipe( executionResult, map((result) => @@ -137,20 +137,10 @@ export const TestConnectorForm = ({ }; const AwaitingExecution = () => ( - +

@@ -162,7 +152,7 @@ const SuccessfulExecution = () => ( title={i18n.translate( 'xpack.triggersActionsUI.sections.testConnectorForm.executionSuccessfulTitle', { - defaultMessage: 'Success', + defaultMessage: 'Action was successful', values: {}, } )} @@ -172,12 +162,13 @@ const SuccessfulExecution = () => ( >

); + const FailedExecussion = ({ executionResult: { message, serviceMessage }, }: { @@ -188,8 +179,7 @@ const FailedExecussion = ({ title: i18n.translate( 'xpack.triggersActionsUI.sections.testConnectorForm.executionFailureDescription', { - defaultMessage: - 'This action has failed to execute and has resulted in the following message:', + defaultMessage: 'The following error was found:', } ), description: @@ -207,7 +197,7 @@ const FailedExecussion = ({ title: i18n.translate( 'xpack.triggersActionsUI.sections.testConnectorForm.executionFailureAdditionalDetails', { - defaultMessage: 'Some additional details have been provided by the action:', + defaultMessage: 'Details:', } ), description: serviceMessage, @@ -218,7 +208,7 @@ const FailedExecussion = ({ title={i18n.translate( 'xpack.triggersActionsUI.sections.testConnectorForm.executionFailureTitle', { - defaultMessage: 'Error', + defaultMessage: 'Action failed to run', } )} data-test-subj="executionFailureResult" From e86c660ca82bff8b6c104e56bdc09e045f6850d9 Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Wed, 16 Sep 2020 18:46:54 +0100 Subject: [PATCH 10/15] added Run button in connector list and Save & test button in creation --- .../context/actions_connectors_context.tsx | 4 +- .../connector_add_flyout.tsx | 88 +++++++---- .../connector_edit_flyout.scss | 2 +- .../connector_edit_flyout.tsx | 23 ++- .../components/actions_connectors_list.tsx | 137 ++++++++++++------ 5 files changed, 168 insertions(+), 86 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/context/actions_connectors_context.tsx b/x-pack/plugins/triggers_actions_ui/public/application/context/actions_connectors_context.tsx index d78930344a6736..ffda3e618ea7e9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/context/actions_connectors_context.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/context/actions_connectors_context.tsx @@ -6,7 +6,7 @@ import React, { createContext, useContext } from 'react'; import { HttpSetup, ToastsApi, ApplicationStart, DocLinksStart } from 'kibana/public'; -import { ActionTypeModel } from '../../types'; +import { ActionTypeModel, ActionConnector } from '../../types'; import { TypeRegistry } from '../type_registry'; export interface ActionsConnectorsContextValue { @@ -17,7 +17,7 @@ export interface ActionsConnectorsContextValue { 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' >; capabilities: ApplicationStart['capabilities']; - reloadConnectors?: () => Promise; + reloadConnectors?: () => Promise; docLinks: DocLinksStart; consumer?: string; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_flyout.tsx index 19ce653e465f10..73174d57fd583c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -37,12 +37,14 @@ export interface ConnectorAddFlyoutProps { addFlyoutVisible: boolean; setAddFlyoutVisibility: React.Dispatch>; actionTypes?: ActionType[]; + onTestConnector: (connector: ActionConnector) => void; } export const ConnectorAddFlyout = ({ addFlyoutVisible, setAddFlyoutVisibility, actionTypes, + onTestConnector, }: ConnectorAddFlyoutProps) => { let hasErrors = false; const { @@ -153,6 +155,19 @@ export const ConnectorAddFlyout = ({ return undefined; }); + const onSaveClicked = async () => { + setIsSaving(true); + const savedAction = await onActionConnectorSave(); + setIsSaving(false); + if (savedAction) { + closeFlyout(); + if (reloadConnectors) { + await reloadConnectors(); + } + } + return savedAction; + }; + return ( @@ -245,35 +260,50 @@ export const ConnectorAddFlyout = ({ )} - {canSave && actionTypeModel && actionType ? ( - - { - setIsSaving(true); - const savedAction = await onActionConnectorSave(); - setIsSaving(false); - if (savedAction) { - closeFlyout(); - if (reloadConnectors) { - reloadConnectors(); - } - } - }} - > - - - - ) : null} + + + {canSave && actionTypeModel && actionType ? ( + + + { + const savedConnector = await onSaveClicked(); + if (savedConnector) { + onTestConnector(savedConnector); + } + }} + > + + + + + + + + + + ) : null} + + diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.scss b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.scss index 873a3ceb762cdf..b9144a070c613c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.scss +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.scss @@ -1,3 +1,3 @@ .connectorEditFlyoutTabs { - margin-bottom: '-25px'; + margin-bottom: -25px; } 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 fc902a4fabcd84..7b985ab85cd4ee 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 @@ -26,7 +26,7 @@ import { i18n } from '@kbn/i18n'; import { Option, none, some } from 'fp-ts/lib/Option'; import { ActionConnectorForm, validateBaseProperties } from './action_connector_form'; import { TestConnectorForm } from './test_connector_form'; -import { ActionConnectorTableItem, ActionConnector, IErrorObject } from '../../../types'; +import { ActionConnector, IErrorObject } from '../../../types'; import { connectorReducer } from './connector_reducer'; import { updateActionConnector, executeAction } from '../../lib/action_connector_api'; import { hasSaveActionsCapability } from '../../lib/capabilities'; @@ -36,15 +36,22 @@ import { ActionTypeExecutorResult } from '../../../../../actions/common'; import './connector_edit_flyout.scss'; export interface ConnectorEditProps { - initialConnector: ActionConnectorTableItem; + initialConnector: ActionConnector; editFlyoutVisible: boolean; setEditFlyoutVisibility: React.Dispatch>; + tab?: EditConectorTabs; +} + +export enum EditConectorTabs { + Configuration = 'configuration', + Test = 'test', } export const ConnectorEditFlyout = ({ initialConnector, editFlyoutVisible, setEditFlyoutVisibility, + tab = EditConectorTabs.Configuration, }: ConnectorEditProps) => { const { http, @@ -61,7 +68,7 @@ export const ConnectorEditFlyout = ({ connector: { ...initialConnector, secrets: {} }, }); const [isSaving, setIsSaving] = useState(false); - const [selectedTab, setTab] = useState<'config' | 'test'>('config'); + const [selectedTab, setTab] = useState(tab); const [hasChanges, setHasChanges] = useState(false); const setConnector = (key: string, value: any) => { @@ -232,18 +239,18 @@ export const ConnectorEditFlyout = ({ setTab('config')} + onClick={() => setTab(EditConectorTabs.Configuration)} data-test-subj="configureConnectorTab" - isSelected={'config' === selectedTab} + isSelected={EditConectorTabs.Configuration === selectedTab} > {i18n.translate('xpack.triggersActionsUI.sections.editConnectorForm.tabText', { defaultMessage: 'Configuration', })} setTab('test')} + onClick={() => setTab(EditConectorTabs.Test)} data-test-subj="testConnectorTab" - isSelected={'test' === selectedTab} + isSelected={EditConectorTabs.Test === selectedTab} > {i18n.translate('xpack.triggersActionsUI.sections.testConnectorForm.tabText', { defaultMessage: 'Test', @@ -252,7 +259,7 @@ export const ConnectorEditFlyout = ({ - {selectedTab === 'config' ? ( + {selectedTab === EditConectorTabs.Configuration ? ( !connector.isPreconfigured ? ( { docLinks, } = useAppDependencies(); const canDelete = hasDeleteActionsCapability(capabilities); + const canExecute = hasExecuteActionsCapability(capabilities); const canSave = hasSaveActionsCapability(capabilities); const [actionTypesIndex, setActionTypesIndex] = useState(undefined); const [actions, setActions] = useState([]); - const [data, setData] = useState([]); const [selectedItems, setSelectedItems] = useState([]); const [isLoadingActionTypes, setIsLoadingActionTypes] = useState(false); const [isLoadingActions, setIsLoadingActions] = useState(false); const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false); const [addFlyoutVisible, setAddFlyoutVisibility] = useState(false); - const [actionTypesList, setActionTypesList] = useState>( - [] - ); - const [editedConnectorItem, setEditedConnectorItem] = useState< - ActionConnectorTableItem | undefined - >(undefined); + const [editConnectorProps, setEditConnectorProps] = useState<{ + initialConnector?: ActionConnector; + tab?: EditConectorTabs; + }>({}); const [connectorsToDelete, setConnectorsToDelete] = useState([]); useEffect(() => { @@ -90,30 +93,25 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - useEffect(() => { - // Avoid flickering before action types load - if (typeof actionTypesIndex === 'undefined') { - return; - } - // Update the data for the table - const updatedData = actions.map((action) => { - return { - ...action, - actionType: actionTypesIndex[action.actionTypeId] - ? actionTypesIndex[action.actionTypeId].name - : action.actionTypeId, - }; - }); - setData(updatedData); - // Update the action types list for the filter - const actionTypes = Object.values(actionTypesIndex) - .map((actionType) => ({ - value: actionType.id, - name: `${actionType.name} (${getActionsCountByActionType(actions, actionType.id)})`, - })) - .sort((a, b) => a.name.localeCompare(b.name)); - setActionTypesList(actionTypes); - }, [actions, actionTypesIndex]); + const actionConnectorTableItems: ActionConnectorTableItem[] = actionTypesIndex + ? actions.map((action) => { + return { + ...action, + actionType: actionTypesIndex[action.actionTypeId] + ? actionTypesIndex[action.actionTypeId].name + : action.actionTypeId, + }; + }) + : []; + + const actionTypesList: Array<{ value: string; name: string }> = actionTypesIndex + ? Object.values(actionTypesIndex) + .map((actionType) => ({ + value: actionType.id, + name: `${actionType.name} (${getActionsCountByActionType(actions, actionType.id)})`, + })) + .sort((a, b) => a.name.localeCompare(b.name)) + : []; async function loadActions() { setIsLoadingActions(true); @@ -134,8 +132,8 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { } } - async function editItem(connectorTableItem: ActionConnectorTableItem) { - setEditedConnectorItem(connectorTableItem); + async function editItem(actionConnector: ActionConnector, tab: EditConectorTabs) { + setEditConnectorProps({ initialConnector: actionConnector, tab }); setEditFlyoutVisibility(true); } @@ -159,7 +157,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { const link = ( editItem(item)} + onClick={() => editItem(item, EditConectorTabs.Configuration)} key={item.id} disabled={actionTypesIndex ? !actionTypesIndex[item.actionTypeId].enabled : true} > @@ -203,6 +201,11 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { item={item} onDelete={() => setConnectorsToDelete([item.id])} /> + editItem(item, EditConectorTabs.Test)} + /> ); }, @@ -212,7 +215,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { const table = ( { )} - {data.length !== 0 && table} - {data.length === 0 && canSave && !isLoadingActions && !isLoadingActionTypes && ( - setAddFlyoutVisibility(true)} /> - )} - {data.length === 0 && !canSave && } + {actionConnectorTableItems.length !== 0 && table} + {actionConnectorTableItems.length === 0 && + canSave && + !isLoadingActions && + !isLoadingActionTypes && ( + setAddFlyoutVisibility(true)} /> + )} + {actionConnectorTableItems.length === 0 && !canSave && } { editItem(connector, EditConectorTabs.Test)} /> - {editedConnectorItem ? ( + {editConnectorProps.initialConnector ? ( @@ -432,6 +442,41 @@ const DeleteOperation: React.FunctionComponent<{ ); }; +const RunOperation: React.FunctionComponent<{ + item: ActionConnectorTableItem; + canExecute: boolean; + onRun: () => void; +}> = ({ item, canExecute, onRun }) => { + return ( + + + + + + ); +}; + const NoPermissionPrompt: React.FunctionComponent<{}> = () => ( Date: Tue, 29 Sep 2020 11:38:11 +0100 Subject: [PATCH 11/15] maded onTestConnector callback optional --- .../connector_add_flyout.tsx | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_flyout.tsx index 73174d57fd583c..9bb9d07307e131 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -37,7 +37,7 @@ export interface ConnectorAddFlyoutProps { addFlyoutVisible: boolean; setAddFlyoutVisibility: React.Dispatch>; actionTypes?: ActionType[]; - onTestConnector: (connector: ActionConnector) => void; + onTestConnector?: (connector: ActionConnector) => void; } export const ConnectorAddFlyout = ({ @@ -264,26 +264,28 @@ export const ConnectorAddFlyout = ({ {canSave && actionTypeModel && actionType ? ( - - { - const savedConnector = await onSaveClicked(); - if (savedConnector) { - onTestConnector(savedConnector); - } - }} - > - - - + {onTestConnector && ( + + { + const savedConnector = await onSaveClicked(); + if (savedConnector) { + onTestConnector(savedConnector); + } + }} + > + + + + )} Date: Tue, 29 Sep 2020 12:15:17 +0100 Subject: [PATCH 12/15] use connectors context in jira and resilient --- .../components/builtin_action_types/jira/jira_params.test.tsx | 4 ++-- .../components/builtin_action_types/jira/jira_params.tsx | 4 ++-- .../builtin_action_types/resilient/resilient_params.test.tsx | 4 ++-- .../builtin_action_types/resilient/resilient_params.tsx | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.test.tsx index 26d358310741c5..3146ceee297050 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.test.tsx @@ -11,10 +11,10 @@ import { DocLinksStart } from 'kibana/public'; import { useGetIssueTypes } from './use_get_issue_types'; import { useGetFieldsByIssueType } from './use_get_fields_by_issue_type'; -jest.mock('../../../app_context', () => { +jest.mock('../../../context/actions_connectors_context', () => { const post = jest.fn(); return { - useAppDependencies: jest.fn(() => ({ http: { post } })), + useActionsConnectorsContext: jest.fn(() => ({ http: { post } })), }; }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.tsx index bde3d67ffd65f4..1cadb12d969946 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.tsx @@ -13,7 +13,7 @@ import { EuiFlexGroup } from '@elastic/eui'; import { EuiFlexItem } from '@elastic/eui'; import { EuiSpacer } from '@elastic/eui'; -import { useAppDependencies } from '../../../app_context'; +import { useActionsConnectorsContext } from '../../../context/actions_connectors_context'; import { ActionParamsProps } from '../../../../types'; import { TextAreaWithMessageVariables } from '../../text_area_with_message_variables'; import { TextFieldWithMessageVariables } from '../../text_field_with_message_variables'; @@ -35,7 +35,7 @@ const JiraParamsFields: React.FunctionComponent([]); const [firstLoad, setFirstLoad] = useState(false); const [prioritiesSelectOptions, setPrioritiesSelectOptions] = useState([]); - const { http, toastNotifications } = useAppDependencies(); + const { http, toastNotifications } = useActionsConnectorsContext(); useEffect(() => { setFirstLoad(true); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.test.tsx index 17020805757f9d..e5898b129dee8d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.test.tsx @@ -11,10 +11,10 @@ import { DocLinksStart } from 'kibana/public'; import { useGetIncidentTypes } from './use_get_incident_types'; import { useGetSeverity } from './use_get_severity'; -jest.mock('../../../app_context', () => { +jest.mock('../../../context/actions_connectors_context', () => { const post = jest.fn(); return { - useAppDependencies: jest.fn(() => ({ http: { post } })), + useActionsConnectorsContext: jest.fn(() => ({ http: { post } })), }; }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.tsx index 4b157c69999852..8fd479fc652dd3 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.tsx @@ -17,7 +17,7 @@ import { import { i18n } from '@kbn/i18n'; import { ActionParamsProps } from '../../../../types'; -import { useAppDependencies } from '../../../app_context'; +import { useActionsConnectorsContext } from '../../../context/actions_connectors_context'; import { ResilientActionParams } from './types'; import { TextAreaWithMessageVariables } from '../../text_area_with_message_variables'; import { TextFieldWithMessageVariables } from '../../text_field_with_message_variables'; @@ -34,7 +34,7 @@ const ResilientParamsFields: React.FunctionComponent { const [firstLoad, setFirstLoad] = useState(false); - const { http, toastNotifications } = useAppDependencies(); + const { http, toastNotifications } = useActionsConnectorsContext(); const { title, description, comments, incidentTypes, severityCode, savedObjectId } = actionParams.subActionParams || {}; From 71c85ce940b3e186a37c91805dcee0e877477a2b Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Tue, 29 Sep 2020 12:53:05 +0100 Subject: [PATCH 13/15] removed usage of context in ibm and jira --- .../components/builtin_action_types/jira/jira_params.tsx | 4 ++-- .../builtin_action_types/resilient/resilient_params.tsx | 4 ++-- .../sections/action_connector_form/action_form.tsx | 2 ++ .../sections/action_connector_form/test_connector_form.tsx | 4 +++- x-pack/plugins/triggers_actions_ui/public/types.ts | 2 ++ 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.tsx index 1cadb12d969946..b457dcc60a43f9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.tsx @@ -13,7 +13,6 @@ import { EuiFlexGroup } from '@elastic/eui'; import { EuiFlexItem } from '@elastic/eui'; import { EuiSpacer } from '@elastic/eui'; -import { useActionsConnectorsContext } from '../../../context/actions_connectors_context'; import { ActionParamsProps } from '../../../../types'; import { TextAreaWithMessageVariables } from '../../text_area_with_message_variables'; import { TextFieldWithMessageVariables } from '../../text_field_with_message_variables'; @@ -28,6 +27,8 @@ const JiraParamsFields: React.FunctionComponent { const { title, description, comments, issueType, priority, labels, savedObjectId } = actionParams.subActionParams || {}; @@ -35,7 +36,6 @@ const JiraParamsFields: React.FunctionComponent([]); const [firstLoad, setFirstLoad] = useState(false); const [prioritiesSelectOptions, setPrioritiesSelectOptions] = useState([]); - const { http, toastNotifications } = useActionsConnectorsContext(); useEffect(() => { setFirstLoad(true); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.tsx index 8fd479fc652dd3..b150c97506b693 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.tsx @@ -17,7 +17,6 @@ import { import { i18n } from '@kbn/i18n'; import { ActionParamsProps } from '../../../../types'; -import { useActionsConnectorsContext } from '../../../context/actions_connectors_context'; import { ResilientActionParams } from './types'; import { TextAreaWithMessageVariables } from '../../text_area_with_message_variables'; import { TextFieldWithMessageVariables } from '../../text_field_with_message_variables'; @@ -32,9 +31,10 @@ const ResilientParamsFields: React.FunctionComponent { const [firstLoad, setFirstLoad] = useState(false); - const { http, toastNotifications } = useActionsConnectorsContext(); const { title, description, comments, incidentTypes, severityCode, savedObjectId } = actionParams.subActionParams || {}; 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 ac5b2a2187c2f3..e80fe966a2a74c 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 @@ -311,6 +311,8 @@ export const ActionForm = ({ messageVariables={messageVariables} defaultMessage={defaultActionMessage ?? undefined} docLinks={docLinks} + http={http} + toastNotifications={toastNotifications} actionConnector={actionConnector} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx index a73fd4e22e6371..315254a003e896 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/test_connector_form.tsx @@ -42,7 +42,7 @@ export const TestConnectorForm = ({ onExecutAction, isExecutingAction, }: ConnectorAddFlyoutProps) => { - const { actionTypeRegistry, docLinks } = useActionsConnectorsContext(); + const { actionTypeRegistry, docLinks, http, toastNotifications } = useActionsConnectorsContext(); const actionTypeModel = actionTypeRegistry.get(connector.actionTypeId); const ParamsFieldsComponent = actionTypeModel.actionParamsFields; @@ -74,6 +74,8 @@ export const TestConnectorForm = ({ } messageVariables={[]} docLinks={docLinks} + http={http} + toastNotifications={toastNotifications} actionConnector={connector} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index 56405baa5c65dd..ca552591f23dcb 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -54,6 +54,8 @@ export interface ActionParamsProps { messageVariables?: ActionVariable[]; defaultMessage?: string; docLinks: DocLinksStart; + http?: HttpSetup; + toastNotifications: ToastsSetup; actionConnector?: ActionConnector; } From 2b4f2b42cdb8e79987dce90d31115acfbb4cb62d Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Tue, 29 Sep 2020 14:36:44 +0100 Subject: [PATCH 14/15] fixed deps in connectors --- .../email/email_params.test.tsx | 4 ++++ .../es_index/es_index_params.test.tsx | 4 ++++ .../jira/jira_params.test.tsx | 22 +++++++++++++------ .../pagerduty/pagerduty_params.test.tsx | 4 ++++ .../resilient/resilient_params.test.tsx | 18 ++++++++++----- .../server_log/server_log_params.test.tsx | 7 ++++++ .../servicenow/servicenow_params.test.tsx | 4 ++++ .../slack/slack_params.test.tsx | 4 ++++ .../webhook/webhook_params.test.tsx | 4 ++++ .../context/actions_connectors_context.tsx | 7 ++---- .../action_connector_form/action_form.tsx | 7 ++---- .../triggers_actions_ui/public/types.ts | 4 ++-- 12 files changed, 64 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_params.test.tsx index 8c37dc940a2386..ed7b9a19d95418 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_params.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_params.test.tsx @@ -6,10 +6,12 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { DocLinksStart } from 'kibana/public'; +import { coreMock } from 'src/core/public/mocks'; import EmailParamsFields from './email_params'; describe('EmailParamsFields renders', () => { test('all params fields is rendered', () => { + const mocks = coreMock.createSetup(); const actionParams = { cc: [], bcc: [], @@ -25,6 +27,8 @@ describe('EmailParamsFields renders', () => { editAction={() => {}} index={0} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} /> ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index/es_index_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index/es_index_params.test.tsx index a882e3bc43f343..0e4215e503275d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index/es_index_params.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index/es_index_params.test.tsx @@ -7,9 +7,11 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import ParamsFields from './es_index_params'; import { DocLinksStart } from 'kibana/public'; +import { coreMock } from 'src/core/public/mocks'; describe('IndexParamsFields renders', () => { test('all params fields is rendered', () => { + const mocks = coreMock.createSetup(); const actionParams = { documents: [{ test: 123 }], }; @@ -21,6 +23,8 @@ describe('IndexParamsFields renders', () => { editAction={() => {}} index={0} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} /> ); expect(wrapper.find('[data-test-subj="documentsJsonEditor"]').first().prop('value')).toBe(`{ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.test.tsx index 3146ceee297050..d96657f8ca4077 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.test.tsx @@ -7,20 +7,16 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import JiraParamsFields from './jira_params'; import { DocLinksStart } from 'kibana/public'; +import { coreMock } from 'src/core/public/mocks'; import { useGetIssueTypes } from './use_get_issue_types'; import { useGetFieldsByIssueType } from './use_get_fields_by_issue_type'; -jest.mock('../../../context/actions_connectors_context', () => { - const post = jest.fn(); - return { - useActionsConnectorsContext: jest.fn(() => ({ http: { post } })), - }; -}); - jest.mock('./use_get_issue_types'); jest.mock('./use_get_fields_by_issue_type'); +const mocks = coreMock.createSetup(); + const useGetIssueTypesMock = useGetIssueTypes as jest.Mock; const useGetFieldsByIssueTypeMock = useGetFieldsByIssueType as jest.Mock; @@ -93,6 +89,8 @@ describe('JiraParamsFields renders', () => { index={0} messageVariables={[]} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} actionConnector={connector} /> ); @@ -118,6 +116,8 @@ describe('JiraParamsFields renders', () => { index={0} messageVariables={[]} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} actionConnector={connector} /> ); @@ -141,6 +141,8 @@ describe('JiraParamsFields renders', () => { index={0} messageVariables={[]} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} actionConnector={connector} /> ); @@ -164,6 +166,8 @@ describe('JiraParamsFields renders', () => { index={0} messageVariables={[]} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} actionConnector={connector} /> ); @@ -191,6 +195,8 @@ describe('JiraParamsFields renders', () => { index={0} messageVariables={[]} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} actionConnector={connector} /> ); @@ -218,6 +224,8 @@ describe('JiraParamsFields renders', () => { index={0} messageVariables={[]} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} actionConnector={connector} /> ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty/pagerduty_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty/pagerduty_params.test.tsx index fe83054edbe07c..ea947a159b893c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty/pagerduty_params.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty/pagerduty_params.test.tsx @@ -8,9 +8,11 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { EventActionOptions, SeverityActionOptions } from '.././types'; import PagerDutyParamsFields from './pagerduty_params'; import { DocLinksStart } from 'kibana/public'; +import { coreMock } from 'src/core/public/mocks'; describe('PagerDutyParamsFields renders', () => { test('all params fields is rendered', () => { + const mocks = coreMock.createSetup(); const actionParams = { eventAction: EventActionOptions.TRIGGER, dedupKey: 'test', @@ -30,6 +32,8 @@ describe('PagerDutyParamsFields renders', () => { editAction={() => {}} index={0} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} /> ); expect(wrapper.find('[data-test-subj="severitySelect"]').length > 0).toBeTruthy(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.test.tsx index e5898b129dee8d..5f03a548bf16e8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/resilient_params.test.tsx @@ -10,13 +10,9 @@ import { DocLinksStart } from 'kibana/public'; import { useGetIncidentTypes } from './use_get_incident_types'; import { useGetSeverity } from './use_get_severity'; +import { coreMock } from 'src/core/public/mocks'; -jest.mock('../../../context/actions_connectors_context', () => { - const post = jest.fn(); - return { - useActionsConnectorsContext: jest.fn(() => ({ http: { post } })), - }; -}); +const mocks = coreMock.createSetup(); jest.mock('./use_get_incident_types'); jest.mock('./use_get_severity'); @@ -92,6 +88,8 @@ describe('ResilientParamsFields renders', () => { index={0} messageVariables={[]} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} actionConnector={connector} /> ); @@ -114,6 +112,8 @@ describe('ResilientParamsFields renders', () => { index={0} messageVariables={[]} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} actionConnector={connector} /> ); @@ -137,6 +137,8 @@ describe('ResilientParamsFields renders', () => { index={0} messageVariables={[]} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} actionConnector={connector} /> ); @@ -157,6 +159,8 @@ describe('ResilientParamsFields renders', () => { index={0} messageVariables={[]} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} actionConnector={connector} /> ); @@ -180,6 +184,8 @@ describe('ResilientParamsFields renders', () => { index={0} messageVariables={[]} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} actionConnector={connector} /> ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/server_log/server_log_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/server_log/server_log_params.test.tsx index 3a015cddcd335f..407cd70d4ad4c0 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/server_log/server_log_params.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/server_log/server_log_params.test.tsx @@ -8,8 +8,11 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { ServerLogLevelOptions } from '.././types'; import ServerLogParamsFields from './server_log_params'; import { DocLinksStart } from 'kibana/public'; +import { coreMock } from 'src/core/public/mocks'; describe('ServerLogParamsFields renders', () => { + const mocks = coreMock.createSetup(); + test('all params fields is rendered', () => { const actionParams = { level: ServerLogLevelOptions.TRACE, @@ -23,6 +26,8 @@ describe('ServerLogParamsFields renders', () => { index={0} defaultMessage={'test default message'} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} /> ); expect(wrapper.find('[data-test-subj="loggingLevelSelect"]').length > 0).toBeTruthy(); @@ -44,6 +49,8 @@ describe('ServerLogParamsFields renders', () => { editAction={() => {}} index={0} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} /> ); expect(wrapper.find('[data-test-subj="loggingLevelSelect"]').length > 0).toBeTruthy(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_params.test.tsx index f4d831d7234e78..cc8041b38c3605 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_params.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_params.test.tsx @@ -7,9 +7,11 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import ServiceNowParamsFields from './servicenow_params'; import { DocLinksStart } from 'kibana/public'; +import { coreMock } from 'src/core/public/mocks'; describe('ServiceNowParamsFields renders', () => { test('all params fields is rendered', () => { + const mocks = coreMock.createSetup(); const actionParams = { subAction: 'pushToService', subActionParams: { @@ -32,6 +34,8 @@ describe('ServiceNowParamsFields renders', () => { index={0} messageVariables={[]} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} /> ); expect(wrapper.find('[data-test-subj="urgencySelect"]').length > 0).toBeTruthy(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/slack/slack_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/slack/slack_params.test.tsx index 45c1929ae1e22b..c580424c05b956 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/slack/slack_params.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/slack/slack_params.test.tsx @@ -7,9 +7,11 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import SlackParamsFields from './slack_params'; import { DocLinksStart } from 'kibana/public'; +import { coreMock } from 'src/core/public/mocks'; describe('SlackParamsFields renders', () => { test('all params fields is rendered', () => { + const mocks = coreMock.createSetup(); const actionParams = { message: 'test message', }; @@ -21,6 +23,8 @@ describe('SlackParamsFields renders', () => { editAction={() => {}} index={0} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} /> ); expect(wrapper.find('[data-test-subj="messageTextArea"]').length > 0).toBeTruthy(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook_params.test.tsx index 6a1c5cb2bfb535..a4cb36cab76b62 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook_params.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/webhook/webhook_params.test.tsx @@ -7,9 +7,11 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import WebhookParamsFields from './webhook_params'; import { DocLinksStart } from 'kibana/public'; +import { coreMock } from 'src/core/public/mocks'; describe('WebhookParamsFields renders', () => { test('all params fields is rendered', () => { + const mocks = coreMock.createSetup(); const actionParams = { body: 'test message', }; @@ -21,6 +23,8 @@ describe('WebhookParamsFields renders', () => { editAction={() => {}} index={0} docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + toastNotifications={mocks.notifications.toasts} + http={mocks.http} /> ); expect(wrapper.find('[data-test-subj="bodyJsonEditor"]').length > 0).toBeTruthy(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/context/actions_connectors_context.tsx b/x-pack/plugins/triggers_actions_ui/public/application/context/actions_connectors_context.tsx index ffda3e618ea7e9..786fc12380f901 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/context/actions_connectors_context.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/context/actions_connectors_context.tsx @@ -5,17 +5,14 @@ */ import React, { createContext, useContext } from 'react'; -import { HttpSetup, ToastsApi, ApplicationStart, DocLinksStart } from 'kibana/public'; +import { HttpSetup, ApplicationStart, DocLinksStart, ToastsSetup } from 'kibana/public'; import { ActionTypeModel, ActionConnector } from '../../types'; import { TypeRegistry } from '../type_registry'; export interface ActionsConnectorsContextValue { http: HttpSetup; actionTypeRegistry: TypeRegistry; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; + toastNotifications: ToastsSetup; capabilities: ApplicationStart['capabilities']; reloadConnectors?: () => Promise; docLinks: DocLinksStart; 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 e80fe966a2a74c..1b176e0f63dbde 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 @@ -29,7 +29,7 @@ import { EuiText, EuiLoadingSpinner, } from '@elastic/eui'; -import { HttpSetup, ToastsApi, ApplicationStart, DocLinksStart } from 'kibana/public'; +import { HttpSetup, ToastsSetup, ApplicationStart, DocLinksStart } from 'kibana/public'; import { loadActionTypes, loadAllActions as loadConnectors } from '../../lib/action_connector_api'; import { IErrorObject, @@ -56,10 +56,7 @@ interface ActionAccordionFormProps { setActionParamsProperty: (key: string, value: any, index: number) => void; http: HttpSetup; actionTypeRegistry: TypeRegistry; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; + toastNotifications: ToastsSetup; docLinks: DocLinksStart; actionTypes?: ActionType[]; messageVariables?: ActionVariable[]; diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index ca552591f23dcb..e147f035fbb86d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -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 { HttpSetup, DocLinksStart } from 'kibana/public'; +import { HttpSetup, DocLinksStart, ToastsSetup } from 'kibana/public'; import { ComponentType } from 'react'; import { ActionGroup } from '../../alerts/common'; import { ActionType } from '../../actions/common'; @@ -54,7 +54,7 @@ export interface ActionParamsProps { messageVariables?: ActionVariable[]; defaultMessage?: string; docLinks: DocLinksStart; - http?: HttpSetup; + http: HttpSetup; toastNotifications: ToastsSetup; actionConnector?: ActionConnector; } From 3dbbafc8154c658bd4442c40deda3be6425c176c Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Wed, 30 Sep 2020 09:17:37 +0100 Subject: [PATCH 15/15] Use euiSizeL instead of hard coded value Co-authored-by: Andrea Del Rio --- .../sections/action_connector_form/connector_edit_flyout.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.scss b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.scss index b9144a070c613c..5d2997d1012557 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.scss +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_edit_flyout.scss @@ -1,3 +1,3 @@ .connectorEditFlyoutTabs { - margin-bottom: -25px; + margin-bottom: -$euiSizeL; }