Skip to content

Commit

Permalink
[ResponseOps][Cases]Add instructions of how to create a connector in …
Browse files Browse the repository at this point in the history
…the create case form (elastic#197041)

Closes elastic#189246

## Summary

- A helper text was added in the create case form to tell the user that
needs to create a connector in the stack management > cases > settings
before attaching it to a case
- A new "add connector" button was placed in the stack management >
cases > settings page, in the connectors section



https://github.com/user-attachments/assets/7866b41a-11b5-4ca3-bd65-988412ab1e2f

---------

Co-authored-by: Antonio <[email protected]>
  • Loading branch information
georgianaonoleata1904 and adcoelho authored Oct 28, 2024
1 parent 73c22a5 commit a904803
Show file tree
Hide file tree
Showing 11 changed files with 69 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,20 @@ import {
import { ConnectorsDropdown } from './connectors_dropdown';
import { connectors, actionTypes } from './__mock__';
import { ConnectorTypes } from '../../../common/types/domain';
import userEvent from '@testing-library/user-event';
import { useApplicationCapabilities } from '../../common/lib/kibana';

const useApplicationCapabilitiesMock = useApplicationCapabilities as jest.Mocked<
typeof useApplicationCapabilities
>;
jest.mock('../../common/lib/kibana');

describe('Connectors', () => {
let wrapper: ReactWrapper;
let appMockRender: AppMockRenderer;
const onChangeConnector = jest.fn();
const handleShowEditFlyout = jest.fn();
const onAddNewConnector = jest.fn();

const props: Props = {
actionTypes,
Expand All @@ -38,6 +46,7 @@ describe('Connectors', () => {
onChangeConnector,
selectedConnector: { id: 'none', type: ConnectorTypes.none },
updateConnectorDisabled: false,
onAddNewConnector,
};

beforeAll(() => {
Expand Down Expand Up @@ -104,12 +113,16 @@ describe('Connectors', () => {
});

it('shows the add connector button', () => {
wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click');
wrapper.update();
appMockRender.render(<Connectors {...props} />);

expect(
wrapper.find('button[data-test-subj="dropdown-connector-add-connector"]').exists()
).toBeTruthy();
expect(screen.getByTestId('add-new-connector')).toBeInTheDocument();
});

it('shows the add connector flyout when the button is clicked', async () => {
appMockRender.render(<Connectors {...props} />);

await userEvent.click(await screen.findByTestId('add-new-connector'));
expect(onAddNewConnector).toHaveBeenCalled();
});

it('the text of the update button is shown correctly', () => {
Expand Down Expand Up @@ -156,16 +169,14 @@ describe('Connectors', () => {
});

it('shows the actions permission message if the user does not have read access to actions', async () => {
appMockRender.coreStart.application.capabilities = {
...appMockRender.coreStart.application.capabilities,
actions: { save: false, show: false },
};
useApplicationCapabilitiesMock().actions = { crud: false, read: false };

appMockRender.render(<Connectors {...props} />);

const result = appMockRender.render(<Connectors {...props} />);
expect(
result.getByTestId('configure-case-connector-permissions-error-msg')
await screen.findByTestId('configure-case-connector-permissions-error-msg')
).toBeInTheDocument();
expect(result.queryByTestId('case-connectors-dropdown')).toBe(null);
expect(screen.queryByTestId('case-connectors-dropdown')).not.toBeInTheDocument();
});

it('shows the actions permission message if the user does not have access to case connector', async () => {
Expand All @@ -177,4 +188,12 @@ describe('Connectors', () => {
).toBeInTheDocument();
expect(result.queryByTestId('case-connectors-dropdown')).toBe(null);
});

it('it should hide the "Add Connector" button when the user lacks the capability to add a new connector', () => {
useApplicationCapabilitiesMock().actions = { crud: false, read: true };

appMockRender.render(<Connectors {...props} />);

expect(screen.queryByTestId('add-new-connector')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ import {
EuiFlexItem,
EuiLink,
EuiText,
EuiButtonEmpty,
} from '@elastic/eui';

import { css } from '@emotion/react';

import { ConnectorsDropdown } from './connectors_dropdown';
import * as i18n from './translations';

Expand All @@ -39,6 +38,7 @@ export interface Props {
onChangeConnector: (id: string) => void;
selectedConnector: { id: string; type: ConnectorTypes };
updateConnectorDisabled: boolean;
onAddNewConnector: () => void;
}
const ConnectorsComponent: React.FC<Props> = ({
actionTypes,
Expand All @@ -50,8 +50,10 @@ const ConnectorsComponent: React.FC<Props> = ({
onChangeConnector,
selectedConnector,
updateConnectorDisabled,
onAddNewConnector,
}) => {
const { actions } = useApplicationCapabilities();
const canSave = actions.crud;
const connector = useMemo(
() => connectors.find((c) => c.id === selectedConnector.id),
[connectors, selectedConnector.id]
Expand Down Expand Up @@ -95,13 +97,19 @@ const ConnectorsComponent: React.FC<Props> = ({
>
<EuiFormRow
fullWidth
css={css`
label {
width: 100%;
}
`}
label={dropDownLabel}
data-test-subj="case-connectors-form-row"
labelAppend={
canSave ? (
<EuiButtonEmpty
size="xs"
data-test-subj="add-new-connector"
onClick={onAddNewConnector}
>
{i18n.ADD_CONNECTOR}
</EuiButtonEmpty>
) : null
}
>
<EuiFlexGroup direction="column">
<EuiFlexItem grow={false}>
Expand All @@ -113,7 +121,6 @@ const ConnectorsComponent: React.FC<Props> = ({
isLoading={isLoading}
onChange={onChangeConnector}
data-test-subj="case-connectors-dropdown"
appendAddConnectorButton={true}
/>
) : (
<EuiText data-test-subj="configure-case-connector-permissions-error-msg" size="s">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@ import type { Props } from './connectors_dropdown';
import { ConnectorsDropdown } from './connectors_dropdown';
import { TestProviders } from '../../common/mock';
import { connectors } from './__mock__';
import userEvent from '@testing-library/user-event';
import { useApplicationCapabilities } from '../../common/lib/kibana';

const useApplicationCapabilitiesMock = useApplicationCapabilities as jest.Mocked<
typeof useApplicationCapabilities
>;
jest.mock('../../common/lib/kibana');

describe('ConnectorsDropdown', () => {
let wrapper: ReactWrapper;
Expand Down Expand Up @@ -388,23 +381,4 @@ describe('ConnectorsDropdown', () => {
);
expect(tooltips[0]).toBeInTheDocument();
});

test('it should hide the "Add New Connector" button when the user lacks the capability to add a new connector', async () => {
const selectedConnector = 'none';
useApplicationCapabilitiesMock().actions = { crud: false, read: true };
render(
<ConnectorsDropdown
appendAddConnectorButton={true}
connectors={[]}
selectedConnector={selectedConnector}
disabled={false}
isLoading={false}
onChange={() => {}}
/>,
{ wrapper: ({ children }) => <TestProviders>{children}</TestProviders> }
);

await userEvent.click(screen.getByTestId('dropdown-connectors'));
expect(screen.queryByTestId('dropdown-connector-add-connector')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/

import React, { Suspense, useMemo } from 'react';
import type { EuiThemeComputed } from '@elastic/eui';
import {
EuiFlexGroup,
EuiFlexItem,
Expand All @@ -20,7 +19,7 @@ import { css } from '@emotion/react';

import type { ActionConnector } from '../../containers/configure/types';
import * as i18n from './translations';
import { useApplicationCapabilities, useKibana } from '../../common/lib/kibana';
import { useKibana } from '../../common/lib/kibana';
import { getConnectorIcon, isDeprecatedConnector } from '../utils';

export interface Props {
Expand All @@ -29,7 +28,6 @@ export interface Props {
isLoading: boolean;
onChange: (id: string) => void;
selectedConnector: string;
appendAddConnectorButton?: boolean;
}

const suspendedComponentWithProps = (ComponentToSuspend: React.ComponentType) => {
Expand Down Expand Up @@ -65,37 +63,14 @@ const noConnectorOption = {
'data-test-subj': 'dropdown-connector-no-connector',
};

const addNewConnector = (euiTheme: EuiThemeComputed<{}>) => ({
value: 'add-connector',
inputDisplay: (
<span
css={css`
font-size: ${euiTheme.font.scale.xs};
font-weight: ${euiTheme.font.weight.medium};
line-height: ${euiTheme.size.l};
&:hover {
text-decoration: underline;
}
`}
>
{i18n.ADD_NEW_CONNECTOR}
</span>
),
'data-test-subj': 'dropdown-connector-add-connector',
});

const ConnectorsDropdownComponent: React.FC<Props> = ({
connectors,
disabled,
isLoading,
onChange,
selectedConnector,
appendAddConnectorButton = false,
}) => {
const { triggersActionsUi } = useKibana().services;
const { actions } = useApplicationCapabilities();
const canSave = actions.crud;
const { euiTheme } = useEuiTheme();
const connectorsAsOptions = useMemo(() => {
const connectorsFormatted = connectors.reduce(
Expand Down Expand Up @@ -152,10 +127,6 @@ const ConnectorsDropdownComponent: React.FC<Props> = ({
[noConnectorOption]
);

if (appendAddConnectorButton && canSave) {
return [...connectorsFormatted, addNewConnector(euiTheme)];
}

return connectorsFormatted;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [connectors]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,8 +565,7 @@ describe('ConfigureCases', () => {
wrappingComponent: TestProviders as ComponentType<React.PropsWithChildren<{}>>,
});

wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click');
wrapper.find('button[data-test-subj="dropdown-connector-add-connector"]').simulate('click');
wrapper.find('button[data-test-subj="add-new-connector"]').simulate('click');

await waitFor(() => {
wrapper.update();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ export const ConfigureCases: React.FC = React.memo(() => {
[]
);

const onAddNewConnector = useCallback(() => {
setFlyOutVisibility({ type: 'addConnector', visible: true });
}, []);

const onChangeConnector = useCallback(
(id: string) => {
if (id === 'add-connector') {
Expand Down Expand Up @@ -577,6 +581,7 @@ export const ConfigureCases: React.FC = React.memo(() => {
onChangeConnector={onChangeConnector}
selectedConnector={connector}
updateConnectorDisabled={updateConnectorDisabled || !permissions.update}
onAddNewConnector={onAddNewConnector}
/>
</div>
<EuiSpacer size="xl" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export const ADD_NEW_CONNECTOR = i18n.translate('xpack.cases.configureCases.addN
defaultMessage: 'Add new connector',
});

export const ADD_CONNECTOR = i18n.translate('xpack.cases.configureCases.addConnector', {
defaultMessage: 'Add connector',
});

export const CASE_CLOSURE_OPTIONS_TITLE = i18n.translate(
'xpack.cases.configureCases.caseClosureOptionsTitle',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@ import { css } from '@emotion/react';

import type { FieldHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { getFieldValidityAndErrorMessage } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { i18n } from '@kbn/i18n';
import type { ActionConnector } from '../../../common/types/domain';
import { ConnectorsDropdown } from '../configure_cases/connectors_dropdown';

const ADD_CONNECTOR_HELPER_TEXT = i18n.translate(
'xpack.cases.connectorSelector.addConnectorHelperText',
{
defaultMessage: 'Go to Cases > Settings to add an external incident management system',
}
);

interface ConnectorSelectorProps {
connectors: ActionConnector[];
dataTestSubj: string;
Expand Down Expand Up @@ -60,7 +68,7 @@ export const ConnectorSelector = ({
describedByIds={idAria ? [idAria] : undefined}
error={errorMessage}
fullWidth
helpText={field.helpText}
helpText={ADD_CONNECTOR_HELPER_TEXT}
isInvalid={isInvalid}
label={field.label}
labelAppend={field.labelAppend}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ export default ({ getPageObject, getService }: FtrProviderContext) => {
});

it('opens and closes the connectors flyout correctly', async () => {
await common.clickAndValidate('dropdown-connectors', 'dropdown-connector-add-connector');
await common.clickAndValidate('dropdown-connector-add-connector', 'euiFlyoutCloseButton');
await common.clickAndValidate('add-new-connector', 'euiFlyoutCloseButton');
await testSubjects.click('euiFlyoutCloseButton');
expect(await testSubjects.exists('euiFlyoutCloseButton')).to.be(false);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ export default ({ getPageObject, getService }: FtrProviderContext) => {
});

it('opens and closes the connectors flyout correctly', async () => {
await common.clickAndValidate('dropdown-connectors', 'dropdown-connector-add-connector');
await common.clickAndValidate('dropdown-connector-add-connector', 'euiFlyoutCloseButton');
await common.clickAndValidate('add-new-connector', 'euiFlyoutCloseButton');
await testSubjects.click('euiFlyoutCloseButton');
expect(await testSubjects.exists('euiFlyoutCloseButton')).to.be(false);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ export default ({ getPageObject, getService }: FtrProviderContext) => {
});

it('opens and closes the connectors flyout correctly', async () => {
await common.clickAndValidate('dropdown-connectors', 'dropdown-connector-add-connector');
await common.clickAndValidate('dropdown-connector-add-connector', 'euiFlyoutCloseButton');
await common.clickAndValidate('add-new-connector', 'euiFlyoutCloseButton');
await testSubjects.click('euiFlyoutCloseButton');
expect(await testSubjects.exists('euiFlyoutCloseButton')).to.be(false);
});
Expand Down

0 comments on commit a904803

Please sign in to comment.