Skip to content

Commit

Permalink
@YulNaumenko code. PR: #58514
Browse files Browse the repository at this point in the history
  • Loading branch information
cnasikas committed Feb 26, 2020
1 parent 0831dcb commit eed3183
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 94 deletions.
2 changes: 1 addition & 1 deletion x-pack/legacy/plugins/siem/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const siem = (kibana: any) => {
id: APP_ID,
configPrefix: 'xpack.siem',
publicDir: resolve(__dirname, 'public'),
require: ['kibana', 'elasticsearch', 'alerting', 'actions'],
require: ['kibana', 'elasticsearch', 'alerting', 'actions', 'triggers_actions_ui'],
uiExports: {
app: {
description: i18n.translate('xpack.siem.securityDescription', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import React, { useState } from 'react';
import {
EuiDescribedFormGroup,
EuiFormRow,
Expand All @@ -18,6 +18,12 @@ import styled from 'styled-components';
import { ConnectorsDropdown } from './connectors_dropdown';
import * as i18n from './translations';

import {
ActionsConnectorsContextProvider,
ConnectorAddFlyout,
} from '../../../../../../../../plugins/triggers_actions_ui/public';
import { useKibana } from '../../../../lib/kibana';

const EuiFormRowExtended = styled(EuiFormRow)`
.euiFormRow__labelWrapper {
.euiFormRow__label {
Expand All @@ -27,25 +33,42 @@ const EuiFormRowExtended = styled(EuiFormRow)`
`;

const ConnectorsComponent: React.FC = () => {
const { http, triggers_actions_ui, notifications, application } = useKibana().services;
const [addFlyoutVisible, setAddFlyoutVisibility] = useState<boolean>(false);
const dropDownLabel = (
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>{i18n.INCIDENT_MANAGEMENT_SYSTEM_LABEL}</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiLink>{i18n.ADD_NEW_CONNECTOR}</EuiLink>
<EuiLink onClick={() => setAddFlyoutVisibility(true)}>{i18n.ADD_NEW_CONNECTOR}</EuiLink>
</EuiFlexItem>
</EuiFlexGroup>
);

return (
<EuiDescribedFormGroup
fullWidth
title={<h3>{i18n.INCIDENT_MANAGEMENT_SYSTEM_TITLE}</h3>}
description={i18n.INCIDENT_MANAGEMENT_SYSTEM_DESC}
>
<EuiFormRowExtended fullWidth label={dropDownLabel}>
<ConnectorsDropdown />
</EuiFormRowExtended>
</EuiDescribedFormGroup>
<>
<EuiDescribedFormGroup
fullWidth
title={<h3>{i18n.INCIDENT_MANAGEMENT_SYSTEM_TITLE}</h3>}
description={i18n.INCIDENT_MANAGEMENT_SYSTEM_DESC}
>
<EuiFormRowExtended fullWidth label={dropDownLabel}>
<ConnectorsDropdown />
</EuiFormRowExtended>
</EuiDescribedFormGroup>
<ActionsConnectorsContextProvider
value={{
http,
actionTypeRegistry: triggers_actions_ui.actionTypeRegistry,
toastNotifications: notifications.toasts,
capabilities: application.capabilities,
}}
>
<ConnectorAddFlyout
addFlyoutVisible={addFlyoutVisible}
setAddFlyoutVisibility={setAddFlyoutVisibility}
/>
</ActionsConnectorsContextProvider>
</>
);
};

Expand Down
8 changes: 8 additions & 0 deletions x-pack/legacy/plugins/siem/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,26 @@ import { UsageCollectionSetup } from '../../../../../src/plugins/usage_collectio
import { initTelemetry } from './lib/telemetry';
import { KibanaServices } from './lib/kibana';


import {
TriggersAndActionsUIPublicPluginSetup,
TriggersAndActionsUIPublicPluginStart,
} from '../../../../plugins/triggers_actions_ui/public';

export { AppMountParameters, CoreSetup, CoreStart, PluginInitializerContext };

export interface SetupPlugins {
home: HomePublicPluginSetup;
usageCollection: UsageCollectionSetup;
triggers_actions_ui: TriggersAndActionsUIPublicPluginSetup;
}
export interface StartPlugins {
data: DataPublicPluginStart;
embeddable: IEmbeddableStart;
inspector: InspectorStart;
newsfeed?: NewsfeedStart;
uiActions: UiActionsStart;
triggers_actions_ui: TriggersAndActionsUIPublicPluginStart;
}
export type StartServices = CoreStart & StartPlugins;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@
*/

import React, { createContext, useContext } from 'react';
import { ActionType } from '../../types';
import { HttpSetup, ToastsApi, ApplicationStart } from 'kibana/public';
import { ActionTypeModel } from '../../types';
import { TypeRegistry } from '../type_registry';

export interface ActionsConnectorsContextValue {
addFlyoutVisible: boolean;
editFlyoutVisible: boolean;
setEditFlyoutVisibility: React.Dispatch<React.SetStateAction<boolean>>;
setAddFlyoutVisibility: React.Dispatch<React.SetStateAction<boolean>>;
actionTypesIndex: Record<string, ActionType> | undefined;
reloadConnectors: () => Promise<void>;
http: HttpSetup;
actionTypeRegistry: TypeRegistry<ActionTypeModel>;
toastNotifications?: Pick<
ToastsApi,
'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError'
>;
capabilities: ApplicationStart['capabilities'];
reloadConnectors?: () => Promise<void>;
}

const ActionsConnectorsContext = createContext<ActionsConnectorsContextValue>(null as any);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,49 @@
* 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 from 'react';
import React, { useEffect, useState } from 'react';
import { EuiFlexItem, EuiCard, EuiIcon, EuiFlexGrid } from '@elastic/eui';
import { ActionType, ActionTypeModel } from '../../../types';
import { i18n } from '@kbn/i18n';
import { ActionType, ActionTypeIndex } from '../../../types';
import { loadActionTypes } from '../../lib/action_connector_api';
import { useActionsConnectorsContext } from '../../context/actions_connectors_context';
import { TypeRegistry } from '../../type_registry';

interface Props {
onActionTypeChange: (actionType: ActionType) => void;
actionTypeRegistry: TypeRegistry<ActionTypeModel>;
}

export const ActionTypeMenu = ({ onActionTypeChange, actionTypeRegistry }: Props) => {
const { actionTypesIndex } = useActionsConnectorsContext();
if (!actionTypesIndex) {
return null;
}
export const ActionTypeMenu = ({ onActionTypeChange }: Props) => {
const { http, toastNotifications, actionTypeRegistry } = useActionsConnectorsContext();
const [actionTypesIndex, setActionTypesIndex] = useState<ActionTypeIndex | undefined>(undefined);
const [isLoadingActionTypes, setIsLoadingActionTypes] = useState<boolean>(false);

const actionTypes = Object.entries(actionTypesIndex)
useEffect(() => {
(async () => {
try {
setIsLoadingActionTypes(true);
const actionTypes = await loadActionTypes({ http });
const index: ActionTypeIndex = {};
for (const actionTypeItem of actionTypes) {
index[actionTypeItem.id] = actionTypeItem;
}
setActionTypesIndex(index);
} catch (e) {
if (toastNotifications) {
toastNotifications.addDanger({
title: i18n.translate(
'xpack.triggersActionsUI.sections.actionsConnectorsList.unableToLoadActionTypesMessage',
{ defaultMessage: 'Unable to load action types' }
),
});
}
} finally {
setIsLoadingActionTypes(false);
}
})();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const actionTypes = Object.entries(actionTypesIndex ?? [])
.filter(([index]) => actionTypeRegistry.has(index))
.map(([index, actionType]) => {
const actionTypeModel = actionTypeRegistry.get(index);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,31 @@ import {
EuiFlyoutBody,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useActionsConnectorsContext } from '../../context/actions_connectors_context';
import { ActionTypeMenu } from './action_type_menu';
import { ActionConnectorForm, validateBaseProperties } from './action_connector_form';
import { ActionType, ActionConnector, IErrorObject } from '../../../types';
import { useAppDependencies } from '../../app_context';
import { connectorReducer } from './connector_reducer';
import { hasSaveActionsCapability } from '../../lib/capabilities';
import { createActionConnector } from '../../lib/action_connector_api';
import { useActionsConnectorsContext } from '../../context/actions_connectors_context';

export const ConnectorAddFlyout = () => {
export interface ConnectorAddFlyoutProps {
addFlyoutVisible: boolean;
setAddFlyoutVisibility: React.Dispatch<React.SetStateAction<boolean>>;
}

export const ConnectorAddFlyout = ({
addFlyoutVisible,
setAddFlyoutVisibility,
}: ConnectorAddFlyoutProps) => {
let hasErrors = false;
const { http, toastNotifications, capabilities, actionTypeRegistry } = useAppDependencies();
const {
http,
toastNotifications,
capabilities,
actionTypeRegistry,
reloadConnectors,
} = useActionsConnectorsContext();
const [actionType, setActionType] = useState<ActionType | undefined>(undefined);

// hooks
Expand All @@ -47,11 +60,6 @@ export const ConnectorAddFlyout = () => {
dispatch({ command: { type: 'setConnector' }, payload: { key: 'connector', value } });
};

const {
addFlyoutVisible,
setAddFlyoutVisibility,
reloadConnectors,
} = useActionsConnectorsContext();
const [isSaving, setIsSaving] = useState<boolean>(false);

const closeFlyout = useCallback(() => {
Expand All @@ -77,12 +85,7 @@ export const ConnectorAddFlyout = () => {
let currentForm;
let actionTypeModel;
if (!actionType) {
currentForm = (
<ActionTypeMenu
onActionTypeChange={onActionTypeChange}
actionTypeRegistry={actionTypeRegistry}
/>
);
currentForm = <ActionTypeMenu onActionTypeChange={onActionTypeChange} />;
} else {
actionTypeModel = actionTypeRegistry.get(actionType.id);

Expand All @@ -107,17 +110,19 @@ export const ConnectorAddFlyout = () => {
const onActionConnectorSave = async (): Promise<ActionConnector | undefined> =>
await createActionConnector({ http, connector })
.then(savedConnector => {
toastNotifications.addSuccess(
i18n.translate(
'xpack.triggersActionsUI.sections.addConnectorForm.updateSuccessNotificationText',
{
defaultMessage: "Created '{connectorName}'",
values: {
connectorName: savedConnector.name,
},
}
)
);
if (toastNotifications) {
toastNotifications.addSuccess(
i18n.translate(
'xpack.triggersActionsUI.sections.addConnectorForm.updateSuccessNotificationText',
{
defaultMessage: "Created '{connectorName}'",
values: {
connectorName: savedConnector.name,
},
}
)
);
}
return savedConnector;
})
.catch(errorRes => {
Expand Down Expand Up @@ -195,7 +200,9 @@ export const ConnectorAddFlyout = () => {
setIsSaving(false);
if (savedAction) {
closeFlyout();
reloadConnectors();
if (reloadConnectors) {
reloadConnectors();
}
}
}}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,19 @@ describe('connector_edit_flyout', () => {
<AppContextProvider appDeps={deps}>
<ActionsConnectorsContextProvider
value={{
addFlyoutVisible: false,
setAddFlyoutVisibility: state => {},
editFlyoutVisible: true,
setEditFlyoutVisibility: state => {},
actionTypesIndex: {
'test-action-type-id': { id: 'test-action-type-id', name: 'test', enabled: true },
},
http: deps.http,
capabilities: deps.capabilities,
actionTypeRegistry: deps.actionTypeRegistry,
reloadConnectors: () => {
return new Promise<void>(() => {});
},
}}
>
<ConnectorEditFlyout initialConnector={connector} />
<ConnectorEditFlyout
initialConnector={connector}
editFlyoutVisible={true}
setEditFlyoutVisibility={state => {}}
/>
</ActionsConnectorsContextProvider>
</AppContextProvider>
);
Expand Down
Loading

0 comments on commit eed3183

Please sign in to comment.