diff --git a/x-pack/plugins/siem/public/pages/case/components/configure_cases/connectors.test.tsx b/x-pack/plugins/siem/public/pages/case/components/configure_cases/connectors.test.tsx
index 125a42b126466..b0271f6849ac5 100644
--- a/x-pack/plugins/siem/public/pages/case/components/configure_cases/connectors.test.tsx
+++ b/x-pack/plugins/siem/public/pages/case/components/configure_cases/connectors.test.tsx
@@ -16,13 +16,17 @@ describe('Connectors', () => {
let wrapper: ReactWrapper;
const onChangeConnector = jest.fn();
const handleShowAddFlyout = jest.fn();
+ const handleShowEditFlyout = jest.fn();
+
const props: Props = {
disabled: false,
+ updateConnectorDisabled: false,
connectors,
selectedConnector: 'none',
isLoading: false,
onChangeConnector,
handleShowAddFlyout,
+ handleShowEditFlyout,
};
beforeAll(() => {
@@ -87,4 +91,16 @@ describe('Connectors', () => {
expect(onChangeConnector).toHaveBeenCalled();
expect(onChangeConnector).toHaveBeenCalledWith('none');
});
+
+ test('the text of the update button is shown correctly', () => {
+ const newWrapper = mount(, {
+ wrappingComponent: TestProviders,
+ });
+
+ expect(
+ newWrapper
+ .find('button[data-test-subj="case-configure-update-selected-connector-button"]')
+ .text()
+ ).toBe('Update My Connector');
+ });
});
diff --git a/x-pack/plugins/siem/public/pages/case/components/configure_cases/connectors.tsx b/x-pack/plugins/siem/public/pages/case/components/configure_cases/connectors.tsx
index de6d5f76cfad0..1b1439d3bac43 100644
--- a/x-pack/plugins/siem/public/pages/case/components/configure_cases/connectors.tsx
+++ b/x-pack/plugins/siem/public/pages/case/components/configure_cases/connectors.tsx
@@ -4,13 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React from 'react';
+import React, { useMemo } from 'react';
import {
EuiDescribedFormGroup,
EuiFormRow,
EuiFlexGroup,
EuiFlexItem,
EuiLink,
+ EuiButton,
} from '@elastic/eui';
import styled from 'styled-components';
@@ -28,35 +29,55 @@ const EuiFormRowExtended = styled(EuiFormRow)`
}
`;
+const AddConnectorEuiFormRow = styled(EuiFormRow)`
+ width: 100%;
+ max-width: 100%;
+ text-align: right;
+`;
+
export interface Props {
connectors: Connector[];
disabled: boolean;
isLoading: boolean;
+ updateConnectorDisabled: boolean;
onChangeConnector: (id: string) => void;
selectedConnector: string;
handleShowAddFlyout: () => void;
+ handleShowEditFlyout: () => void;
}
const ConnectorsComponent: React.FC = ({
connectors,
- disabled,
isLoading,
+ disabled,
+ updateConnectorDisabled,
onChangeConnector,
selectedConnector,
handleShowAddFlyout,
+ handleShowEditFlyout,
}) => {
- const dropDownLabel = (
-
- {i18n.INCIDENT_MANAGEMENT_SYSTEM_LABEL}
-
-
- {i18n.ADD_NEW_CONNECTOR}
-
-
-
+ const connectorsName = useMemo(
+ () => connectors.find(c => c.id === selectedConnector)?.name ?? 'none',
+ [connectors, selectedConnector]
+ );
+
+ const dropDownLabel = useMemo(
+ () => (
+
+ {i18n.INCIDENT_MANAGEMENT_SYSTEM_LABEL}
+
+ {connectorsName !== 'none' && (
+
+ {i18n.UPDATE_SELECTED_CONNECTOR(connectorsName)}
+
+ )}
+
+
+ ),
+ [connectorsName]
);
return (
@@ -81,6 +102,16 @@ const ConnectorsComponent: React.FC = ({
data-test-subj="case-connectors-dropdown"
/>
+
+
+ {i18n.ADD_NEW_CONNECTOR}
+
+
>
);
diff --git a/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.test.tsx b/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.test.tsx
index 0359c1dbdba67..08975703241c7 100644
--- a/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.test.tsx
+++ b/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.test.tsx
@@ -11,13 +11,11 @@ import { ConfigureCases } from './';
import { TestProviders } from '../../../../mock';
import { Connectors } from './connectors';
import { ClosureOptions } from './closure_options';
-import { Mapping } from './mapping';
import {
ActionsConnectorsContextProvider,
ConnectorAddFlyout,
ConnectorEditFlyout,
} from '../../../../../../triggers_actions_ui/public';
-import { EuiBottomBar } from '@elastic/eui';
import { useKibana } from '../../../../lib/kibana';
import { useConnectors } from '../../../../containers/case/configure/use_connectors';
@@ -55,17 +53,11 @@ describe('ConfigureCases', () => {
});
test('it renders the Connectors', () => {
- expect(wrapper.find('[data-test-subj="case-connectors-form-group"]').exists()).toBeTruthy();
+ expect(wrapper.find('[data-test-subj="dropdown-connectors"]').exists()).toBeTruthy();
});
test('it renders the ClosureType', () => {
- expect(
- wrapper.find('[data-test-subj="case-closure-options-form-group"]').exists()
- ).toBeTruthy();
- });
-
- test('it renders the Mapping', () => {
- expect(wrapper.find('[data-test-subj="case-mapping-form-group"]').exists()).toBeTruthy();
+ expect(wrapper.find('[data-test-subj="closure-options-radio-group"]').exists()).toBeTruthy();
});
test('it renders the ActionsConnectorsContextProvider', () => {
@@ -127,8 +119,12 @@ describe('ConfigureCases', () => {
).toBeTruthy();
});
- test('it disables the update connector button when the connectorId is invalid', () => {
- expect(wrapper.find(Mapping).prop('disabled')).toBe(true);
+ test('it hides the update connector button when the connectorId is invalid', () => {
+ expect(
+ wrapper
+ .find('button[data-test-subj="case-configure-update-selected-connector-button"]')
+ .exists()
+ ).toBeFalsy();
});
});
@@ -171,14 +167,6 @@ describe('ConfigureCases', () => {
expect(wrapper.find(ClosureOptions).prop('disabled')).toBe(false);
expect(wrapper.find(ClosureOptions).prop('closureTypeSelected')).toBe('close-by-user');
- // Mapping
- expect(wrapper.find(Mapping).prop('disabled')).toBe(true);
- expect(wrapper.find(Mapping).prop('updateConnectorDisabled')).toBe(false);
- expect(wrapper.find(Mapping).prop('connectorActionTypeId')).toBe('.servicenow');
- expect(wrapper.find(Mapping).prop('mapping')).toEqual(
- connectors[0].config.casesConfiguration.mapping
- );
-
// Flyouts
expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(false);
expect(wrapper.find(ConnectorAddFlyout).prop('actionTypes')).toEqual([
@@ -200,28 +188,41 @@ describe('ConfigureCases', () => {
).toBeFalsy();
});
- test('it disables the mapping permanently', () => {
- expect(wrapper.find(Mapping).prop('disabled')).toBe(true);
- });
-
- test('it sets the mapping of a connector correctly', () => {
- expect(wrapper.find(Mapping).prop('mapping')).toEqual(
- connectors[0].config.casesConfiguration.mapping
- );
- });
-
- // TODO: When mapping is enabled the test.todo should be implemented.
- test.todo('it disables the update connector button when loading the configuration');
-
test('it disables correctly when the user cannot crud', () => {
const newWrapper = mount(, {
wrappingComponent: TestProviders,
});
- expect(newWrapper.find(Connectors).prop('disabled')).toBe(true);
- expect(newWrapper.find(ClosureOptions).prop('disabled')).toBe(true);
- expect(newWrapper.find(Mapping).prop('disabled')).toBe(true);
- expect(newWrapper.find(Mapping).prop('updateConnectorDisabled')).toBe(true);
+ expect(newWrapper.find('button[data-test-subj="dropdown-connectors"]').prop('disabled')).toBe(
+ true
+ );
+
+ expect(
+ newWrapper
+ .find('button[data-test-subj="case-configure-add-connector-button"]')
+ .prop('disabled')
+ ).toBe(true);
+
+ expect(
+ newWrapper
+ .find('button[data-test-subj="case-configure-update-selected-connector-button"]')
+ .prop('disabled')
+ ).toBe(true);
+
+ // Two closure options
+ expect(
+ newWrapper
+ .find('[data-test-subj="closure-options-radio-group"] input')
+ .first()
+ .prop('disabled')
+ ).toBe(true);
+
+ expect(
+ newWrapper
+ .find('[data-test-subj="closure-options-radio-group"] input')
+ .at(1)
+ .prop('disabled')
+ ).toBe(true);
});
});
@@ -232,7 +233,18 @@ describe('ConfigureCases', () => {
jest.resetAllMocks();
jest.restoreAllMocks();
jest.clearAllMocks();
- useCaseConfigureMock.mockImplementation(() => useCaseConfigureResponse);
+ useCaseConfigureMock.mockImplementation(() => ({
+ ...useCaseConfigureResponse,
+ mapping: connectors[1].config.casesConfiguration.mapping,
+ closureType: 'close-by-user',
+ connectorId: 'servicenow-2',
+ connectorName: 'unchanged',
+ currentConfiguration: {
+ connectorName: 'unchanged',
+ connectorId: 'servicenow-1',
+ closureType: 'close-by-user',
+ },
+ }));
useConnectorsMock.mockImplementation(() => ({
...useConnectorsResponse,
loading: true,
@@ -243,7 +255,9 @@ describe('ConfigureCases', () => {
});
test('it disables correctly Connector when loading connectors', () => {
- expect(wrapper.find(Connectors).prop('disabled')).toBe(true);
+ expect(
+ wrapper.find('button[data-test-subj="dropdown-connectors"]').prop('disabled')
+ ).toBeTruthy();
});
test('it pass the correct value to isLoading attribute on Connector', () => {
@@ -254,38 +268,31 @@ describe('ConfigureCases', () => {
expect(wrapper.find(ClosureOptions).prop('disabled')).toBe(true);
});
- test('it disables the update connector button when loading the connectors', () => {
- expect(wrapper.find(Mapping).prop('disabled')).toBe(true);
+ test('it hides the update connector button when loading the connectors', () => {
+ expect(
+ wrapper
+ .find('button[data-test-subj="case-configure-update-selected-connector-button"]')
+ .prop('disabled')
+ ).toBe(true);
});
+
test('it disables the buttons of action bar when loading connectors', () => {
- useCaseConfigureMock.mockImplementation(() => ({
- ...useCaseConfigureResponse,
- mapping: connectors[1].config.casesConfiguration.mapping,
- closureType: 'close-by-user',
- connectorId: 'servicenow-2',
- connectorName: 'unchanged',
- currentConfiguration: {
- connectorName: 'unchanged',
- connectorId: 'servicenow-1',
- closureType: 'close-by-user',
- },
- }));
const newWrapper = mount(, {
wrappingComponent: TestProviders,
});
expect(
newWrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]')
+ .find('button[data-test-subj="case-configure-action-bottom-bar-cancel-button"]')
.first()
- .prop('isDisabled')
+ .prop('disabled')
).toBe(true);
expect(
newWrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]')
+ .find('button[data-test-subj="case-configure-action-bottom-bar-save-button"]')
.first()
- .prop('isDisabled')
+ .prop('disabled')
).toBe(true);
});
});
@@ -297,6 +304,7 @@ describe('ConfigureCases', () => {
jest.resetAllMocks();
useCaseConfigureMock.mockImplementation(() => ({
...useCaseConfigureResponse,
+ connectorId: 'servicenow-1',
persistLoading: true,
}));
@@ -311,11 +319,27 @@ describe('ConfigureCases', () => {
});
test('it disables correctly ClosureOptions when saving configuration', () => {
- expect(wrapper.find(ClosureOptions).prop('disabled')).toBe(true);
+ expect(
+ wrapper
+ .find('[data-test-subj="closure-options-radio-group"] input')
+ .first()
+ .prop('disabled')
+ ).toBe(true);
+
+ expect(
+ wrapper
+ .find('[data-test-subj="closure-options-radio-group"] input')
+ .at(1)
+ .prop('disabled')
+ ).toBe(true);
});
test('it disables the update connector button when saving the configuration', () => {
- expect(wrapper.find(Mapping).prop('disabled')).toBe(true);
+ expect(
+ wrapper
+ .find('button[data-test-subj="case-configure-update-selected-connector-button"]')
+ .prop('disabled')
+ ).toBe(true);
});
test('it disables the buttons of action bar when saving configuration', () => {
@@ -387,6 +411,32 @@ describe('ConfigureCases', () => {
});
});
+ describe('loading configuration', () => {
+ let wrapper: ReactWrapper;
+
+ beforeEach(() => {
+ jest.resetAllMocks();
+ useCaseConfigureMock.mockImplementation(() => ({
+ ...useCaseConfigureResponse,
+ loading: true,
+ }));
+ useConnectorsMock.mockImplementation(() => ({
+ ...useConnectorsResponse,
+ }));
+ useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs);
+ useGetUrlSearchMock.mockImplementation(() => searchURL);
+ wrapper = mount(, { wrappingComponent: TestProviders });
+ });
+
+ test('it hides the update connector button when loading the configuration', () => {
+ expect(
+ wrapper
+ .find('button[data-test-subj="case-configure-update-selected-connector-button"]')
+ .exists()
+ ).toBeFalsy();
+ });
+ });
+
describe('update connector', () => {
let wrapper: ReactWrapper;
const persistCaseConfigure = jest.fn();
@@ -500,18 +550,22 @@ describe('ConfigureCases', () => {
wrapper.update();
expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(true);
- expect(wrapper.find(EuiBottomBar).exists()).toBeFalsy();
+ expect(
+ wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
+ ).toBeFalsy();
});
test('it show the edit flyout when pressing the update connector button', () => {
const wrapper = mount(, { wrappingComponent: TestProviders });
wrapper
- .find('button[data-test-subj="case-mapping-update-connector-button"]')
+ .find('button[data-test-subj="case-configure-update-selected-connector-button"]')
.simulate('click');
wrapper.update();
expect(wrapper.find(ConnectorEditFlyout).prop('editFlyoutVisible')).toBe(true);
- expect(wrapper.find(EuiBottomBar).exists()).toBeFalsy();
+ expect(
+ wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
+ ).toBeFalsy();
});
test('it tracks the changes successfully', () => {
@@ -681,7 +735,7 @@ describe('ConfigureCases', () => {
// Press update connector button
wrapper
- .find('button[data-test-subj="case-mapping-update-connector-button"]')
+ .find('button[data-test-subj="case-configure-update-selected-connector-button"]')
.simulate('click');
wrapper.update();
@@ -778,29 +832,29 @@ describe('ConfigureCases', () => {
).toBeFalsy();
});
- test('it sets the mapping correctly when changing connector types', () => {
- useCaseConfigureMock.mockImplementation(() => ({
- ...useCaseConfigureResponse,
- mapping: connectors[2].config.casesConfiguration.mapping,
- closureType: 'close-by-user',
- connectorId: 'jira-1',
- connectorName: 'unchanged',
- currentConfiguration: {
- connectorName: 'unchanged',
+ test('the text of the update button is changed successfully', () => {
+ useCaseConfigureMock
+ .mockImplementationOnce(() => ({
+ ...useCaseConfigureResponse,
connectorId: 'servicenow-1',
- closureType: 'close-by-user',
- },
- persistLoading: false,
- }));
+ }))
+ .mockImplementation(() => ({
+ ...useCaseConfigureResponse,
+ connectorId: 'servicenow-2',
+ }));
const wrapper = mount(, { wrappingComponent: TestProviders });
+
+ wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click');
+ wrapper.update();
+ wrapper.find('button[data-test-subj="dropdown-connector-servicenow-2"]').simulate('click');
+ wrapper.update();
+
expect(
- wrapper.find('button[data-test-subj="case-configure-third-party-select-title"]').text()
- ).toBe('Summary');
+ wrapper
+ .find('button[data-test-subj="case-configure-update-selected-connector-button"]')
+ .text()
+ ).toBe('Update My Connector 2');
});
-
- // TODO: When mapping is enabled the test.todo should be implemented.
- test.todo('the mapping is changed successfully when changing the third party');
- test.todo('the mapping is changed successfully when changing the action type');
});
});
diff --git a/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.tsx b/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.tsx
index 40def5231a304..739083a5009ec 100644
--- a/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.tsx
+++ b/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { useCallback, useEffect, useState, Dispatch, SetStateAction, useMemo } from 'react';
+import React, { useCallback, useEffect, useState, Dispatch, SetStateAction } from 'react';
import styled, { css } from 'styled-components';
import {
@@ -16,7 +16,8 @@ import {
EuiButtonEmpty,
EuiText,
} from '@elastic/eui';
-import { isEmpty, difference } from 'lodash/fp';
+
+import { difference } from 'lodash/fp';
import { useKibana } from '../../../../lib/kibana';
import { useConnectors } from '../../../../containers/case/configure/use_connectors';
import { useCaseConfigure } from '../../../../containers/case/configure/use_configure';
@@ -31,12 +32,10 @@ import {
import { ActionConnectorTableItem } from '../../../../../../triggers_actions_ui/public/types';
import { getCaseUrl } from '../../../../components/link_to';
import { useGetUrlSearch } from '../../../../components/navigation/use_get_url_search';
-import { CCMapsCombinedActionAttributes } from '../../../../containers/case/configure/types';
import { connectorsConfiguration } from '../../../../lib/connectors/config';
import { Connectors } from '../configure_cases/connectors';
import { ClosureOptions } from '../configure_cases/closure_options';
-import { Mapping } from '../configure_cases/mapping';
import { SectionWrapper } from '../wrappers';
import { navTabs } from '../../../../pages/home/home_navigations';
import * as i18n from './translations';
@@ -79,14 +78,12 @@ const ConfigureCasesComponent: React.FC = ({ userC
const {
connectorId,
closureType,
- mapping,
currentConfiguration,
loading: loadingCaseConfigure,
persistLoading,
persistCaseConfigure,
setConnector,
setClosureType,
- setMapping,
} = useCaseConfigure();
const { loading: isLoadingConnectors, connectors, refetchConnectors } = useConnectors();
@@ -107,7 +104,7 @@ const ConfigureCasesComponent: React.FC = ({ userC
closureType,
});
},
- [connectorId, connectors, closureType, mapping]
+ [connectorId, connectors, closureType]
);
const onClickAddConnector = useCallback(() => {
@@ -149,24 +146,6 @@ const ConfigureCasesComponent: React.FC = ({ userC
[currentConfiguration, connectorId, closureType]
);
- useEffect(() => {
- if (
- !isEmpty(connectors) &&
- connectorId !== 'none' &&
- connectors.some(c => c.id === connectorId)
- ) {
- const myConnector = connectors.find(c => c.id === connectorId);
- const myMapping = myConnector?.config?.casesConfiguration?.mapping ?? [];
- setMapping(
- myMapping.map((m: CCMapsCombinedActionAttributes) => ({
- source: m.source,
- target: m.target,
- actionType: m.action_type ?? m.actionType,
- }))
- );
- }
- }, [connectors, connectorId]);
-
useEffect(() => {
if (
!isLoadingConnectors &&
@@ -200,11 +179,6 @@ const ConfigureCasesComponent: React.FC = ({ userC
currentConfiguration.closureType,
]);
- const connectorActionTypeId = useMemo(
- () => connectors.find(c => c.id === connectorId)?.actionTypeId ?? '.none',
- [connectorId, connectors]
- );
-
return (
{!connectorIsValid && (
@@ -219,16 +193,6 @@ const ConfigureCasesComponent: React.FC = ({ userC
)}
-
-
-
= ({ userC
/>
-
{actionBarVisible && (
diff --git a/x-pack/plugins/siem/public/pages/case/components/configure_cases/translations.ts b/x-pack/plugins/siem/public/pages/case/components/configure_cases/translations.ts
index 46d713773a837..58438d5cd666a 100644
--- a/x-pack/plugins/siem/public/pages/case/components/configure_cases/translations.ts
+++ b/x-pack/plugins/siem/public/pages/case/components/configure_cases/translations.ts
@@ -33,13 +33,13 @@ export const NO_CONNECTOR = i18n.translate('xpack.siem.case.configureCases.noCon
});
export const ADD_NEW_CONNECTOR = i18n.translate('xpack.siem.case.configureCases.addNewConnector', {
- defaultMessage: 'Add new connector option',
+ defaultMessage: 'Add new connector',
});
export const CASE_CLOSURE_OPTIONS_TITLE = i18n.translate(
'xpack.siem.case.configureCases.caseClosureOptionsTitle',
{
- defaultMessage: 'Cases Closures',
+ defaultMessage: 'Case Closures',
}
);
@@ -170,6 +170,13 @@ export const UPDATE_CONNECTOR = i18n.translate('xpack.siem.case.configureCases.u
defaultMessage: 'Update connector',
});
+export const UPDATE_SELECTED_CONNECTOR = (connectorName: string): string => {
+ return i18n.translate('xpack.siem.case.configureCases.updateSelectedConnector', {
+ values: { connectorName },
+ defaultMessage: 'Update { connectorName }',
+ });
+};
+
export const UNSAVED_CHANGES = (unsavedChanges: number): string => {
return i18n.translate('xpack.siem.case.configureCases.unsavedChanges', {
values: { unsavedChanges },