Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cases] Show deprecated icon in connectors with isDeprecated true #132237

Merged
merged 10 commits into from
May 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions x-pack/plugins/actions/server/lib/is_conector_deprecated.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ describe('isConnectorDeprecated', () => {
isPreconfigured: false as const,
};

it('returns false if the config is not defined', () => {
// @ts-expect-error
expect(isConnectorDeprecated({})).toBe(false);
});

it('returns false if the connector is not ITSM or SecOps', () => {
expect(isConnectorDeprecated(connector)).toBe(false);
});
Expand Down Expand Up @@ -48,4 +53,24 @@ describe('isConnectorDeprecated', () => {
})
).toBe(true);
});

it('returns true if the connector is .servicenow and the usesTableApi is omitted', () => {
expect(
isConnectorDeprecated({
...connector,
actionTypeId: '.servicenow',
config: { apiUrl: 'http://example.com' },
})
).toBe(true);
});

it('returns true if the connector is .servicenow-sir and the usesTableApi is omitted', () => {
expect(
isConnectorDeprecated({
...connector,
actionTypeId: '.servicenow-sir',
config: { apiUrl: 'http://example.com' },
})
).toBe(true);
});
});
40 changes: 36 additions & 4 deletions x-pack/plugins/actions/server/lib/is_conector_deprecated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
* 2.0.
*/

import { isPlainObject } from 'lodash';
import { PreConfiguredAction, RawAction } from '../types';

export type ConnectorWithOptionalDeprecation = Omit<PreConfiguredAction, 'isDeprecated'> &
Pick<Partial<PreConfiguredAction>, 'isDeprecated'>;

const isObject = (obj: unknown): obj is Record<string, unknown> => isPlainObject(obj);

export const isConnectorDeprecated = (
connector: RawAction | ConnectorWithOptionalDeprecation
): boolean => {
Expand All @@ -18,11 +21,40 @@ export const isConnectorDeprecated = (
* Connectors after the Elastic ServiceNow application use the
* Import Set API (https://developer.servicenow.com/dev.do#!/reference/api/rome/rest/c_ImportSetAPI)
* A ServiceNow connector is considered deprecated if it uses the Table API.
*
* All other connectors do not have the usesTableApi config property
* so the function will always return false for them.
*/
return !!connector.config?.usesTableApi;

/**
* We cannot deduct if the connector is
* deprecated without config. In this case
* we always return false.
*/
if (!isObject(connector.config)) {
return false;
}

/**
* If the usesTableApi is not defined it means that the connector is created
* before the introduction of the usesTableApi property. In that case, the connector is assumed
* to be deprecated because all connectors prior 7.16 where using the Table API.
* Migrations x-pack/plugins/actions/server/saved_objects/actions_migrations.ts set
* the usesTableApi property to true to all connectors prior 7.16. Pre configured connectors
* cannot be migrated. This check ensures that pre configured connectors without the
* usesTableApi property explicitly in the kibana.yml file are considered deprecated.
* According to the schema defined here x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts
* if the property is not defined it will be set to true at the execution of the connector.
*/
if (!Object.hasOwn(connector.config, 'usesTableApi')) {
return true;
}

/**
* Connector created prior to 7.16 will be migrated to have the usesTableApi property set to true.
* Connectors created after 7.16 should have the usesTableApi property set to true or false.
* If the usesTableApi is omitted on an API call it will be defaulted to true. Check the schema
* here x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts.
* The !! is to make TS happy.
*/
return !!connector.config.usesTableApi;
}

return false;
Expand Down
10 changes: 9 additions & 1 deletion x-pack/plugins/cases/common/api/connectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@

import * as rt from 'io-ts';

import { ActionResult, ActionType } from '@kbn/actions-plugin/common';
import type { ActionType } from '@kbn/actions-plugin/common';
/**
* ActionResult type from the common folder is outdated.
* The type from server is not exported properly so we
* disable the linting for the moment
*/

// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import type { ActionResult } from '@kbn/actions-plugin/server/types';
import { JiraFieldsRT } from './jira';
import { ResilientFieldsRT } from './resilient';
import { ServiceNowITSMFieldsRT } from './servicenow_itsm';
Expand Down
5 changes: 5 additions & 0 deletions x-pack/plugins/cases/public/common/mock/connectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const connectorsMock: ActionConnector[] = [
apiUrl: 'https://instance1.service-now.com',
},
isPreconfigured: false,
isDeprecated: false,
},
{
id: 'resilient-2',
Expand All @@ -26,6 +27,7 @@ export const connectorsMock: ActionConnector[] = [
orgId: '201',
},
isPreconfigured: false,
isDeprecated: false,
},
{
id: 'jira-1',
Expand All @@ -35,6 +37,7 @@ export const connectorsMock: ActionConnector[] = [
apiUrl: 'https://instance.atlassian.ne',
},
isPreconfigured: false,
isDeprecated: false,
},
{
id: 'servicenow-sir',
Expand All @@ -44,6 +47,7 @@ export const connectorsMock: ActionConnector[] = [
apiUrl: 'https://instance1.service-now.com',
},
isPreconfigured: false,
isDeprecated: false,
},
{
id: 'servicenow-uses-table-api',
Expand All @@ -54,6 +58,7 @@ export const connectorsMock: ActionConnector[] = [
usesTableApi: true,
},
isPreconfigured: false,
isDeprecated: true,
},
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ describe('ExternalServiceColumn ', () => {
name: 'None',
config: {},
isPreconfigured: false,
isDeprecated: false,
},
]}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ describe('ConnectorsDropdown', () => {
name: 'None',
config: {},
isPreconfigured: false,
isDeprecated: false,
},
]}
/>,
Expand All @@ -269,4 +270,26 @@ describe('ConnectorsDropdown', () => {
);
expect(tooltips[0]).toBeInTheDocument();
});

test('it shows the deprecated tooltip when the connector is deprecated by configuration', () => {
const connector = connectors[0];
render(
<ConnectorsDropdown
{...props}
connectors={[
{
...connector,
isDeprecated: true,
},
]}
selectedConnector={connector.id}
/>,
{ wrapper: ({ children }) => <TestProviders>{children}</TestProviders> }
);

const tooltips = screen.getAllByText(
'This connector is deprecated. Update it, or create a new one.'
);
expect(tooltips[0]).toBeInTheDocument();
});
});
2 changes: 2 additions & 0 deletions x-pack/plugins/cases/public/components/connectors/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const connector = {
actionTypeId: '.jira',
config: {},
isPreconfigured: false,
isDeprecated: false,
};

export const swimlaneConnector = {
Expand All @@ -29,6 +30,7 @@ export const swimlaneConnector = {
},
},
isPreconfigured: false,
isDeprecated: false,
};

export const issues = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,18 @@ describe('ServiceNowITSM Fields', () => {
);
});

it('shows the deprecated callout when the connector uses the table API', async () => {
const tableApiConnector = { ...connector, config: { usesTableApi: true } };
it('shows the deprecated callout if the connector is deprecated', async () => {
const tableApiConnector = { ...connector, isDeprecated: true };
render(<Fields fields={fields} onChange={onChange} connector={tableApiConnector} />);
expect(screen.getByTestId('deprecated-connector-warning-callout')).toBeInTheDocument();
});

it('does not show the deprecated callout when the connector does not uses the table API', async () => {
it('does not show the deprecated callout when the connector is not deprecated', async () => {
render(<Fields fields={fields} onChange={onChange} connector={connector} />);
expect(screen.queryByTestId('deprecated-connector-warning-callout')).not.toBeInTheDocument();
});

it('does not show the deprecated callout when the connector is preconfigured', async () => {
it('does not show the deprecated callout when the connector is preconfigured and not deprecated', async () => {
render(
<Fields
fields={fields}
Expand All @@ -157,12 +157,15 @@ describe('ServiceNowITSM Fields', () => {
expect(screen.queryByTestId('deprecated-connector-warning-callout')).not.toBeInTheDocument();
});

it('does not show the deprecated callout when the config of the connector is undefined', async () => {
it('shows the deprecated callout when the connector is preconfigured and deprecated', async () => {
render(
// @ts-expect-error
<Fields fields={fields} onChange={onChange} connector={{ ...connector, config: undefined }} />
<Fields
fields={fields}
onChange={onChange}
connector={{ ...connector, isPreconfigured: true, isDeprecated: true }}
/>
);
expect(screen.queryByTestId('deprecated-connector-warning-callout')).not.toBeInTheDocument();
expect(screen.queryByTestId('deprecated-connector-warning-callout')).toBeInTheDocument();
});

it('should hide subcategory if selecting a category without subcategories', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { ConnectorCard } from '../card';
import { useGetChoices } from './use_get_choices';
import { Fields, Choice } from './types';
import { choicesToEuiOptions } from './helpers';
import { connectorValidator } from './validator';
import { DeprecatedCallout } from '../deprecated_callout';

const useGetChoicesFields = ['urgency', 'severity', 'impact', 'category', 'subcategory'];
Expand Down Expand Up @@ -44,7 +43,7 @@ const ServiceNowITSMFieldsComponent: React.FunctionComponent<
} = fields ?? {};
const { http, notifications } = useKibana().services;
const [choices, setChoices] = useState<Fields>(defaultFields);
const showConnectorWarning = useMemo(() => connectorValidator(connector) != null, [connector]);
const showConnectorWarning = connector.isDeprecated;

const categoryOptions = useMemo(
() => choicesToEuiOptions(choices.category),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,18 +169,18 @@ describe('ServiceNowSIR Fields', () => {
]);
});

test('it shows the deprecated callout when the connector uses the table API', async () => {
const tableApiConnector = { ...connector, config: { usesTableApi: true } };
test('shows the deprecated callout if the connector is deprecated', async () => {
const tableApiConnector = { ...connector, isDeprecated: true };
render(<Fields fields={fields} onChange={onChange} connector={tableApiConnector} />);
expect(screen.getByTestId('deprecated-connector-warning-callout')).toBeInTheDocument();
});

test('it does not show the deprecated callout when the connector does not uses the table API', async () => {
test('does not show the deprecated callout when the connector is not deprecated', async () => {
render(<Fields fields={fields} onChange={onChange} connector={connector} />);
expect(screen.queryByTestId('deprecated-connector-warning-callout')).not.toBeInTheDocument();
});

it('does not show the deprecated callout when the connector is preconfigured', async () => {
it('does not show the deprecated callout when the connector is preconfigured and not deprecated', async () => {
render(
<Fields
fields={fields}
Expand All @@ -191,12 +191,15 @@ describe('ServiceNowSIR Fields', () => {
expect(screen.queryByTestId('deprecated-connector-warning-callout')).not.toBeInTheDocument();
});

it('does not show the deprecated callout when the config of the connector is undefined', async () => {
it('shows the deprecated callout when the connector is preconfigured and deprecated', async () => {
render(
// @ts-expect-error
<Fields fields={fields} onChange={onChange} connector={{ ...connector, config: undefined }} />
<Fields
fields={fields}
onChange={onChange}
connector={{ ...connector, isPreconfigured: true, isDeprecated: true }}
/>
);
expect(screen.queryByTestId('deprecated-connector-warning-callout')).not.toBeInTheDocument();
expect(screen.queryByTestId('deprecated-connector-warning-callout')).toBeInTheDocument();
});

test('it should hide subcategory if selecting a category without subcategories', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { Choice, Fields } from './types';
import { choicesToEuiOptions } from './helpers';

import * as i18n from './translations';
import { connectorValidator } from './validator';
import { DeprecatedCallout } from '../deprecated_callout';

const useGetChoicesFields = ['category', 'subcategory', 'priority'];
Expand All @@ -43,7 +42,7 @@ const ServiceNowSIRFieldsComponent: React.FunctionComponent<

const { http, notifications } = useKibana().services;
const [choices, setChoices] = useState<Fields>(defaultFields);
const showConnectorWarning = useMemo(() => connectorValidator(connector) != null, [connector]);
const showConnectorWarning = connector.isDeprecated;

const onChangeCb = useCallback(
(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const connector = {
actionTypeId: '.servicenow',
name: 'ServiceNow',
isPreconfigured: false,
isDeprecated: false,
config: {
apiUrl: 'https://dev94428.service-now.com/',
},
Expand Down

This file was deleted.

Loading