Fixed create new connector from alert flyout form throw an error messages in external plugins. (#65539)

* Fixed create new connector from alert flyout form throw an error messages in external plugins.

* Fixed due to comments
This commit is contained in:
Yuliia Naumenko 2020-05-06 16:06:40 -07:00 committed by GitHub
parent c03bdccce1
commit bb9eaf78a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 64 additions and 162 deletions

View file

@ -11,7 +11,6 @@ import { registerBuiltInActionTypes } from './index';
import { ActionTypeModel, ActionParamsProps } from '../../../types'; import { ActionTypeModel, ActionParamsProps } from '../../../types';
import { IndexActionParams, EsIndexActionConnector } from './types'; import { IndexActionParams, EsIndexActionConnector } from './types';
import { coreMock } from '../../../../../../../src/core/public/mocks'; import { coreMock } from '../../../../../../../src/core/public/mocks';
import { ActionsConnectorsContextProvider } from '../../context/actions_connectors_context';
jest.mock('../../../common/index_controls', () => ({ jest.mock('../../../common/index_controls', () => ({
firstFieldOption: jest.fn(), firstFieldOption: jest.fn(),
getFields: jest.fn(), getFields: jest.fn(),
@ -165,25 +164,13 @@ describe('IndexActionConnectorFields renders', () => {
}, },
} as EsIndexActionConnector; } as EsIndexActionConnector;
const wrapper = mountWithIntl( const wrapper = mountWithIntl(
<ActionsConnectorsContextProvider <ConnectorFields
value={{ action={actionConnector}
http: deps!.http, errors={{ index: [] }}
actionTypeRegistry: deps!.actionTypeRegistry, editActionConfig={() => {}}
capabilities: deps!.capabilities, editActionSecrets={() => {}}
toastNotifications: deps!.toastNotifications, http={deps!.http}
reloadConnectors: () => { />
return new Promise<void>(() => {});
},
docLinks: deps!.docLinks,
}}
>
<ConnectorFields
action={actionConnector}
errors={{ index: [] }}
editActionConfig={() => {}}
editActionSecrets={() => {}}
/>
</ActionsConnectorsContextProvider>
); );
await act(async () => { await act(async () => {

View file

@ -33,7 +33,6 @@ import {
getIndexPatterns, getIndexPatterns,
} from '../../../common/index_controls'; } from '../../../common/index_controls';
import { AddMessageVariables } from '../add_message_variables'; import { AddMessageVariables } from '../add_message_variables';
import { useActionsConnectorsContext } from '../../context/actions_connectors_context';
export function getActionType(): ActionTypeModel { export function getActionType(): ActionTypeModel {
return { return {
@ -79,8 +78,7 @@ export function getActionType(): ActionTypeModel {
const IndexActionConnectorFields: React.FunctionComponent<ActionConnectorFieldsProps< const IndexActionConnectorFields: React.FunctionComponent<ActionConnectorFieldsProps<
EsIndexActionConnector EsIndexActionConnector
>> = ({ action, editActionConfig, errors }) => { >> = ({ action, editActionConfig, errors, http }) => {
const { http } = useActionsConnectorsContext();
const { index, refresh, executionTimeField } = action.config; const { index, refresh, executionTimeField } = action.config;
const [hasTimeFieldCheckbox, setTimeFieldCheckboxState] = useState<boolean>( const [hasTimeFieldCheckbox, setTimeFieldCheckboxState] = useState<boolean>(
executionTimeField != null executionTimeField != null

View file

@ -6,7 +6,6 @@
import React, { FunctionComponent } from 'react'; import React, { FunctionComponent } from 'react';
import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers'; import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers';
import { act } from 'react-dom/test-utils'; import { act } from 'react-dom/test-utils';
import { coreMock } from '../../../../../../../src/core/public/mocks';
import { TypeRegistry } from '../../type_registry'; import { TypeRegistry } from '../../type_registry';
import { registerBuiltInActionTypes } from './index'; import { registerBuiltInActionTypes } from './index';
import { ActionTypeModel, ActionParamsProps } from '../../../types'; import { ActionTypeModel, ActionParamsProps } from '../../../types';
@ -16,7 +15,6 @@ import {
SeverityActionOptions, SeverityActionOptions,
PagerDutyActionConnector, PagerDutyActionConnector,
} from './types'; } from './types';
import { ActionsConnectorsContextProvider } from '../../context/actions_connectors_context';
const ACTION_TYPE_ID = '.pagerduty'; const ACTION_TYPE_ID = '.pagerduty';
let actionTypeModel: ActionTypeModel; let actionTypeModel: ActionTypeModel;
@ -29,24 +27,7 @@ beforeAll(async () => {
if (getResult !== null) { if (getResult !== null) {
actionTypeModel = getResult; actionTypeModel = getResult;
} }
const mocks = coreMock.createSetup();
const [
{
application: { capabilities },
},
] = await mocks.getStartServices();
deps = { deps = {
toastNotifications: mocks.notifications.toasts,
http: mocks.http,
capabilities: {
...capabilities,
actions: {
delete: true,
save: true,
show: true,
},
},
actionTypeRegistry: actionTypeRegistry as any,
docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' }, docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' },
}; };
}); });
@ -148,25 +129,13 @@ describe('PagerDutyActionConnectorFields renders', () => {
}, },
} as PagerDutyActionConnector; } as PagerDutyActionConnector;
const wrapper = mountWithIntl( const wrapper = mountWithIntl(
<ActionsConnectorsContextProvider <ConnectorFields
value={{ action={actionConnector}
http: deps!.http, errors={{ index: [], routingKey: [] }}
actionTypeRegistry: deps!.actionTypeRegistry, editActionConfig={() => {}}
capabilities: deps!.capabilities, editActionSecrets={() => {}}
toastNotifications: deps!.toastNotifications, docLinks={deps!.docLinks}
reloadConnectors: () => { />
return new Promise<void>(() => {});
},
docLinks: deps!.docLinks,
}}
>
<ConnectorFields
action={actionConnector}
errors={{ index: [], routingKey: [] }}
editActionConfig={() => {}}
editActionSecrets={() => {}}
/>
</ActionsConnectorsContextProvider>
); );
await act(async () => { await act(async () => {

View file

@ -25,7 +25,6 @@ import { PagerDutyActionParams, PagerDutyActionConnector } from './types';
import pagerDutySvg from './pagerduty.svg'; import pagerDutySvg from './pagerduty.svg';
import { AddMessageVariables } from '../add_message_variables'; import { AddMessageVariables } from '../add_message_variables';
import { hasMustacheTokens } from '../../lib/has_mustache_tokens'; import { hasMustacheTokens } from '../../lib/has_mustache_tokens';
import { useActionsConnectorsContext } from '../../context/actions_connectors_context';
export function getActionType(): ActionTypeModel { export function getActionType(): ActionTypeModel {
return { return {
@ -105,8 +104,7 @@ export function getActionType(): ActionTypeModel {
const PagerDutyActionConnectorFields: React.FunctionComponent<ActionConnectorFieldsProps< const PagerDutyActionConnectorFields: React.FunctionComponent<ActionConnectorFieldsProps<
PagerDutyActionConnector PagerDutyActionConnector
>> = ({ errors, action, editActionConfig, editActionSecrets }) => { >> = ({ errors, action, editActionConfig, editActionSecrets, docLinks }) => {
const { docLinks } = useActionsConnectorsContext();
const { apiUrl } = action.config; const { apiUrl } = action.config;
const { routingKey } = action.secrets; const { routingKey } = action.secrets;
return ( return (

View file

@ -6,12 +6,10 @@
import React, { FunctionComponent } from 'react'; import React, { FunctionComponent } from 'react';
import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers'; import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers';
import { act } from 'react-dom/test-utils'; import { act } from 'react-dom/test-utils';
import { coreMock } from '../../../../../../../src/core/public/mocks';
import { TypeRegistry } from '../../type_registry'; import { TypeRegistry } from '../../type_registry';
import { registerBuiltInActionTypes } from './index'; import { registerBuiltInActionTypes } from './index';
import { ActionTypeModel, ActionParamsProps } from '../../../types'; import { ActionTypeModel, ActionParamsProps } from '../../../types';
import { SlackActionParams, SlackActionConnector } from './types'; import { SlackActionParams, SlackActionConnector } from './types';
import { ActionsConnectorsContextProvider } from '../../context/actions_connectors_context';
const ACTION_TYPE_ID = '.slack'; const ACTION_TYPE_ID = '.slack';
let actionTypeModel: ActionTypeModel; let actionTypeModel: ActionTypeModel;
@ -25,24 +23,7 @@ beforeAll(async () => {
if (getResult !== null) { if (getResult !== null) {
actionTypeModel = getResult; actionTypeModel = getResult;
} }
const mocks = coreMock.createSetup();
const [
{
application: { capabilities },
},
] = await mocks.getStartServices();
deps = { deps = {
toastNotifications: mocks.notifications.toasts,
http: mocks.http,
capabilities: {
...capabilities,
actions: {
delete: true,
save: true,
show: true,
},
},
actionTypeRegistry: actionTypeRegistry as any,
docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' }, docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' },
}; };
}); });
@ -119,25 +100,13 @@ describe('SlackActionFields renders', () => {
config: {}, config: {},
} as SlackActionConnector; } as SlackActionConnector;
const wrapper = mountWithIntl( const wrapper = mountWithIntl(
<ActionsConnectorsContextProvider <ConnectorFields
value={{ action={actionConnector}
http: deps!.http, errors={{ index: [], webhookUrl: [] }}
actionTypeRegistry: deps!.actionTypeRegistry, editActionConfig={() => {}}
capabilities: deps!.capabilities, editActionSecrets={() => {}}
toastNotifications: deps!.toastNotifications, docLinks={deps!.docLinks}
reloadConnectors: () => { />
return new Promise<void>(() => {});
},
docLinks: deps!.docLinks,
}}
>
<ConnectorFields
action={actionConnector}
errors={{ index: [], webhookUrl: [] }}
editActionConfig={() => {}}
editActionSecrets={() => {}}
/>
</ActionsConnectorsContextProvider>
); );
await act(async () => { await act(async () => {

View file

@ -15,7 +15,6 @@ import {
} from '../../../types'; } from '../../../types';
import { SlackActionParams, SlackActionConnector } from './types'; import { SlackActionParams, SlackActionConnector } from './types';
import { AddMessageVariables } from '../add_message_variables'; import { AddMessageVariables } from '../add_message_variables';
import { useActionsConnectorsContext } from '../../context/actions_connectors_context';
export function getActionType(): ActionTypeModel { export function getActionType(): ActionTypeModel {
return { return {
@ -76,8 +75,7 @@ export function getActionType(): ActionTypeModel {
const SlackActionFields: React.FunctionComponent<ActionConnectorFieldsProps< const SlackActionFields: React.FunctionComponent<ActionConnectorFieldsProps<
SlackActionConnector SlackActionConnector
>> = ({ action, editActionSecrets, errors }) => { >> = ({ action, editActionSecrets, errors, docLinks }) => {
const { docLinks } = useActionsConnectorsContext();
const { webhookUrl } = action.secrets; const { webhookUrl } = action.secrets;
return ( return (

View file

@ -49,7 +49,7 @@ export const AlertsContextProvider = ({
export const useAlertsContext = () => { export const useAlertsContext = () => {
const ctx = useContext(AlertsContext); const ctx = useContext(AlertsContext);
if (!ctx) { if (!ctx) {
throw new Error('ActionsConnectorsContext has not been set.'); throw new Error('AlertsContext has not been set.');
} }
return ctx; return ctx;
}; };

View file

@ -9,29 +9,14 @@ import { coreMock } from '../../../../../../../src/core/public/mocks';
import { actionTypeRegistryMock } from '../../action_type_registry.mock'; import { actionTypeRegistryMock } from '../../action_type_registry.mock';
import { ValidationResult, ActionConnector } from '../../../types'; import { ValidationResult, ActionConnector } from '../../../types';
import { ActionConnectorForm } from './action_connector_form'; import { ActionConnectorForm } from './action_connector_form';
import { ActionsConnectorsContextProvider } from '../../context/actions_connectors_context';
const actionTypeRegistry = actionTypeRegistryMock.create(); const actionTypeRegistry = actionTypeRegistryMock.create();
describe('action_connector_form', () => { describe('action_connector_form', () => {
let deps: any; let deps: any;
beforeAll(async () => { beforeAll(async () => {
const mocks = coreMock.createSetup(); const mocks = coreMock.createSetup();
const [
{
application: { capabilities },
},
] = await mocks.getStartServices();
deps = { deps = {
toastNotifications: mocks.notifications.toasts,
http: mocks.http, http: mocks.http,
capabilities: {
...capabilities,
actions: {
delete: true,
save: true,
show: true,
},
},
actionTypeRegistry: actionTypeRegistry as any, actionTypeRegistry: actionTypeRegistry as any,
docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' }, docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' },
}; };
@ -63,25 +48,15 @@ describe('action_connector_form', () => {
let wrapper; let wrapper;
if (deps) { if (deps) {
wrapper = mountWithIntl( wrapper = mountWithIntl(
<ActionsConnectorsContextProvider <ActionConnectorForm
value={{ actionTypeName={'my-action-type-name'}
http: deps!.http, connector={initialConnector}
actionTypeRegistry: deps!.actionTypeRegistry, dispatch={() => {}}
capabilities: deps!.capabilities, errors={{ name: [] }}
toastNotifications: deps!.toastNotifications, http={deps!.http}
reloadConnectors: () => { actionTypeRegistry={deps!.actionTypeRegistry}
return new Promise<void>(() => {}); docLinks={deps!.docLinks}
}, />
docLinks: deps!.docLinks,
}}
>
<ActionConnectorForm
actionTypeName={'my-action-type-name'}
connector={initialConnector}
dispatch={() => {}}
errors={{ name: [] }}
/>
</ActionsConnectorsContextProvider>
); );
} }
const connectorNameField = wrapper?.find('[data-test-subj="nameInput"]'); const connectorNameField = wrapper?.find('[data-test-subj="nameInput"]');

View file

@ -15,9 +15,10 @@ import {
} from '@elastic/eui'; } from '@elastic/eui';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react'; import { FormattedMessage } from '@kbn/i18n/react';
import { HttpSetup, DocLinksStart } from 'kibana/public';
import { ReducerAction } from './connector_reducer'; import { ReducerAction } from './connector_reducer';
import { ActionConnector, IErrorObject } from '../../../types'; import { ActionConnector, IErrorObject, ActionTypeModel } from '../../../types';
import { useActionsConnectorsContext } from '../../context/actions_connectors_context'; import { TypeRegistry } from '../../type_registry';
export function validateBaseProperties(actionObject: ActionConnector) { export function validateBaseProperties(actionObject: ActionConnector) {
const validationResult = { errors: {} }; const validationResult = { errors: {} };
@ -46,6 +47,9 @@ interface ActionConnectorProps {
body: { message: string; error: string }; body: { message: string; error: string };
}; };
errors: IErrorObject; errors: IErrorObject;
http: HttpSetup;
actionTypeRegistry: TypeRegistry<ActionTypeModel>;
docLinks: DocLinksStart;
} }
export const ActionConnectorForm = ({ export const ActionConnectorForm = ({
@ -54,8 +58,10 @@ export const ActionConnectorForm = ({
actionTypeName, actionTypeName,
serverError, serverError,
errors, errors,
http,
actionTypeRegistry,
docLinks,
}: ActionConnectorProps) => { }: ActionConnectorProps) => {
const { actionTypeRegistry, docLinks } = useActionsConnectorsContext();
const setActionProperty = (key: string, value: any) => { const setActionProperty = (key: string, value: any) => {
dispatch({ command: { type: 'setProperty' }, payload: { key, value } }); dispatch({ command: { type: 'setProperty' }, payload: { key, value } });
}; };
@ -150,6 +156,8 @@ export const ActionConnectorForm = ({
errors={errors} errors={errors}
editActionConfig={setActionConfigProperty} editActionConfig={setActionConfigProperty}
editActionSecrets={setActionSecretsProperty} editActionSecrets={setActionSecretsProperty}
http={http}
docLinks={docLinks}
/> />
) : null} ) : null}
</EuiForm> </EuiForm>

View file

@ -52,6 +52,7 @@ export const ConnectorAddFlyout = ({
capabilities, capabilities,
actionTypeRegistry, actionTypeRegistry,
reloadConnectors, reloadConnectors,
docLinks,
} = useActionsConnectorsContext(); } = useActionsConnectorsContext();
const [actionType, setActionType] = useState<ActionType | undefined>(undefined); const [actionType, setActionType] = useState<ActionType | undefined>(undefined);
const [hasActionsUpgradeableByTrial, setHasActionsUpgradeableByTrial] = useState<boolean>(false); const [hasActionsUpgradeableByTrial, setHasActionsUpgradeableByTrial] = useState<boolean>(false);
@ -114,6 +115,9 @@ export const ConnectorAddFlyout = ({
connector={connector} connector={connector}
dispatch={dispatch} dispatch={dispatch}
errors={errors} errors={errors}
actionTypeRegistry={actionTypeRegistry}
http={http}
docLinks={docLinks}
/> />
); );
} }

View file

@ -25,7 +25,6 @@ import { createActionConnector } from '../../lib/action_connector_api';
import { TypeRegistry } from '../../type_registry'; import { TypeRegistry } from '../../type_registry';
import './connector_add_modal.scss'; import './connector_add_modal.scss';
import { PLUGIN } from '../../constants/plugin'; import { PLUGIN } from '../../constants/plugin';
import { ActionsConnectorsContextProvider } from '../../context/actions_connectors_context';
import { hasSaveActionsCapability } from '../../lib/capabilities'; import { hasSaveActionsCapability } from '../../lib/capabilities';
interface ConnectorAddModalProps { interface ConnectorAddModalProps {
@ -156,23 +155,16 @@ export const ConnectorAddModal = ({
</EuiModalHeader> </EuiModalHeader>
<EuiModalBody> <EuiModalBody>
<ActionsConnectorsContextProvider <ActionConnectorForm
value={{ connector={connector}
actionTypeRegistry, actionTypeName={actionType.name}
http, dispatch={dispatch}
capabilities, serverError={serverError}
toastNotifications, errors={errors}
docLinks, actionTypeRegistry={actionTypeRegistry}
}} docLinks={docLinks}
> http={http}
<ActionConnectorForm />
connector={connector}
actionTypeName={actionType.name}
dispatch={dispatch}
serverError={serverError}
errors={errors}
/>
</ActionsConnectorsContextProvider>
</EuiModalBody> </EuiModalBody>
<EuiModalFooter> <EuiModalFooter>
<EuiButtonEmpty onClick={closeModal}> <EuiButtonEmpty onClick={closeModal}>

View file

@ -182,6 +182,9 @@ export const ConnectorEditFlyout = ({
errors={errors} errors={errors}
actionTypeName={connector.actionType} actionTypeName={connector.actionType}
dispatch={dispatch} dispatch={dispatch}
actionTypeRegistry={actionTypeRegistry}
http={http}
docLinks={docLinks}
/> />
) : ( ) : (
<Fragment> <Fragment>

View file

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { HttpSetup } from 'kibana/public'; import { HttpSetup, DocLinksStart } from 'kibana/public';
import { ActionGroup } from '../../alerting/common'; import { ActionGroup } from '../../alerting/common';
import { ActionType } from '../../actions/common'; import { ActionType } from '../../actions/common';
import { TypeRegistry } from './application/type_registry'; import { TypeRegistry } from './application/type_registry';
@ -27,6 +27,7 @@ export interface ActionConnectorFieldsProps<TActionConnector> {
editActionConfig: (property: string, value: any) => void; editActionConfig: (property: string, value: any) => void;
editActionSecrets: (property: string, value: any) => void; editActionSecrets: (property: string, value: any) => void;
errors: { [key: string]: string[] }; errors: { [key: string]: string[] };
docLinks: DocLinksStart;
http?: HttpSetup; http?: HttpSetup;
} }