Skip to content

Commit

Permalink
Removed filtering for Case owned ServiceNow actions from the Manageme…
Browse files Browse the repository at this point in the history
…nt UI and make it usable for Alerts. Added documentation. (#71579)

* Removed filtering for Case owned ServiceNow actions from the Management UI and make it usable for Alerts. Added documentation.

* extended docs

* Fixed docs

* fixed connector page

* Changed SN variables components

* Fixed issues

* fixed order

* Update docs/user/alerting/action-types/servicenow.asciidoc

Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>

* Update docs/user/alerting/action-types/servicenow.asciidoc

Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>

* Update docs/user/alerting/action-types/servicenow.asciidoc

Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>

* Update docs/user/alerting/action-types/servicenow.asciidoc

Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>

* Update docs/user/alerting/action-types/servicenow.asciidoc

Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>

* Update docs/user/alerting/action-types/servicenow.asciidoc

Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>

* Update docs/user/alerting/action-types/servicenow.asciidoc

Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>

* Update docs/user/alerting/action-types/servicenow.asciidoc

Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>

* -

* fixed tests

Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>
  • Loading branch information
YulNaumenko and gchaps authored Jul 15, 2020
1 parent 8ae6e4b commit 5c5d75f
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 109 deletions.
5 changes: 5 additions & 0 deletions docs/user/alerting/action-types.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ a| <<server-log-action-type, ServerLog>>

| Add a message to a Kibana log.

a| <<servicenow-action-type, ServiceNow>>

| Push or update data to a new incident in ServiceNow.

a| <<slack-action-type, Slack>>

| Send a message to a Slack channel or user.
Expand Down Expand Up @@ -55,3 +59,4 @@ include::action-types/server-log.asciidoc[]
include::action-types/slack.asciidoc[]
include::action-types/webhook.asciidoc[]
include::action-types/pre-configured-connectors.asciidoc[]
include::action-types/servicenow.asciidoc[]
72 changes: 72 additions & 0 deletions docs/user/alerting/action-types/servicenow.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
[role="xpack"]
[[servicenow-action-type]]
=== ServiceNow action

The ServiceNow action type uses the https://developer.servicenow.com/app.do#!/rest_api_doc?v=orlando&id=c_TableAPI[V2 Table API] to create ServiceNow incidents.

[float]
[[servicenow-connector-configuration]]
==== Connector configuration

ServiceNow connectors have the following configuration properties:

Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action.
URL:: ServiceNow instance URL.
Username:: Username for HTTP Basic authentication.
Password:: Password for HTTP Basic authentication.

[float]
[[Preconfigured-servicenow-configuration]]
==== Preconfigured action type

[source,text]
--
my-servicenow:
name: preconfigured-servicenow-action-type
actionTypeId: .servicenow
config:
apiUrl: https://dev94428.service-now.com/
secrets:
username: testuser
password: passwordkeystorevalue
--

`config` defines the action type specific to the configuration and contains the following properties:

[cols="2*<"]
|===

| `apiUrl`
| An address that corresponds to *Sender*.

|===

`secrets` defines sensitive information for the action type:

[cols="2*<"]
|===

| `username`
| A string that corresponds to *User*.

| `password`
| A string that corresponds to *Password*. Should be stored in the <<creating-keystore, {kib} keystore>>.

|===

[[servicenow-action-configuration]]
==== Action configuration

ServiceNow actions have the following configuration properties:

Urgency:: The extent to which the incident resolution can delay.
Severity:: The severity of the incident.
Impact:: The effect an incident has on business. Can be measured by the number of affected users or by how critical it is to the business in question.
Short description:: A short description of the incident, used for searching the contents of the knowledge base.
Description:: The details about the incident.
Additional comments:: Additional information for the client, such as how to troubleshoot the issue.

[[configuring-servicenow]]
==== Configuring and testing ServiceNow

ServiceNow offers free https://developer.servicenow.com/dev.do#!/guides/madrid/now-platform/pdi-guide/obtaining-a-pdi[Personal Developer Instances], which you can use to test incidents.
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('api', () => {
});

test('it calls createIncident correctly', async () => {
const params = { ...apiParams, externalId: null, comments: undefined };
const params = { ...apiParams, externalId: null, comments: [] };
await api.pushToService({
externalService,
mapping,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const pushToServiceHandler = async ({

let incident = {};
// TODO: should be removed later but currently keep it for the Case implementation support
if (mapping) {
if (mapping && Array.isArray(params.comments)) {
const fields = prepareFieldsForTransformation({
externalCase: params.externalObject,
mapping,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ describe('ServiceNowActionConnectorFields renders', () => {
editActionConfig={() => {}}
editActionSecrets={() => {}}
docLinks={deps!.docLinks}
consumer={'case'}
/>
);
expect(wrapper.find('[data-test-subj="case-servicenow-mappings"]').length > 0).toBeTruthy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import {
EuiFormRow,
EuiFieldPassword,
EuiSpacer,
EuiLink,
} from '@elastic/eui';

import { isEmpty } from 'lodash';
import { FormattedMessage } from '@kbn/i18n/react';
import { ActionConnectorFieldsProps } from '../../../../types';
import * as i18n from './translations';
import { ServiceNowActionConnector, CasesConfigurationMapping } from './types';
Expand All @@ -23,7 +25,7 @@ import { FieldMapping } from './case_mappings/field_mapping';

const ServiceNowConnectorFields: React.FC<ActionConnectorFieldsProps<
ServiceNowActionConnector
>> = ({ action, editActionSecrets, editActionConfig, errors, consumer }) => {
>> = ({ action, editActionSecrets, editActionConfig, errors, consumer, docLinks }) => {
// TODO: remove incidentConfiguration later, when Case ServiceNow will move their fields to the level of action execution
const { apiUrl, incidentConfiguration, isCaseOwned } = action.config;
const mapping = incidentConfiguration ? incidentConfiguration.mapping : [];
Expand Down Expand Up @@ -79,6 +81,17 @@ const ServiceNowConnectorFields: React.FC<ActionConnectorFieldsProps<
error={errors.apiUrl}
isInvalid={isApiUrlInvalid}
label={i18n.API_URL_LABEL}
helpText={
<EuiLink
href={`${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/servicenow-action-type.html#configuring-servicenow`}
target="_blank"
>
<FormattedMessage
id="xpack.triggersActionsUI.components.builtinActionTypes.serviceNowAction.apiUrlHelpLabel"
defaultMessage="Configure Personal Developer Instance for ServiceNow"
/>
</EuiLink>
}
>
<EuiFieldText
fullWidth
Expand Down Expand Up @@ -149,7 +162,7 @@ const ServiceNowConnectorFields: React.FC<ActionConnectorFieldsProps<
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
{isCaseOwned && ( // TODO: remove this block later, when Case ServiceNow will move their fields to the level of action execution
{consumer === 'case' && ( // TODO: remove this block later, when Case ServiceNow will move their fields to the level of action execution
<>
<EuiSpacer size="l" />
<EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('ServiceNowParamsFields renders', () => {
);
expect(wrapper.find('[data-test-subj="impactSelect"]').length > 0).toBeTruthy();
expect(wrapper.find('[data-test-subj="titleInput"]').length > 0).toBeTruthy();
expect(wrapper.find('[data-test-subj="incidentDescriptionTextArea"]').length > 0).toBeTruthy();
expect(wrapper.find('[data-test-subj="incidentCommentTextArea"]').length > 0).toBeTruthy();
expect(wrapper.find('[data-test-subj="descriptionTextArea"]').length > 0).toBeTruthy();
expect(wrapper.find('[data-test-subj="commentTextArea"]').length > 0).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
*/

import React, { Fragment, useEffect } from 'react';
import { EuiFormRow, EuiTextArea } from '@elastic/eui';
import { EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { EuiSelect } from '@elastic/eui';
import { EuiFlexGroup } from '@elastic/eui';
import { EuiFlexItem } from '@elastic/eui';
import { EuiFieldText } from '@elastic/eui';
import { EuiSpacer } from '@elastic/eui';
import { EuiTitle } from '@elastic/eui';
import { ActionParamsProps } from '../../../../types';
import { AddMessageVariables } from '../../add_message_variables';
import { ServiceNowActionParams } from './types';
import { TextAreaWithMessageVariables } from '../../text_area_with_message_variables';
import { TextFieldWithMessageVariables } from '../../text_field_with_message_variables';

const ServiceNowParamsFields: React.FunctionComponent<ActionParamsProps<
ServiceNowActionParams
Expand Down Expand Up @@ -76,13 +76,6 @@ const ServiceNowParamsFields: React.FunctionComponent<ActionParamsProps<
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [title, description, comment, severity, impact, urgency]);

const onSelectMessageVariable = (paramsProperty: string, variable: string) => {
editSubActionProperty(
paramsProperty,
((actionParams as any).subActionParams[paramsProperty] ?? '').concat(` {{${variable}}}`)
);
};

return (
<Fragment>
<EuiTitle size="s">
Expand Down Expand Up @@ -164,96 +157,44 @@ const ServiceNowParamsFields: React.FunctionComponent<ActionParamsProps<
defaultMessage: 'Short description',
}
)}
labelAppend={
<AddMessageVariables
messageVariables={messageVariables}
onSelectEventHandler={(variable: string) => onSelectMessageVariable('title', variable)}
paramsProperty="title"
/>
}
>
<EuiFieldText
fullWidth
name="title"
data-test-subj="titleInput"
isInvalid={errors.title.length > 0 && title !== undefined}
value={title || ''}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
editSubActionProperty('title', e.target.value);
}}
onBlur={() => {
if (!title) {
editSubActionProperty('title', '');
}
}}
<TextFieldWithMessageVariables
index={index}
editAction={editSubActionProperty}
messageVariables={messageVariables}
paramsProperty={'title'}
inputTargetValue={title}
errors={errors.title as string[]}
/>
</EuiFormRow>
<EuiFormRow
fullWidth
<TextAreaWithMessageVariables
index={index}
editAction={editSubActionProperty}
messageVariables={messageVariables}
paramsProperty={'description'}
inputTargetValue={description}
label={i18n.translate(
'xpack.triggersActionsUI.components.builtinActionTypes.serviceNow.descriptionTextAreaFieldLabel',
{
defaultMessage: 'Description (optional)',
}
)}
labelAppend={
<AddMessageVariables
messageVariables={messageVariables}
onSelectEventHandler={(variable: string) =>
onSelectMessageVariable('description', variable)
}
paramsProperty="description"
/>
}
>
<EuiTextArea
fullWidth
name="description"
value={description || ''}
data-test-subj="incidentDescriptionTextArea"
onChange={(e) => {
editSubActionProperty('description', e.target.value);
}}
onBlur={() => {
if (!description) {
editSubActionProperty('description', '');
}
}}
/>
</EuiFormRow>
<EuiFormRow
fullWidth
errors={errors.description as string[]}
/>
<TextAreaWithMessageVariables
index={index}
editAction={editSubActionProperty}
messageVariables={messageVariables}
paramsProperty={'comment'}
inputTargetValue={comment}
label={i18n.translate(
'xpack.triggersActionsUI.components.builtinActionTypes.serviceNow.commentsTextAreaFieldLabel',
{
defaultMessage: 'Additional comments (optional)',
}
)}
labelAppend={
<AddMessageVariables
messageVariables={messageVariables}
onSelectEventHandler={(variable: string) =>
onSelectMessageVariable('comment', variable)
}
paramsProperty="comment"
/>
}
>
<EuiTextArea
fullWidth
name="comment"
value={comment || ''}
data-test-subj="incidentCommentTextArea"
onChange={(e) => {
editSubActionProperty('comment', e.target.value);
}}
onBlur={() => {
if (!comment) {
editSubActionProperty('comment', '');
}
}}
/>
</EuiFormRow>
errors={errors.comment as string[]}
/>
</Fragment>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ import { TypeRegistry } from '../../type_registry';
import { actionTypeCompare } from '../../lib/action_type_compare';
import { checkActionFormActionTypeEnabled } from '../../lib/check_action_type_enabled';
import { VIEW_LICENSE_OPTIONS_LINK } from '../../../common/constants';
import { ServiceNowConnectorConfiguration } from '../../../common';

interface ActionAccordionFormProps {
actions: AlertAction[];
Expand Down Expand Up @@ -132,14 +131,7 @@ export const ActionForm = ({
try {
setIsLoadingConnectors(true);
const loadedConnectors = await loadConnectors({ http });
setConnectors(
loadedConnectors.filter(
(action) =>
action.actionTypeId !== ServiceNowConnectorConfiguration.id ||
(action.actionTypeId === ServiceNowConnectorConfiguration.id &&
!action.config.isCaseOwned)
)
);
setConnectors(loadedConnectors);
} catch (e) {
toastNotifications.addDanger({
title: i18n.translate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { ServiceNowConnectorConfiguration } from '../../../../common';
import { useAppDependencies } from '../../../app_context';
import { loadAllActions, loadActionTypes, deleteActions } from '../../../lib/action_connector_api';
import ConnectorAddFlyout from '../../action_connector_form/connector_add_flyout';
Expand Down Expand Up @@ -119,14 +118,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => {
setIsLoadingActions(true);
try {
const actionsResponse = await loadAllActions({ http });
setActions(
actionsResponse.filter(
(action) =>
action.actionTypeId !== ServiceNowConnectorConfiguration.id ||
(action.actionTypeId === ServiceNowConnectorConfiguration.id &&
!action.config.isCaseOwned)
)
);
setActions(actionsResponse);
} catch (e) {
toastNotifications.addDanger({
title: i18n.translate(
Expand Down

0 comments on commit 5c5d75f

Please sign in to comment.