diff --git a/x-pack/plugins/siem/cypress/integration/cases_connectors.spec.ts b/x-pack/plugins/siem/cypress/integration/cases_connectors.spec.ts
index 2d650b1bbd9d1..6beb936d15ee6 100644
--- a/x-pack/plugins/siem/cypress/integration/cases_connectors.spec.ts
+++ b/x-pack/plugins/siem/cypress/integration/cases_connectors.spec.ts
@@ -11,7 +11,6 @@ import { goToEditExternalConnection } from '../tasks/all_cases';
import {
addServiceNowConnector,
openAddNewConnectorOption,
- saveChanges,
selectLastConnectorCreated,
} from '../tasks/configure_cases';
import { loginAndWaitForPageWithoutDateRange } from '../tasks/login';
@@ -37,7 +36,6 @@ describe('Cases connectors', () => {
cy.get(TOASTER).should('have.text', "Created 'New connector'");
selectLastConnectorCreated();
- saveChanges();
cy.wait('@saveConnector', { timeout: 10000 })
.its('status')
diff --git a/x-pack/plugins/siem/cypress/screens/configure_cases.ts b/x-pack/plugins/siem/cypress/screens/configure_cases.ts
index 5a1e897c43e27..006c524a38acb 100644
--- a/x-pack/plugins/siem/cypress/screens/configure_cases.ts
+++ b/x-pack/plugins/siem/cypress/screens/configure_cases.ts
@@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export const ADD_NEW_CONNECTOR_OPTION_LINK =
- '[data-test-subj="case-configure-add-connector-button"]';
+export const ADD_NEW_CONNECTOR_DROPDOWN_BUTTON =
+ '[data-test-subj="dropdown-connector-add-connector"]';
export const CONNECTOR = (id: string) => {
return `[data-test-subj='dropdown-connector-${id}']`;
diff --git a/x-pack/plugins/siem/cypress/tasks/configure_cases.ts b/x-pack/plugins/siem/cypress/tasks/configure_cases.ts
index 9172e02708ae7..6ba9e875c7cb0 100644
--- a/x-pack/plugins/siem/cypress/tasks/configure_cases.ts
+++ b/x-pack/plugins/siem/cypress/tasks/configure_cases.ts
@@ -5,13 +5,12 @@
*/
import {
- ADD_NEW_CONNECTOR_OPTION_LINK,
+ ADD_NEW_CONNECTOR_DROPDOWN_BUTTON,
CONNECTOR,
CONNECTOR_NAME,
CONNECTORS_DROPDOWN,
PASSWORD,
SAVE_BTN,
- SAVE_CHANGES_BTN,
SERVICE_NOW_CONNECTOR_CARD,
URL,
USERNAME,
@@ -33,15 +32,12 @@ export const openAddNewConnectorOption = () => {
cy.get(MAIN_PAGE).then($page => {
if ($page.find(SERVICE_NOW_CONNECTOR_CARD).length !== 1) {
cy.wait(1000);
- cy.get(ADD_NEW_CONNECTOR_OPTION_LINK).click({ force: true });
+ cy.get(CONNECTORS_DROPDOWN).click({ force: true });
+ cy.get(ADD_NEW_CONNECTOR_DROPDOWN_BUTTON).click();
}
});
};
-export const saveChanges = () => {
- cy.get(SAVE_CHANGES_BTN).click();
-};
-
export const selectLastConnectorCreated = () => {
cy.get(CONNECTORS_DROPDOWN).click({ force: true });
cy.get('@createConnector')
diff --git a/x-pack/plugins/siem/public/cases/components/callout/index.test.tsx b/x-pack/plugins/siem/public/cases/components/callout/index.test.tsx
index 0ab90d8a73126..f157f654d5617 100644
--- a/x-pack/plugins/siem/public/cases/components/callout/index.test.tsx
+++ b/x-pack/plugins/siem/public/cases/components/callout/index.test.tsx
@@ -19,53 +19,79 @@ describe('CaseCallOut ', () => {
...defaultProps,
message: 'we have one message',
};
+
const wrapper = mount();
+
expect(
wrapper
- .find(`[data-test-subj="callout-message"]`)
+ .find(`[data-test-subj="callout-message-primary"]`)
.last()
.exists()
).toBeTruthy();
+ });
+
+ it('Renders multi message callout', () => {
+ const props = {
+ ...defaultProps,
+ messages: [
+ { ...defaultProps, description:
{'we have two messages'}
},
+ { ...defaultProps, description: {'for real'}
},
+ ],
+ };
+ const wrapper = mount();
expect(
wrapper
- .find(`[data-test-subj="callout-messages"]`)
+ .find(`[data-test-subj="callout-message-primary"]`)
.last()
.exists()
).toBeFalsy();
+ expect(
+ wrapper
+ .find(`[data-test-subj="callout-messages-primary"]`)
+ .last()
+ .exists()
+ ).toBeTruthy();
});
- it('Renders multi message callout', () => {
+
+ it('it shows the correct type of callouts', () => {
const props = {
...defaultProps,
messages: [
- { ...defaultProps, description: {'we have two messages'}
},
+ {
+ ...defaultProps,
+ description: {'we have two messages'}
,
+ errorType: 'danger' as 'primary' | 'success' | 'warning' | 'danger',
+ },
{ ...defaultProps, description: {'for real'}
},
],
};
const wrapper = mount();
expect(
wrapper
- .find(`[data-test-subj="callout-message"]`)
+ .find(`[data-test-subj="callout-messages-danger"]`)
.last()
.exists()
- ).toBeFalsy();
+ ).toBeTruthy();
+
expect(
wrapper
- .find(`[data-test-subj="callout-messages"]`)
+ .find(`[data-test-subj="callout-messages-primary"]`)
.last()
.exists()
).toBeTruthy();
});
+
it('Dismisses callout', () => {
const props = {
...defaultProps,
message: 'we have one message',
};
const wrapper = mount();
- expect(wrapper.find(`[data-test-subj="case-call-out"]`).exists()).toBeTruthy();
+ expect(wrapper.find(`[data-test-subj="case-call-out-primary"]`).exists()).toBeTruthy();
wrapper
- .find(`[data-test-subj="callout-dismiss"]`)
+ .find(`[data-test-subj="callout-dismiss-primary"]`)
.last()
.simulate('click');
- expect(wrapper.find(`[data-test-subj="case-call-out"]`).exists()).toBeFalsy();
+ expect(wrapper.find(`[data-test-subj="case-call-out-primary"]`).exists()).toBeFalsy();
});
});
diff --git a/x-pack/plugins/siem/public/cases/components/callout/index.tsx b/x-pack/plugins/siem/public/cases/components/callout/index.tsx
index 0fc93af7f318d..5266c9aec9705 100644
--- a/x-pack/plugins/siem/public/cases/components/callout/index.tsx
+++ b/x-pack/plugins/siem/public/cases/components/callout/index.tsx
@@ -12,28 +12,69 @@ import * as i18n from './translations';
export * from './helpers';
+interface ErrorMessage {
+ title: string;
+ description: JSX.Element;
+ errorType?: 'primary' | 'success' | 'warning' | 'danger';
+}
+
interface CaseCallOutProps {
title: string;
message?: string;
- messages?: Array<{ title: string; description: JSX.Element }>;
+ messages?: ErrorMessage[];
}
const CaseCallOutComponent = ({ title, message, messages }: CaseCallOutProps) => {
const [showCallOut, setShowCallOut] = useState(true);
const handleCallOut = useCallback(() => setShowCallOut(false), [setShowCallOut]);
+ let callOutMessages = messages ?? [];
+
+ if (message) {
+ callOutMessages = [
+ ...callOutMessages,
+ {
+ title: '',
+ description: {message}
,
+ errorType: 'primary',
+ },
+ ];
+ }
+
+ const groupedErrorMessages = callOutMessages.reduce((acc, currentMessage: ErrorMessage) => {
+ const key = currentMessage.errorType == null ? 'primary' : currentMessage.errorType;
+ return {
+ ...acc,
+ [key]: [...(acc[key] || []), currentMessage],
+ };
+ }, {} as { [key in NonNullable]: ErrorMessage[] });
return showCallOut ? (
<>
-
- {!isEmpty(messages) && (
-
- )}
- {!isEmpty(message) && {message}
}
-
- {i18n.DISMISS_CALLOUT}
-
-
-
+ {(Object.keys(groupedErrorMessages) as Array).map(key => (
+
+
+ {!isEmpty(groupedErrorMessages[key]) && (
+
+ )}
+
+ {i18n.DISMISS_CALLOUT}
+
+
+
+
+ ))}
>
) : null;
};
diff --git a/x-pack/plugins/siem/public/cases/components/configure_cases/connectors.test.tsx b/x-pack/plugins/siem/public/cases/components/configure_cases/connectors.test.tsx
index 41cd3e549415d..4f6fad8491206 100644
--- a/x-pack/plugins/siem/public/cases/components/configure_cases/connectors.test.tsx
+++ b/x-pack/plugins/siem/public/cases/components/configure_cases/connectors.test.tsx
@@ -15,7 +15,6 @@ import { connectors } from './__mock__';
describe('Connectors', () => {
let wrapper: ReactWrapper;
const onChangeConnector = jest.fn();
- const handleShowAddFlyout = jest.fn();
const handleShowEditFlyout = jest.fn();
const props: Props = {
@@ -25,7 +24,6 @@ describe('Connectors', () => {
selectedConnector: 'none',
isLoading: false,
onChangeConnector,
- handleShowAddFlyout,
handleShowEditFlyout,
};
@@ -92,6 +90,15 @@ describe('Connectors', () => {
expect(onChangeConnector).toHaveBeenCalledWith('none');
});
+ test('it shows the add connector button', () => {
+ wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click');
+ wrapper.update();
+
+ expect(
+ wrapper.find('button[data-test-subj="dropdown-connector-add-connector"]').exists()
+ ).toBeTruthy();
+ });
+
test('the text of the update button is shown correctly', () => {
const newWrapper = mount(, {
wrappingComponent: TestProviders,
diff --git a/x-pack/plugins/siem/public/cases/components/configure_cases/connectors.tsx b/x-pack/plugins/siem/public/cases/components/configure_cases/connectors.tsx
index 3916ce297a0a4..76e816a2909ab 100644
--- a/x-pack/plugins/siem/public/cases/components/configure_cases/connectors.tsx
+++ b/x-pack/plugins/siem/public/cases/components/configure_cases/connectors.tsx
@@ -11,7 +11,6 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiLink,
- EuiButton,
} from '@elastic/eui';
import styled from 'styled-components';
@@ -29,12 +28,6 @@ const EuiFormRowExtended = styled(EuiFormRow)`
}
`;
-const AddConnectorEuiFormRow = styled(EuiFormRow)`
- width: 100%;
- max-width: 100%;
- text-align: right;
-`;
-
export interface Props {
connectors: Connector[];
disabled: boolean;
@@ -42,7 +35,6 @@ export interface Props {
updateConnectorDisabled: boolean;
onChangeConnector: (id: string) => void;
selectedConnector: string;
- handleShowAddFlyout: () => void;
handleShowEditFlyout: () => void;
}
const ConnectorsComponent: React.FC = ({
@@ -52,7 +44,6 @@ const ConnectorsComponent: React.FC = ({
updateConnectorDisabled,
onChangeConnector,
selectedConnector,
- handleShowAddFlyout,
handleShowEditFlyout,
}) => {
const connectorsName = useMemo(
@@ -77,7 +68,7 @@ const ConnectorsComponent: React.FC = ({
),
- [connectorsName]
+ [connectorsName, updateConnectorDisabled]
);
return (
@@ -100,18 +91,9 @@ const ConnectorsComponent: React.FC = ({
isLoading={isLoading}
onChange={onChangeConnector}
data-test-subj="case-connectors-dropdown"
+ appendAddConnectorButton={true}
/>
-
-
- {i18n.ADD_NEW_CONNECTOR}
-
-
>
);
diff --git a/x-pack/plugins/siem/public/cases/components/configure_cases/connectors_dropdown.tsx b/x-pack/plugins/siem/public/cases/components/configure_cases/connectors_dropdown.tsx
index b2b2edb04bd29..c5481f592e750 100644
--- a/x-pack/plugins/siem/public/cases/components/configure_cases/connectors_dropdown.tsx
+++ b/x-pack/plugins/siem/public/cases/components/configure_cases/connectors_dropdown.tsx
@@ -18,6 +18,7 @@ export interface Props {
isLoading: boolean;
onChange: (id: string) => void;
selectedConnector: string;
+ appendAddConnectorButton?: boolean;
}
const ICON_SIZE = 'm';
@@ -42,40 +43,55 @@ const noConnectorOption = {
'data-test-subj': 'dropdown-connector-no-connector',
};
+const addNewConnector = {
+ value: 'add-connector',
+ inputDisplay: (
+
+ {i18n.ADD_NEW_CONNECTOR}
+
+ ),
+ 'data-test-subj': 'dropdown-connector-add-connector',
+};
+
const ConnectorsDropdownComponent: React.FC = ({
connectors,
disabled,
isLoading,
onChange,
selectedConnector,
+ appendAddConnectorButton = false,
}) => {
- const connectorsAsOptions = useMemo(
- () =>
- connectors.reduce(
- (acc, connector) => [
- ...acc,
- {
- value: connector.id,
- inputDisplay: (
-
-
-
-
-
- {connector.name}
-
-
- ),
- 'data-test-subj': `dropdown-connector-${connector.id}`,
- },
- ],
- [noConnectorOption]
- ),
- [connectors]
- );
+ const connectorsAsOptions = useMemo(() => {
+ const connectorsFormatted = connectors.reduce(
+ (acc, connector) => [
+ ...acc,
+ {
+ value: connector.id,
+ inputDisplay: (
+
+
+
+
+
+ {connector.name}
+
+
+ ),
+ 'data-test-subj': `dropdown-connector-${connector.id}`,
+ },
+ ],
+ [noConnectorOption]
+ );
+
+ if (appendAddConnectorButton) {
+ return [...connectorsFormatted, addNewConnector];
+ }
+
+ return connectorsFormatted;
+ }, [connectors]);
return (
{
wrapper.find('[data-test-subj="configure-cases-warning-callout"]').exists()
).toBeFalsy();
});
-
- test('it does NOT render the EuiBottomBar', () => {
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeFalsy();
- });
-
- test('it disables correctly ClosureOptions when the connector is set to none', () => {
- expect(wrapper.find(ClosureOptions).prop('disabled')).toBe(true);
- });
});
describe('Unhappy path', () => {
@@ -182,12 +172,6 @@ describe('ConfigureCases', () => {
expect(wrapper.find(ConnectorEditFlyout).prop('initialConnector')).toEqual(connectors[0]);
});
- test('it does not shows the action bar when there is no change', () => {
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeFalsy();
- });
-
test('it disables correctly when the user cannot crud', () => {
const newWrapper = mount(, {
wrappingComponent: TestProviders,
@@ -197,12 +181,6 @@ describe('ConfigureCases', () => {
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"]')
@@ -275,26 +253,6 @@ describe('ConfigureCases', () => {
.prop('disabled')
).toBe(true);
});
-
- test('it disables the buttons of action bar when loading connectors', () => {
- const newWrapper = mount(, {
- wrappingComponent: TestProviders,
- });
-
- expect(
- newWrapper
- .find('button[data-test-subj="case-configure-action-bottom-bar-cancel-button"]')
- .first()
- .prop('disabled')
- ).toBe(true);
-
- expect(
- newWrapper
- .find('button[data-test-subj="case-configure-action-bottom-bar-save-button"]')
- .first()
- .prop('disabled')
- ).toBe(true);
- });
});
describe('saving configuration', () => {
@@ -341,74 +299,6 @@ describe('ConfigureCases', () => {
.prop('disabled')
).toBe(true);
});
-
- test('it disables the buttons of action bar when saving configuration', () => {
- 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',
- },
- persistLoading: true,
- }));
-
- const newWrapper = mount(, {
- wrappingComponent: TestProviders,
- });
-
- expect(
- newWrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]')
- .first()
- .prop('isDisabled')
- ).toBe(true);
-
- expect(
- newWrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]')
- .first()
- .prop('isDisabled')
- ).toBe(true);
- });
-
- test('it shows the loading spinner when saving configuration', () => {
- 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',
- },
- persistLoading: true,
- }));
-
- const newWrapper = mount(, {
- wrappingComponent: TestProviders,
- });
-
- expect(
- newWrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]')
- .first()
- .prop('isLoading')
- ).toBe(true);
-
- expect(
- newWrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]')
- .first()
- .prop('isLoading')
- ).toBe(true);
- });
});
describe('loading configuration', () => {
@@ -437,7 +327,7 @@ describe('ConfigureCases', () => {
});
});
- describe('update connector', () => {
+ describe('connectors', () => {
let wrapper: ReactWrapper;
const persistCaseConfigure = jest.fn();
@@ -445,13 +335,13 @@ describe('ConfigureCases', () => {
jest.resetAllMocks();
useCaseConfigureMock.mockImplementation(() => ({
...useCaseConfigureResponse,
- mapping: connectors[1].config.casesConfiguration.mapping,
+ mapping: connectors[0].config.casesConfiguration.mapping,
closureType: 'close-by-user',
- connectorId: 'servicenow-2',
- connectorName: 'unchanged',
+ connectorId: 'servicenow-1',
+ connectorName: 'My connector',
currentConfiguration: {
- connectorName: 'unchanged',
- connectorId: 'servicenow-1',
+ connectorName: 'My connector',
+ connectorId: 'My connector',
closureType: 'close-by-user',
},
persistCaseConfigure,
@@ -463,12 +353,10 @@ describe('ConfigureCases', () => {
wrapper = mount(, { wrappingComponent: TestProviders });
});
- test('it submits the configuration correctly', () => {
- wrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]')
- .first()
- .simulate('click');
-
+ test('it submits the configuration correctly when changing connector', () => {
+ 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(persistCaseConfigure).toHaveBeenCalled();
@@ -479,382 +367,112 @@ describe('ConfigureCases', () => {
});
});
- test('it has the correct url on cancel button', () => {
- expect(
- wrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]')
- .first()
- .prop('href')
- ).toBe(`#/link-to/case${searchURL}`);
- });
-
- test('it disables the buttons of action bar when loading configuration', () => {
- 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',
- },
- loading: true,
- }));
- const newWrapper = mount(, {
- wrappingComponent: TestProviders,
- });
-
- expect(
- newWrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]')
- .first()
- .prop('isDisabled')
- ).toBe(true);
-
- expect(
- newWrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]')
- .first()
- .prop('isDisabled')
- ).toBe(true);
- });
- });
-
- describe('user interactions', () => {
- beforeEach(() => {
- jest.resetAllMocks();
- useCaseConfigureMock.mockImplementation(() => ({
- ...useCaseConfigureResponse,
- mapping: connectors[1].config.casesConfiguration.mapping,
- closureType: 'close-by-user',
- connectorId: 'servicenow-2',
- connectorName: 'unchanged',
- currentConfiguration: {
- connectorName: 'unchanged',
- connectorId: 'servicenow-2',
- closureType: 'close-by-user',
- },
- }));
- useConnectorsMock.mockImplementation(() => useConnectorsResponse);
- useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs);
- useGetUrlSearchMock.mockImplementation(() => searchURL);
- });
-
- test('it show the add flyout when pressing the add connector button', () => {
- const wrapper = mount(, { wrappingComponent: TestProviders });
- wrapper
- .find('button[data-test-subj="case-configure-add-connector-button"]')
- .simulate('click');
- wrapper.update();
-
- expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(true);
- 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-configure-update-selected-connector-button"]')
- .simulate('click');
- wrapper.update();
-
- expect(wrapper.find(ConnectorEditFlyout).prop('editFlyoutVisible')).toBe(true);
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeFalsy();
- });
-
- test('it tracks the changes successfully', () => {
- 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-pushing',
- },
- }));
- 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();
- wrapper.find('input[id="close-by-pushing"]').simulate('change');
- wrapper.update();
-
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeTruthy();
- expect(
- wrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]')
- .first()
- .text()
- ).toBe('2 unsaved changes');
- });
-
- test('it tracks the changes successfully when name changes', () => {
- useCaseConfigureMock.mockImplementation(() => ({
- ...useCaseConfigureResponse,
- mapping: connectors[1].config.casesConfiguration.mapping,
- closureType: 'close-by-user',
- connectorId: 'servicenow-2',
- connectorName: 'nameChange',
- currentConfiguration: {
- connectorId: 'servicenow-1',
- closureType: 'close-by-pushing',
- connectorName: 'before',
- },
- }));
-
- 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();
- wrapper.find('input[id="close-by-pushing"]').simulate('change');
- wrapper.update();
-
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeTruthy();
- expect(
- wrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]')
- .first()
- .text()
- ).toBe('2 unsaved changes');
- });
-
- test('it tracks and reverts the changes successfully ', () => {
- const wrapper = mount(, { wrappingComponent: TestProviders });
- // change settings
- 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();
- wrapper.find('input[id="close-by-pushing"]').simulate('change');
- wrapper.update();
-
- // revert back to initial settings
- wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click');
- wrapper.update();
- wrapper.find('button[data-test-subj="dropdown-connector-servicenow-1"]').simulate('click');
- wrapper.update();
- wrapper.find('input[id="close-by-user"]').simulate('change');
- wrapper.update();
-
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeFalsy();
- });
-
- test('it close and restores the action bar when the add connector button is pressed', () => {
- useCaseConfigureMock
- .mockImplementationOnce(() => ({
- ...useCaseConfigureResponse,
- mapping: connectors[1].config.casesConfiguration.mapping,
- closureType: 'close-by-user',
- connectorId: 'servicenow-2',
- currentConfiguration: { connectorId: 'servicenow-2', closureType: 'close-by-user' },
- }))
- .mockImplementation(() => ({
- ...useCaseConfigureResponse,
- mapping: connectors[1].config.casesConfiguration.mapping,
- closureType: 'close-by-pushing',
- connectorId: 'servicenow-2',
- currentConfiguration: { connectorId: 'servicenow-2', closureType: 'close-by-user' },
- }));
- const wrapper = mount(, { wrappingComponent: TestProviders });
- // Change closure type
- wrapper.find('input[id="close-by-pushing"]').simulate('change');
- wrapper.update();
-
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeTruthy();
-
- // Press add connector button
- wrapper
- .find('button[data-test-subj="case-configure-add-connector-button"]')
- .simulate('click');
- wrapper.update();
-
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeFalsy();
-
- expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(true);
-
- // Close the add flyout
- wrapper.find('button[data-test-subj="euiFlyoutCloseButton"]').simulate('click');
- wrapper.update();
-
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeTruthy();
-
- expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(false);
-
- expect(
- wrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]')
- .first()
- .text()
- ).toBe('1 unsaved changes');
- });
-
- test('it close and restores the action bar when the update connector button is pressed', () => {
+ test('the text of the update button is changed successfully', () => {
useCaseConfigureMock
.mockImplementationOnce(() => ({
...useCaseConfigureResponse,
- mapping: connectors[1].config.casesConfiguration.mapping,
- closureType: 'close-by-user',
- connectorId: 'servicenow-2',
- currentConfiguration: { connectorId: 'servicenow-2', closureType: 'close-by-user' },
+ connectorId: 'servicenow-1',
}))
.mockImplementation(() => ({
...useCaseConfigureResponse,
- mapping: connectors[1].config.casesConfiguration.mapping,
- closureType: 'close-by-pushing',
connectorId: 'servicenow-2',
- currentConfiguration: { connectorId: 'servicenow-2', closureType: 'close-by-user' },
}));
- const wrapper = mount(, { wrappingComponent: TestProviders });
-
- // Change closure type
- wrapper.find('input[id="close-by-pushing"]').simulate('change');
- wrapper.update();
-
- // Press update connector button
- wrapper
- .find('button[data-test-subj="case-configure-update-selected-connector-button"]')
- .simulate('click');
- wrapper.update();
-
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeFalsy();
-
- expect(wrapper.find(ConnectorEditFlyout).prop('editFlyoutVisible')).toBe(true);
-
- // Close the edit flyout
- wrapper.find('button[data-test-subj="euiFlyoutCloseButton"]').simulate('click');
- wrapper.update();
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeTruthy();
-
- expect(wrapper.find(ConnectorEditFlyout).prop('editFlyoutVisible')).toBe(false);
-
- expect(
- wrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]')
- .first()
- .text()
- ).toBe('1 unsaved changes');
- });
+ wrapper = mount(, { wrappingComponent: TestProviders });
- test('it shows the action bar when the connector is changed', () => {
- useCaseConfigureMock
- .mockImplementationOnce(() => ({
- ...useCaseConfigureResponse,
- mapping: connectors[0].config.casesConfiguration.mapping,
- closureType: 'close-by-user',
- connectorId: 'servicenow-1',
- currentConfiguration: { connectorId: 'servicenow-1', closureType: 'close-by-user' },
- }))
- .mockImplementation(() => ({
- ...useCaseConfigureResponse,
- mapping: connectors[1].config.casesConfiguration.mapping,
- closureType: 'close-by-user',
- connectorId: 'servicenow-2',
- currentConfiguration: { connectorId: 'servicenow-1', closureType: 'close-by-user' },
- }));
- 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('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeTruthy();
expect(
wrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]')
- .first()
+ .find('button[data-test-subj="case-configure-update-selected-connector-button"]')
.text()
- ).toBe('1 unsaved changes');
+ ).toBe('Update My Connector 2');
});
+ });
+});
- test('it closes the action bar when pressing save', () => {
- useCaseConfigureMock
- .mockImplementationOnce(() => ({
- ...useCaseConfigureResponse,
- mapping: connectors[1].config.casesConfiguration.mapping,
- closureType: 'close-by-user',
- connectorId: 'servicenow-2',
- currentConfiguration: { connectorId: 'servicenow-2', closureType: 'close-by-user' },
- }))
- .mockImplementation(() => ({
- ...useCaseConfigureResponse,
- mapping: connectors[1].config.casesConfiguration.mapping,
- closureType: 'close-by-pushing',
- connectorId: 'servicenow-2',
- currentConfiguration: { connectorId: 'servicenow-2', closureType: 'close-by-user' },
- }));
- const wrapper = mount(, { wrappingComponent: TestProviders });
- wrapper.find('input[id="close-by-pushing"]').simulate('change');
- wrapper.update();
-
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeTruthy();
-
- wrapper
- .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]')
- .first()
- .simulate('click');
+describe('closure options', () => {
+ let wrapper: ReactWrapper;
+ const persistCaseConfigure = jest.fn();
+
+ beforeEach(() => {
+ jest.resetAllMocks();
+ useCaseConfigureMock.mockImplementation(() => ({
+ ...useCaseConfigureResponse,
+ mapping: connectors[0].config.casesConfiguration.mapping,
+ closureType: 'close-by-user',
+ connectorId: 'servicenow-1',
+ connectorName: 'My connector',
+ currentConfiguration: {
+ connectorName: 'My connector',
+ connectorId: 'My connector',
+ closureType: 'close-by-user',
+ },
+ persistCaseConfigure,
+ }));
+ useConnectorsMock.mockImplementation(() => useConnectorsResponse);
+ useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs);
+ useGetUrlSearchMock.mockImplementation(() => searchURL);
+
+ wrapper = mount(, { wrappingComponent: TestProviders });
+ });
- wrapper.update();
+ test('it submits the configuration correctly when changing closure type', () => {
+ wrapper.find('input[id="close-by-pushing"]').simulate('change');
+ wrapper.update();
- expect(
- wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists()
- ).toBeFalsy();
+ expect(persistCaseConfigure).toHaveBeenCalled();
+ expect(persistCaseConfigure).toHaveBeenCalledWith({
+ connectorId: 'servicenow-1',
+ connectorName: 'My Connector',
+ closureType: 'close-by-pushing',
});
+ });
+});
- test('the text of the update button is changed successfully', () => {
- useCaseConfigureMock
- .mockImplementationOnce(() => ({
- ...useCaseConfigureResponse,
- connectorId: 'servicenow-1',
- }))
- .mockImplementation(() => ({
- ...useCaseConfigureResponse,
- connectorId: 'servicenow-2',
- }));
+describe('user interactions', () => {
+ beforeEach(() => {
+ jest.resetAllMocks();
+ useCaseConfigureMock.mockImplementation(() => ({
+ ...useCaseConfigureResponse,
+ mapping: connectors[1].config.casesConfiguration.mapping,
+ closureType: 'close-by-user',
+ connectorId: 'servicenow-2',
+ connectorName: 'unchanged',
+ currentConfiguration: {
+ connectorName: 'unchanged',
+ connectorId: 'servicenow-2',
+ closureType: 'close-by-user',
+ },
+ }));
+ useConnectorsMock.mockImplementation(() => useConnectorsResponse);
+ useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs);
+ useGetUrlSearchMock.mockImplementation(() => searchURL);
+ });
- const wrapper = mount(, { wrappingComponent: TestProviders });
+ test('it show the add flyout when pressing the add connector button', () => {
+ 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-add-connector"]').simulate('click');
+ wrapper.update();
- 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(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(true);
+ });
- expect(
- wrapper
- .find('button[data-test-subj="case-configure-update-selected-connector-button"]')
- .text()
- ).toBe('Update My Connector 2');
- });
+ test('it show the edit flyout when pressing the update connector button', () => {
+ const wrapper = mount(, { wrappingComponent: TestProviders });
+ wrapper
+ .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('[data-test-subj="case-configure-action-bottom-bar"]').exists()
+ ).toBeFalsy();
});
});
diff --git a/x-pack/plugins/siem/public/cases/components/configure_cases/index.tsx b/x-pack/plugins/siem/public/cases/components/configure_cases/index.tsx
index d5c6cc671433b..e6fbc7cd3e4db 100644
--- a/x-pack/plugins/siem/public/cases/components/configure_cases/index.tsx
+++ b/x-pack/plugins/siem/public/cases/components/configure_cases/index.tsx
@@ -7,16 +7,8 @@
import React, { useCallback, useEffect, useState, Dispatch, SetStateAction } from 'react';
import styled, { css } from 'styled-components';
-import {
- EuiFlexGroup,
- EuiFlexItem,
- EuiButton,
- EuiCallOut,
- EuiBottomBar,
- EuiButtonEmpty,
- EuiText,
-} from '@elastic/eui';
-import { difference } from 'lodash/fp';
+import { EuiCallOut } from '@elastic/eui';
+
import { useKibana } from '../../../common/lib/kibana';
import { useConnectors } from '../../containers/configure/use_connectors';
import { useCaseConfigure } from '../../containers/configure/use_configure';
@@ -27,16 +19,15 @@ import {
ConnectorEditFlyout,
} from '../../../../../triggers_actions_ui/public';
+import { ClosureType } from '../../containers/configure/types';
+
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { ActionConnectorTableItem } from '../../../../../triggers_actions_ui/public/types';
-import { getCaseUrl } from '../../../common/components/link_to';
-import { useGetUrlSearch } from '../../../common/components/navigation/use_get_url_search';
import { connectorsConfiguration } from '../../../common/lib/connectors/config';
import { Connectors } from './connectors';
import { ClosureOptions } from './closure_options';
import { SectionWrapper } from '../wrappers';
-import { navTabs } from '../../../app/home/home_navigations';
import * as i18n from './translations';
const FormWrapper = styled.div`
@@ -61,7 +52,6 @@ interface ConfigureCasesComponentProps {
}
const ConfigureCasesComponent: React.FC = ({ userCanCrud }) => {
- const search = useGetUrlSearch(navTabs.case);
const { http, triggers_actions_ui, notifications, application, docLinks } = useKibana().services;
const [connectorIsValid, setConnectorIsValid] = useState(true);
@@ -71,15 +61,13 @@ const ConfigureCasesComponent: React.FC = ({ userC
null
);
- const [actionBarVisible, setActionBarVisible] = useState(false);
- const [totalConfigurationChanges, setTotalConfigurationChanges] = useState(0);
-
const {
connectorId,
closureType,
currentConfiguration,
loading: loadingCaseConfigure,
persistLoading,
+ version,
persistCaseConfigure,
setConnector,
setClosureType,
@@ -93,45 +81,12 @@ const ConfigureCasesComponent: React.FC = ({ userC
const isLoadingAny = isLoadingConnectors || persistLoading || loadingCaseConfigure;
const updateConnectorDisabled = isLoadingAny || !connectorIsValid || connectorId === 'none';
- const handleSubmit = useCallback(
- // TO DO give a warning/error to user when field are not mapped so they have chance to do it
- () => {
- setActionBarVisible(false);
- persistCaseConfigure({
- connectorId,
- connectorName: connectors.find(c => c.id === connectorId)?.name ?? '',
- closureType,
- });
- },
- [connectorId, connectors, closureType]
- );
-
- const onClickAddConnector = useCallback(() => {
- setActionBarVisible(false);
- setAddFlyoutVisibility(true);
- }, []);
-
const onClickUpdateConnector = useCallback(() => {
- setActionBarVisible(false);
setEditFlyoutVisibility(true);
}, []);
- const handleActionBar = useCallback(() => {
- const currentConfigurationMinusName = {
- connectorId: currentConfiguration.connectorId,
- closureType: currentConfiguration.closureType,
- };
- const unsavedChanges = difference(Object.values(currentConfigurationMinusName), [
- connectorId,
- closureType,
- ]).length;
- setActionBarVisible(!(unsavedChanges === 0));
- setTotalConfigurationChanges(unsavedChanges);
- }, [currentConfiguration, connectorId, closureType]);
-
const handleSetAddFlyoutVisibility = useCallback(
(isVisible: boolean) => {
- handleActionBar();
setAddFlyoutVisibility(isVisible);
},
[currentConfiguration, connectorId, closureType]
@@ -139,12 +94,40 @@ const ConfigureCasesComponent: React.FC = ({ userC
const handleSetEditFlyoutVisibility = useCallback(
(isVisible: boolean) => {
- handleActionBar();
setEditFlyoutVisibility(isVisible);
},
[currentConfiguration, connectorId, closureType]
);
+ const onChangeConnector = useCallback(
+ (id: string) => {
+ if (id === 'add-connector') {
+ setAddFlyoutVisibility(true);
+ return;
+ }
+
+ setConnector(id);
+ persistCaseConfigure({
+ connectorId: id,
+ connectorName: connectors.find(c => c.id === id)?.name ?? '',
+ closureType,
+ });
+ },
+ [connectorId, closureType, version]
+ );
+
+ const onChangeClosureType = useCallback(
+ (type: ClosureType) => {
+ setClosureType(type);
+ persistCaseConfigure({
+ connectorId,
+ connectorName: connectors.find(c => c.id === connectorId)?.name ?? '',
+ closureType: type,
+ });
+ },
+ [connectorId, closureType, version]
+ );
+
useEffect(() => {
if (
!isLoadingConnectors &&
@@ -168,16 +151,6 @@ const ConfigureCasesComponent: React.FC = ({ userC
}
}, [connectors, connectorId]);
- useEffect(() => {
- handleActionBar();
- }, [
- connectors,
- connectorId,
- closureType,
- currentConfiguration.connectorId,
- currentConfiguration.closureType,
- ]);
-
return (
{!connectorIsValid && (
@@ -195,8 +168,8 @@ const ConfigureCasesComponent: React.FC = ({ userC
@@ -204,57 +177,12 @@ const ConfigureCasesComponent: React.FC = ({ userC
connectors={connectors ?? []}
disabled={persistLoading || isLoadingConnectors || !userCanCrud}
isLoading={isLoadingConnectors}
- onChangeConnector={setConnector}
+ onChangeConnector={onChangeConnector}
updateConnectorDisabled={updateConnectorDisabled || !userCanCrud}
- handleShowAddFlyout={onClickAddConnector}
handleShowEditFlyout={onClickUpdateConnector}
selectedConnector={connectorId}
/>
- {actionBarVisible && (
-
-
-
-
-
- {i18n.UNSAVED_CHANGES(totalConfigurationChanges)}
-
-
-
-
-
-
-
- {i18n.CANCEL}
-
-
-
-
- {i18n.SAVE_CHANGES}
-
-
-
-
-
-
- )}
{
defaultMessage: 'Update { connectorName }',
});
};
-
-export const UNSAVED_CHANGES = (unsavedChanges: number): string => {
- return i18n.translate('xpack.siem.case.configureCases.unsavedChanges', {
- values: { unsavedChanges },
- defaultMessage: '{unsavedChanges} unsaved changes',
- });
-};
diff --git a/x-pack/plugins/siem/public/cases/components/edit_connector/index.test.tsx b/x-pack/plugins/siem/public/cases/components/edit_connector/index.test.tsx
index 5dfed80baa8ed..8fada565b3463 100644
--- a/x-pack/plugins/siem/public/cases/components/edit_connector/index.test.tsx
+++ b/x-pack/plugins/siem/public/cases/components/edit_connector/index.test.tsx
@@ -40,23 +40,17 @@ describe('EditConnector ', () => {
);
- expect(
- wrapper
- .find(`[data-test-subj="dropdown-connectors"]`)
- .last()
- .prop('disabled')
- ).toBeTruthy();
-
expect(
wrapper
.find(`span[data-test-subj="dropdown-connector-no-connector"]`)
.last()
.exists()
).toBeTruthy();
- wrapper
- .find(`[data-test-subj="connector-edit-button"]`)
- .last()
- .simulate('click');
+
+ 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
@@ -64,30 +58,27 @@ describe('EditConnector ', () => {
.last()
.exists()
).toBeTruthy();
-
- expect(
- wrapper
- .find(`[data-test-subj="dropdown-connectors"]`)
- .last()
- .prop('disabled')
- ).toBeFalsy();
});
+
it('Edit external service on submit', async () => {
const wrapper = mount(
);
- wrapper
- .find(`[data-test-subj="connector-edit-button"]`)
- .last()
- .simulate('click');
+
+ 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(`[data-test-subj="edit-connectors-submit"]`)
.last()
.exists()
).toBeTruthy();
+
await act(async () => {
wrapper
.find(`[data-test-subj="edit-connectors-submit"]`)
@@ -97,6 +88,7 @@ describe('EditConnector ', () => {
expect(onSubmit).toBeCalledWith(sampleConnector);
});
});
+
it('Resets selector on cancel', async () => {
const props = {
...defaultProps,
@@ -106,10 +98,12 @@ describe('EditConnector ', () => {
);
- wrapper
- .find(`[data-test-subj="connector-edit-button"]`)
- .last()
- .simulate('click');
+
+ 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();
+
await act(async () => {
wrapper
.find(`[data-test-subj="edit-connectors-cancel"]`)
@@ -123,20 +117,7 @@ describe('EditConnector ', () => {
);
});
});
- it('Renders disabled button', () => {
- const props = { ...defaultProps, disabled: true };
- const wrapper = mount(
-
-
-
- );
- expect(
- wrapper
- .find(`[data-test-subj="connector-edit-button"]`)
- .last()
- .prop('disabled')
- ).toBeTruthy();
- });
+
it('Renders loading spinner', () => {
const props = { ...defaultProps, isLoading: true };
const wrapper = mount(
diff --git a/x-pack/plugins/siem/public/cases/components/edit_connector/index.tsx b/x-pack/plugins/siem/public/cases/components/edit_connector/index.tsx
index 29f06532a4ab4..38062b8837054 100644
--- a/x-pack/plugins/siem/public/cases/components/edit_connector/index.tsx
+++ b/x-pack/plugins/siem/public/cases/components/edit_connector/index.tsx
@@ -12,7 +12,6 @@ import {
EuiFlexItem,
EuiButton,
EuiButtonEmpty,
- EuiButtonIcon,
EuiLoadingSpinner,
} from '@elastic/eui';
import styled, { css } from 'styled-components';
@@ -52,21 +51,24 @@ export const EditConnector = React.memo(
options: { stripEmptyFields: false },
schema,
});
- const [isEditConnector, setIsEditConnector] = useState(false);
- const handleOnClick = useCallback(() => {
- setIsEditConnector(true);
- }, []);
+ const [connectorHasChanged, setConnectorHasChanged] = useState(false);
+ const onChangeConnector = useCallback(
+ connectorId => {
+ setConnectorHasChanged(selectedConnector !== connectorId);
+ },
+ [selectedConnector]
+ );
const onCancelConnector = useCallback(() => {
form.setFieldValue('connector', selectedConnector);
- setIsEditConnector(false);
+ setConnectorHasChanged(false);
}, [form, selectedConnector]);
const onSubmitConnector = useCallback(async () => {
const { isValid, data: newData } = await form.submit();
if (isValid && newData.connector) {
onSubmit(newData.connector);
- setIsEditConnector(false);
+ setConnectorHasChanged(false);
}
}, [form, onSubmit]);
return (
@@ -76,17 +78,6 @@ export const EditConnector = React.memo(
{i18n.CONNECTORS}
{isLoading && }
- {!isLoading && (
-
-
-
- )}
@@ -103,15 +94,16 @@ export const EditConnector = React.memo(
dataTestSubj: 'caseConnectors',
idAria: 'caseConnectors',
isLoading,
- disabled: !isEditConnector,
+ disabled,
defaultValue: selectedConnector,
}}
+ onChange={onChangeConnector}
/>
- {isEditConnector && (
+ {connectorHasChanged && (
diff --git a/x-pack/plugins/siem/public/cases/components/use_push_to_service/index.tsx b/x-pack/plugins/siem/public/cases/components/use_push_to_service/index.tsx
index ae8a67b75d36c..5d238b623eb4a 100644
--- a/x-pack/plugins/siem/public/cases/components/use_push_to_service/index.tsx
+++ b/x-pack/plugins/siem/public/cases/components/use_push_to_service/index.tsx
@@ -67,7 +67,11 @@ export const usePushToService = ({
}, [caseId, caseServices, caseConnectorId, caseConnectorName, postPushToService, updateCase]);
const errorsMsg = useMemo(() => {
- let errors: Array<{ title: string; description: JSX.Element }> = [];
+ let errors: Array<{
+ title: string;
+ description: JSX.Element;
+ errorType?: 'primary' | 'success' | 'warning' | 'danger';
+ }> = [];
if (actionLicense != null && !actionLicense.enabledInLicense) {
errors = [...errors, getLicenseError()];
}
@@ -115,6 +119,7 @@ export const usePushToService = ({
id="xpack.siem.case.caseView.pushToServiceDisableByInvalidConnector"
/>
),
+ errorType: 'danger',
},
];
}
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 219e922a0158c..da47e42ea02a6 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -13152,7 +13152,6 @@
"xpack.siem.case.configureCases.incidentManagementSystemLabel": "インシデント管理システム",
"xpack.siem.case.configureCases.incidentManagementSystemTitle": "サードパーティのインシデント管理システムに接続",
"xpack.siem.case.configureCases.noConnector": "コネクターを選択していません",
- "xpack.siem.case.configureCases.saveChangesButton": "変更を保存",
"xpack.siem.case.configureCases.updateConnector": "コネクターを更新",
"xpack.siem.case.configureCases.warningMessage": "構成が無効のようです。選択したコネクターが見つかりませんコネクターを削除しましたか?",
"xpack.siem.case.configureCases.warningTitle": "警告",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 954162647bf83..3d96a0ebe0a3f 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -13159,7 +13159,6 @@
"xpack.siem.case.configureCases.incidentManagementSystemLabel": "事件管理系统",
"xpack.siem.case.configureCases.incidentManagementSystemTitle": "连接到第三方事件管理系统",
"xpack.siem.case.configureCases.noConnector": "未选择连接器",
- "xpack.siem.case.configureCases.saveChangesButton": "保存更改",
"xpack.siem.case.configureCases.updateConnector": "更新连接器",
"xpack.siem.case.configureCases.warningMessage": "配置似乎无效。选择的连接器缺失。您是否已删除该连接器?",
"xpack.siem.case.configureCases.warningTitle": "警告",