diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/config.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/config.test.ts index 26550f1732655..8830b2cc23c38 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/config.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/config.test.ts @@ -24,6 +24,7 @@ describe('config', () => { table: 'incident', useImportAPI: true, commentFieldKey: 'work_notes', + appId: '7148dbc91bf1f450ced060a7234bcb88', }); }); @@ -35,6 +36,7 @@ describe('config', () => { table: 'sn_si_incident', useImportAPI: true, commentFieldKey: 'work_notes', + appId: '2f0746801baeb01019ae54e4604bcb0f', }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/config.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/config.ts index ba29bcc39b25a..11f18f0407fdf 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/config.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/config.ts @@ -14,6 +14,9 @@ export const ServiceNowITSMActionTypeId = '.servicenow'; export const ServiceNowSIRActionTypeId = '.servicenow-sir'; export const ServiceNowITOMActionTypeId = '.servicenow-itom'; +const SN_ITSM_APP_ID = '7148dbc91bf1f450ced060a7234bcb88'; +const SN_SIR_APP_ID = '2f0746801baeb01019ae54e4604bcb0f'; + export const snExternalServiceConfig: SNProductsConfig = { '.servicenow': { importSetTable: 'x_elas2_inc_int_elastic_incident', @@ -21,6 +24,7 @@ export const snExternalServiceConfig: SNProductsConfig = { table: 'incident', useImportAPI: true, commentFieldKey: 'work_notes', + appId: SN_ITSM_APP_ID, }, '.servicenow-sir': { importSetTable: 'x_elas2_sir_int_elastic_si_incident', @@ -28,6 +32,7 @@ export const snExternalServiceConfig: SNProductsConfig = { table: 'sn_si_incident', useImportAPI: true, commentFieldKey: 'work_notes', + appId: SN_SIR_APP_ID, }, '.servicenow-itom': { importSetTable: 'x_elas2_inc_int_elastic_incident', diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts index 31af3781c6b04..352a0c22c7ec8 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts @@ -253,6 +253,7 @@ export interface SNProductsConfigValue { useImportAPI: boolean; importSetTable: string; commentFieldKey: string; + appId?: string; } export type SNProductsConfig = Record; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/application_required_callout.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/application_required_callout.test.tsx index 67c3238b04774..cf192305a14fb 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/application_required_callout.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/application_required_callout.test.tsx @@ -9,9 +9,11 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { ApplicationRequiredCallout } from './application_required_callout'; +const appId = 'test'; + describe('ApplicationRequiredCallout', () => { test('it renders the callout', () => { - render(); + render(); expect(screen.getByText('Elastic ServiceNow App not installed')).toBeInTheDocument(); expect( screen.getByText('Please go to the ServiceNow app store and install the application') @@ -19,12 +21,20 @@ describe('ApplicationRequiredCallout', () => { }); test('it renders the ServiceNow store button', () => { - render(); + render(); expect(screen.getByText('Visit ServiceNow app store')).toBeInTheDocument(); }); + it('should render with correct href for the ServiceNow store button', () => { + render(); + expect(screen.getByRole('link')).toHaveAttribute( + 'href', + 'https://store.servicenow.com/sn_appstore_store.do#!/store/application/test' + ); + }); + test('it renders an error message if provided', () => { - render(); + render(); expect(screen.getByText('Error message: Denied')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/application_required_callout.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/application_required_callout.tsx index 2faa5a9f4a5e0..462d68d50508d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/application_required_callout.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/application_required_callout.tsx @@ -25,10 +25,11 @@ const ERROR_MESSAGE = i18n.translate( ); interface Props { + appId: string; message?: string | null; } -const ApplicationRequiredCalloutComponent: React.FC = ({ message }) => { +const ApplicationRequiredCalloutComponent: React.FC = ({ appId, message }) => { return ( <> @@ -50,7 +51,7 @@ const ApplicationRequiredCalloutComponent: React.FC = ({ message }) => { {ERROR_MESSAGE}: {message}

)} - + diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/installation_callout.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/installation_callout.test.tsx index ee63a546e6aa1..9b3d00973cd6d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/installation_callout.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/installation_callout.test.tsx @@ -10,9 +10,11 @@ import { render, screen } from '@testing-library/react'; import { InstallationCallout } from './installation_callout'; +const appId = 'test'; + describe('DeprecatedCallout', () => { test('it renders correctly', () => { - render(); + render(); expect( screen.getByText( 'To use this connector, first install the Elastic app from the ServiceNow app store.' @@ -21,7 +23,15 @@ describe('DeprecatedCallout', () => { }); test('it renders the button', () => { - render(); + render(); expect(screen.getByRole('link')).toBeInTheDocument(); }); + + it('should render with correct href for the ServiceNow store button', () => { + render(); + expect(screen.getByRole('link')).toHaveAttribute( + 'href', + 'https://store.servicenow.com/sn_appstore_store.do#!/store/application/test' + ); + }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/installation_callout.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/installation_callout.tsx index 064207910568f..536cf8923abd1 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/installation_callout.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/installation_callout.tsx @@ -11,7 +11,11 @@ import { EuiSpacer, EuiCallOut } from '@elastic/eui'; import * as i18n from './translations'; import { SNStoreButton } from './sn_store_button'; -const InstallationCalloutComponent: React.FC = () => { +interface Props { + appId: string; +} + +const InstallationCalloutComponent: React.FC = ({ appId }) => { return ( <> @@ -22,7 +26,7 @@ const InstallationCalloutComponent: React.FC = () => { data-test-subj="snInstallationCallout" title={i18n.INSTALLATION_CALLOUT_TITLE} > - + diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_connectors.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_connectors.tsx index db3c32755f0ed..7c53d4322ddb9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_connectors.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_connectors.tsx @@ -20,6 +20,8 @@ import { InstallationCallout } from './installation_callout'; import { UpdateConnector } from './update_connector'; import { updateActionConnector } from '../../../lib/action_connector_api'; import { Credentials } from './credentials'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { snExternalServiceConfig } from '../../../../../../actions/server/builtin_action_types/servicenow/config'; const ServiceNowConnectorFields: React.FC> = ({ @@ -151,7 +153,9 @@ const ServiceNowConnectorFields: React.FC )} - {requiresNewApplication && } + {requiresNewApplication && ( + + )} {!requiresNewApplication && } {showApplicationRequiredCallout && requiresNewApplication && ( - + )} ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/sn_store_button.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/sn_store_button.test.tsx index 500325202b651..795101d9dbc59 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/sn_store_button.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/sn_store_button.test.tsx @@ -9,41 +9,49 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { SNStoreButton, SNStoreLink } from './sn_store_button'; +const appId = 'test'; + describe('SNStoreButton', () => { it('should render the button', () => { - render(); + render(); expect(screen.getByText('Visit ServiceNow app store')).toBeInTheDocument(); }); it('should render a danger button', () => { - render(); + render(); expect(screen.getByRole('link')).toHaveClass('euiButton--danger'); }); it('should render with correct href', () => { - render(); - expect(screen.getByRole('link')).toHaveAttribute('href', 'https://store.servicenow.com/'); + render(); + expect(screen.getByRole('link')).toHaveAttribute( + 'href', + 'https://store.servicenow.com/sn_appstore_store.do#!/store/application/test' + ); }); it('should render with target blank', () => { - render(); + render(); expect(screen.getByRole('link')).toHaveAttribute('target', '_blank'); }); }); describe('SNStoreLink', () => { it('should render the link', () => { - render(); + render(); expect(screen.getByText('Visit ServiceNow app store')).toBeInTheDocument(); }); it('should render with correct href', () => { - render(); - expect(screen.getByRole('link')).toHaveAttribute('href', 'https://store.servicenow.com/'); + render(); + expect(screen.getByRole('link')).toHaveAttribute( + 'href', + 'https://store.servicenow.com/sn_appstore_store.do#!/store/application/test' + ); }); it('should render with target blank', () => { - render(); + render(); expect(screen.getByRole('link')).toHaveAttribute('target', '_blank'); }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/sn_store_button.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/sn_store_button.tsx index 5a33237159a02..3cbec513d179c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/sn_store_button.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/sn_store_button.tsx @@ -10,15 +10,23 @@ import { EuiButtonProps, EuiButton, EuiLink } from '@elastic/eui'; import * as i18n from './translations'; -const STORE_URL = 'https://store.servicenow.com/'; +const getStoreURL = (appId: string): string => + `https://store.servicenow.com/sn_appstore_store.do#!/store/application/${appId}`; interface Props { + appId: string; color: EuiButtonProps['color']; } -const SNStoreButtonComponent: React.FC = ({ color }) => { +const SNStoreButtonComponent: React.FC = ({ color, appId }) => { return ( - + {i18n.VISIT_SN_STORE} ); @@ -26,8 +34,8 @@ const SNStoreButtonComponent: React.FC = ({ color }) => { export const SNStoreButton = memo(SNStoreButtonComponent); -const SNStoreLinkComponent: React.FC = () => ( - +const SNStoreLinkComponent: React.FC> = ({ appId }) => ( + {i18n.VISIT_SN_STORE} ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/update_connector.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/update_connector.tsx index 02127eb6ff4f0..f937b4e0a9be4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/update_connector.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/update_connector.tsx @@ -28,6 +28,8 @@ import { isFieldInvalid } from './helpers'; import { ApplicationRequiredCallout } from './application_required_callout'; import { SNStoreLink } from './sn_store_button'; import { CredentialsAuth } from './credentials_auth'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { snExternalServiceConfig } from '../../../../../../actions/server/builtin_action_types/servicenow/config'; const title = i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.serviceNow.updateFormTitle', @@ -140,7 +142,11 @@ const UpdateConnectorComponent: React.FC = ({ id="xpack.triggersActionsUI.components.builtinActionTypes.serviceNowAction.serviceNowAppRunning" defaultMessage="The Elastic App from the ServiceNow app store must be installed prior to running the update. {visitLink} to install the app" values={{ - visitLink: , + visitLink: ( + + ), }} /> ), @@ -175,7 +181,10 @@ const UpdateConnectorComponent: React.FC = ({ {applicationInfoErrorMsg && ( - + )}