mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Alerting][Connectors] Add new executor subaction to get 3rd party case fields (#82519)
This commit is contained in:
parent
1885dda6e6
commit
e1b7073a64
27 changed files with 2163 additions and 1455 deletions
|
@ -69,18 +69,21 @@ Table of Contents
|
|||
- [`secrets`](#secrets-6)
|
||||
- [`params`](#params-6)
|
||||
- [`subActionParams (pushToService)`](#subactionparams-pushtoservice)
|
||||
- [`subActionParams (getFields)`](#subactionparams-getfields-1)
|
||||
- [Jira](#jira)
|
||||
- [`config`](#config-7)
|
||||
- [`secrets`](#secrets-7)
|
||||
- [`params`](#params-7)
|
||||
- [`subActionParams (pushToService)`](#subactionparams-pushtoservice-1)
|
||||
- [`subActionParams (issueTypes)`](#subactionparams-issuetypes)
|
||||
- [`subActionParams (getFields)`](#subactionparams-getfields-2)
|
||||
- [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2)
|
||||
- [IBM Resilient](#ibm-resilient)
|
||||
- [`config`](#config-8)
|
||||
- [`secrets`](#secrets-8)
|
||||
- [`params`](#params-8)
|
||||
- [`subActionParams (pushToService)`](#subactionparams-pushtoservice-3)
|
||||
- [`subActionParams (getFields)`](#subactionparams-getfields-3)
|
||||
- [Command Line Utility](#command-line-utility)
|
||||
- [Developing New Action Types](#developing-new-action-types)
|
||||
- [licensing](#licensing)
|
||||
|
@ -563,7 +566,7 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a
|
|||
|
||||
| Property | Description | Type |
|
||||
| --------------- | ------------------------------------------------------------------------------------ | ------ |
|
||||
| subAction | The sub action to perform. It can be `pushToService`, `handshake`, and `getIncident` | string |
|
||||
| subAction | The sub action to perform. It can be `getFields`, `pushToService`, `handshake`, and `getIncident` | string |
|
||||
| subActionParams | The parameters of the sub action | object |
|
||||
|
||||
#### `subActionParams (pushToService)`
|
||||
|
@ -580,6 +583,10 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a
|
|||
| urgency | The name of the urgency in ServiceNow. | string _(optional)_ |
|
||||
| impact | The name of the impact in ServiceNow. | string _(optional)_ |
|
||||
|
||||
#### `subActionParams (getFields)`
|
||||
|
||||
No parameters for `getFields` sub-action. Provide an empty object `{}`.
|
||||
|
||||
---
|
||||
|
||||
## Jira
|
||||
|
@ -606,7 +613,7 @@ The Jira action uses the [V2 API](https://developer.atlassian.com/cloud/jira/pla
|
|||
|
||||
| Property | Description | Type |
|
||||
| --------------- | ----------------------------------------------------------------------------------------------------------------------- | ------ |
|
||||
| subAction | The sub action to perform. It can be `pushToService`, `handshake`, `getIncident`, `issueTypes`, and `fieldsByIssueType` | string |
|
||||
| subAction | The sub action to perform. It can be `getFields`, `pushToService`, `handshake`, `getIncident`, `issueTypes`, and `fieldsByIssueType` | string |
|
||||
| subActionParams | The parameters of the sub action | object |
|
||||
|
||||
#### `subActionParams (pushToService)`
|
||||
|
@ -627,6 +634,10 @@ The Jira action uses the [V2 API](https://developer.atlassian.com/cloud/jira/pla
|
|||
|
||||
No parameters for `issueTypes` sub-action. Provide an empty object `{}`.
|
||||
|
||||
#### `subActionParams (getFields)`
|
||||
|
||||
No parameters for `getFields` sub-action. Provide an empty object `{}`.
|
||||
|
||||
#### `subActionParams (pushToService)`
|
||||
|
||||
| Property | Description | Type |
|
||||
|
@ -655,7 +666,7 @@ ID: `.resilient`
|
|||
|
||||
| Property | Description | Type |
|
||||
| --------------- | ------------------------------------------------------------------------------------ | ------ |
|
||||
| subAction | The sub action to perform. It can be `pushToService`, `handshake`, and `getIncident` | string |
|
||||
| subAction | The sub action to perform. It can be `getFields`, `pushToService`, `handshake`, and `getIncident` | string |
|
||||
| subActionParams | The parameters of the sub action | object |
|
||||
|
||||
#### `subActionParams (pushToService)`
|
||||
|
@ -670,6 +681,10 @@ ID: `.resilient`
|
|||
| incidentTypes | An array with the ids of IBM Resilient incident types. | number[] _(optional)_ |
|
||||
| severityCode | IBM Resilient id of the severity code. | number _(optional)_ |
|
||||
|
||||
#### `subActionParams (getFields)`
|
||||
|
||||
No parameters for `getFields` sub-action. Provide an empty object `{}`.
|
||||
|
||||
# Command Line Utility
|
||||
|
||||
The [`kbn-action`](https://github.com/pmuellr/kbn-action) tool can be used to send HTTP requests to the Actions plugin. For instance, to create a Slack action from the `.slack` Action Type, use the following command:
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,6 +17,7 @@ import {
|
|||
PushToServiceApiParams,
|
||||
PushToServiceResponse,
|
||||
GetIssueHandlerArgs,
|
||||
GetCommonFieldsHandlerArgs,
|
||||
} from './types';
|
||||
|
||||
// TODO: to remove, need to support Case
|
||||
|
@ -39,6 +40,11 @@ const getIssueTypesHandler = async ({ externalService }: GetIssueTypesHandlerArg
|
|||
return res;
|
||||
};
|
||||
|
||||
const getFieldsHandler = async ({ externalService }: GetCommonFieldsHandlerArgs) => {
|
||||
const res = await externalService.getFields();
|
||||
return res;
|
||||
};
|
||||
|
||||
const getFieldsByIssueTypeHandler = async ({
|
||||
externalService,
|
||||
params,
|
||||
|
@ -157,6 +163,7 @@ const pushToServiceHandler = async ({
|
|||
};
|
||||
|
||||
export const api: ExternalServiceApi = {
|
||||
getFields: getFieldsHandler,
|
||||
handshake: handshakeHandler,
|
||||
pushToService: pushToServiceHandler,
|
||||
getIncident: getIncidentHandler,
|
||||
|
|
|
@ -40,6 +40,7 @@ interface GetActionTypeParams {
|
|||
}
|
||||
|
||||
const supportedSubActions: string[] = [
|
||||
'getFields',
|
||||
'pushToService',
|
||||
'issueTypes',
|
||||
'fieldsByIssueType',
|
||||
|
@ -145,6 +146,13 @@ async function executor(
|
|||
});
|
||||
}
|
||||
|
||||
if (subAction === 'getFields') {
|
||||
data = await api.getFields({
|
||||
externalService,
|
||||
params: subActionParams,
|
||||
});
|
||||
}
|
||||
|
||||
if (subAction === 'issues') {
|
||||
const getIssuesParams = subActionParams as ExecutorSubActionGetIssuesParams;
|
||||
data = await api.issues({
|
||||
|
|
|
@ -73,6 +73,20 @@ const createMock = (): jest.Mocked<ExternalService> => {
|
|||
key: 'RJ-107',
|
||||
title: 'Test title',
|
||||
})),
|
||||
getFields: jest.fn().mockImplementation(() => ({
|
||||
description: {
|
||||
allowedValues: [],
|
||||
defaultValue: {},
|
||||
required: true,
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
summary: {
|
||||
allowedValues: [],
|
||||
defaultValue: {},
|
||||
required: true,
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
})),
|
||||
};
|
||||
|
||||
service.createComment.mockImplementationOnce(() =>
|
||||
|
@ -97,7 +111,6 @@ const createMock = (): jest.Mocked<ExternalService> => {
|
|||
const externalServiceMock = {
|
||||
create: createMock,
|
||||
};
|
||||
|
||||
const mapping: Map<string, Partial<MapRecord>> = new Map();
|
||||
|
||||
mapping.set('title', {
|
||||
|
|
|
@ -55,6 +55,7 @@ export const ExecutorSubActionGetIncidentParamsSchema = schema.object({
|
|||
});
|
||||
|
||||
// Reserved for future implementation
|
||||
export const ExecutorSubActionCommonFieldsParamsSchema = schema.object({});
|
||||
export const ExecutorSubActionHandshakeParamsSchema = schema.object({});
|
||||
export const ExecutorSubActionGetCapabilitiesParamsSchema = schema.object({});
|
||||
export const ExecutorSubActionGetIssueTypesParamsSchema = schema.object({});
|
||||
|
@ -65,6 +66,10 @@ export const ExecutorSubActionGetIssuesParamsSchema = schema.object({ title: sch
|
|||
export const ExecutorSubActionGetIssueParamsSchema = schema.object({ id: schema.string() });
|
||||
|
||||
export const ExecutorParamsSchema = schema.oneOf([
|
||||
schema.object({
|
||||
subAction: schema.literal('getFields'),
|
||||
subActionParams: ExecutorSubActionCommonFieldsParamsSchema,
|
||||
}),
|
||||
schema.object({
|
||||
subAction: schema.literal('getIncident'),
|
||||
subActionParams: ExecutorSubActionGetIncidentParamsSchema,
|
||||
|
|
|
@ -57,8 +57,10 @@ const fieldsResponse = {
|
|||
id: '10006',
|
||||
name: 'Task',
|
||||
fields: {
|
||||
summary: { fieldId: 'summary' },
|
||||
summary: { required: true, schema: { type: 'string' }, fieldId: 'summary' },
|
||||
priority: {
|
||||
required: false,
|
||||
schema: { type: 'string' },
|
||||
fieldId: 'priority',
|
||||
allowedValues: [
|
||||
{
|
||||
|
@ -198,7 +200,7 @@ describe('Jira service', () => {
|
|||
error.response = { data: { errors: { summary: 'Required field' } } };
|
||||
throw error;
|
||||
});
|
||||
expect(service.getIncident('1')).rejects.toThrow(
|
||||
await expect(service.getIncident('1')).rejects.toThrow(
|
||||
'[Action][Jira]: Unable to get incident with id 1. Error: An error has occurred Reason: Required field'
|
||||
);
|
||||
});
|
||||
|
@ -348,7 +350,7 @@ describe('Jira service', () => {
|
|||
throw error;
|
||||
});
|
||||
|
||||
expect(
|
||||
await expect(
|
||||
service.createIncident({
|
||||
incident: {
|
||||
summary: 'title',
|
||||
|
@ -442,7 +444,7 @@ describe('Jira service', () => {
|
|||
throw error;
|
||||
});
|
||||
|
||||
expect(
|
||||
await expect(
|
||||
service.updateIncident({
|
||||
incidentId: '1',
|
||||
incident: {
|
||||
|
@ -526,7 +528,7 @@ describe('Jira service', () => {
|
|||
throw error;
|
||||
});
|
||||
|
||||
expect(
|
||||
await expect(
|
||||
service.createComment({
|
||||
incidentId: '1',
|
||||
comment: {
|
||||
|
@ -587,7 +589,7 @@ describe('Jira service', () => {
|
|||
throw error;
|
||||
});
|
||||
|
||||
expect(service.getCapabilities()).rejects.toThrow(
|
||||
await expect(service.getCapabilities()).rejects.toThrow(
|
||||
'[Action][Jira]: Unable to get capabilities. Error: An error has occurred. Reason: Could not get capabilities'
|
||||
);
|
||||
});
|
||||
|
@ -657,7 +659,7 @@ describe('Jira service', () => {
|
|||
throw error;
|
||||
});
|
||||
|
||||
expect(service.getIssueTypes()).rejects.toThrow(
|
||||
await expect(service.getIssueTypes()).rejects.toThrow(
|
||||
'[Action][Jira]: Unable to get issue types. Error: An error has occurred. Reason: Could not get issue types'
|
||||
);
|
||||
});
|
||||
|
@ -741,7 +743,7 @@ describe('Jira service', () => {
|
|||
throw error;
|
||||
});
|
||||
|
||||
expect(service.getIssueTypes()).rejects.toThrow(
|
||||
await expect(service.getIssueTypes()).rejects.toThrow(
|
||||
'[Action][Jira]: Unable to get issue types. Error: An error has occurred. Reason: Could not get issue types'
|
||||
);
|
||||
});
|
||||
|
@ -765,6 +767,8 @@ describe('Jira service', () => {
|
|||
|
||||
expect(res).toEqual({
|
||||
priority: {
|
||||
required: false,
|
||||
schema: { type: 'string' },
|
||||
allowedValues: [
|
||||
{ id: '1', name: 'Highest' },
|
||||
{ id: '2', name: 'High' },
|
||||
|
@ -774,7 +778,12 @@ describe('Jira service', () => {
|
|||
],
|
||||
defaultValue: { id: '3', name: 'Medium' },
|
||||
},
|
||||
summary: { allowedValues: [], defaultValue: {} },
|
||||
summary: {
|
||||
required: true,
|
||||
schema: { type: 'string' },
|
||||
allowedValues: [],
|
||||
defaultValue: {},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -815,7 +824,7 @@ describe('Jira service', () => {
|
|||
throw error;
|
||||
});
|
||||
|
||||
expect(service.getFieldsByIssueType('10006')).rejects.toThrow(
|
||||
await expect(service.getFieldsByIssueType('10006')).rejects.toThrow(
|
||||
'[Action][Jira]: Unable to get fields. Error: An error has occurred. Reason: Could not get fields'
|
||||
);
|
||||
});
|
||||
|
@ -837,8 +846,10 @@ describe('Jira service', () => {
|
|||
requestMock.mockImplementationOnce(() => ({
|
||||
data: {
|
||||
values: [
|
||||
{ fieldId: 'summary' },
|
||||
{ required: true, schema: { type: 'string' }, fieldId: 'summary' },
|
||||
{
|
||||
required: false,
|
||||
schema: { type: 'string' },
|
||||
fieldId: 'priority',
|
||||
allowedValues: [
|
||||
{
|
||||
|
@ -859,10 +870,17 @@ describe('Jira service', () => {
|
|||
|
||||
expect(res).toEqual({
|
||||
priority: {
|
||||
required: false,
|
||||
schema: { type: 'string' },
|
||||
allowedValues: [{ id: '3', name: 'Medium' }],
|
||||
defaultValue: { id: '3', name: 'Medium' },
|
||||
},
|
||||
summary: { allowedValues: [], defaultValue: {} },
|
||||
summary: {
|
||||
required: true,
|
||||
schema: { type: 'string' },
|
||||
allowedValues: [],
|
||||
defaultValue: {},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -881,8 +899,10 @@ describe('Jira service', () => {
|
|||
requestMock.mockImplementationOnce(() => ({
|
||||
data: {
|
||||
values: [
|
||||
{ fieldId: 'summary' },
|
||||
{ required: true, schema: { type: 'string' }, fieldId: 'summary' },
|
||||
{
|
||||
required: true,
|
||||
schema: { type: 'string' },
|
||||
fieldId: 'priority',
|
||||
allowedValues: [
|
||||
{
|
||||
|
@ -927,7 +947,7 @@ describe('Jira service', () => {
|
|||
throw error;
|
||||
});
|
||||
|
||||
expect(service.getFieldsByIssueType('10006')).rejects.toThrow(
|
||||
await expect(service.getFieldsByIssueType('10006')).rejects.toThrowError(
|
||||
'[Action][Jira]: Unable to get fields. Error: An error has occurred. Reason: Could not get issue types'
|
||||
);
|
||||
});
|
||||
|
@ -976,7 +996,7 @@ describe('Jira service', () => {
|
|||
throw error;
|
||||
});
|
||||
|
||||
expect(service.getIssues('Test title')).rejects.toThrow(
|
||||
await expect(service.getIssues('Test title')).rejects.toThrow(
|
||||
'[Action][Jira]: Unable to get issues. Error: An error has occurred. Reason: Could not get issue types'
|
||||
);
|
||||
});
|
||||
|
@ -1020,9 +1040,128 @@ describe('Jira service', () => {
|
|||
throw error;
|
||||
});
|
||||
|
||||
expect(service.getIssue('RJ-107')).rejects.toThrow(
|
||||
await expect(service.getIssue('RJ-107')).rejects.toThrow(
|
||||
'[Action][Jira]: Unable to get issue with id RJ-107. Error: An error has occurred. Reason: Could not get issue types'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFields', () => {
|
||||
const callMocks = () => {
|
||||
requestMock
|
||||
.mockImplementationOnce(() => ({
|
||||
data: {
|
||||
capabilities: {
|
||||
'list-project-issuetypes':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes',
|
||||
'list-issuetype-fields':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields',
|
||||
},
|
||||
},
|
||||
}))
|
||||
.mockImplementationOnce(() => ({
|
||||
data: {
|
||||
values: issueTypesResponse.data.projects[0].issuetypes,
|
||||
},
|
||||
}))
|
||||
.mockImplementationOnce(() => ({
|
||||
data: {
|
||||
capabilities: {
|
||||
'list-project-issuetypes':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes',
|
||||
'list-issuetype-fields':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields',
|
||||
},
|
||||
},
|
||||
}))
|
||||
.mockImplementationOnce(() => ({
|
||||
data: {
|
||||
capabilities: {
|
||||
'list-project-issuetypes':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes',
|
||||
'list-issuetype-fields':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields',
|
||||
},
|
||||
},
|
||||
}))
|
||||
.mockImplementationOnce(() => ({
|
||||
data: {
|
||||
values: [
|
||||
{ required: true, schema: { type: 'string' }, fieldId: 'summary' },
|
||||
{ required: true, schema: { type: 'string' }, fieldId: 'description' },
|
||||
{
|
||||
required: false,
|
||||
schema: { type: 'string' },
|
||||
fieldId: 'priority',
|
||||
allowedValues: [
|
||||
{
|
||||
name: 'Medium',
|
||||
id: '3',
|
||||
},
|
||||
],
|
||||
defaultValue: {
|
||||
name: 'Medium',
|
||||
id: '3',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}))
|
||||
.mockImplementationOnce(() => ({
|
||||
data: {
|
||||
values: [
|
||||
{ required: true, schema: { type: 'string' }, fieldId: 'summary' },
|
||||
{ required: true, schema: { type: 'string' }, fieldId: 'description' },
|
||||
],
|
||||
},
|
||||
}));
|
||||
};
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
test('it should call request with correct arguments', async () => {
|
||||
callMocks();
|
||||
await service.getFields();
|
||||
const callUrls = [
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities',
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes',
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities',
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities',
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes/10006',
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes/10007',
|
||||
];
|
||||
requestMock.mock.calls.forEach((call, i) => {
|
||||
expect(call[0].url).toEqual(callUrls[i]);
|
||||
});
|
||||
});
|
||||
test('it returns common fields correctly', async () => {
|
||||
callMocks();
|
||||
const res = await service.getFields();
|
||||
expect(res).toEqual({
|
||||
description: {
|
||||
allowedValues: [],
|
||||
defaultValue: {},
|
||||
required: true,
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
summary: {
|
||||
allowedValues: [],
|
||||
defaultValue: {},
|
||||
required: true,
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('it should throw an error', async () => {
|
||||
requestMock.mockImplementation(() => {
|
||||
const error: ResponseError = new Error('An error has occurred');
|
||||
error.response = { data: { errors: { summary: 'Required field' } } };
|
||||
throw error;
|
||||
});
|
||||
await expect(service.getFields()).rejects.toThrow(
|
||||
'[Action][Jira]: Unable to get capabilities. Error: An error has occurred. Reason: Required field'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,18 +8,20 @@ import axios from 'axios';
|
|||
|
||||
import { Logger } from '../../../../../../src/core/server';
|
||||
import {
|
||||
ExternalServiceCredentials,
|
||||
ExternalService,
|
||||
CreateCommentParams,
|
||||
CreateIncidentParams,
|
||||
UpdateIncidentParams,
|
||||
ExternalService,
|
||||
ExternalServiceCommentResponse,
|
||||
ExternalServiceCredentials,
|
||||
ExternalServiceIncidentResponse,
|
||||
Fields,
|
||||
FieldSchema,
|
||||
GetCommonFieldsResponse,
|
||||
Incident,
|
||||
JiraPublicConfigurationType,
|
||||
JiraSecretConfigurationType,
|
||||
Fields,
|
||||
CreateCommentParams,
|
||||
Incident,
|
||||
ResponseError,
|
||||
ExternalServiceCommentResponse,
|
||||
ExternalServiceIncidentResponse,
|
||||
UpdateIncidentParams,
|
||||
} from './types';
|
||||
|
||||
import * as i18n from './translations';
|
||||
|
@ -127,14 +129,21 @@ export const createExternalService = (
|
|||
issueTypes.map((type) => ({ id: type.id, name: type.name }));
|
||||
|
||||
const normalizeFields = (fields: {
|
||||
[key: string]: { allowedValues?: Array<{}>; defaultValue?: {} };
|
||||
[key: string]: {
|
||||
allowedValues?: Array<{}>;
|
||||
defaultValue?: {};
|
||||
required: boolean;
|
||||
schema: FieldSchema;
|
||||
};
|
||||
}) =>
|
||||
Object.keys(fields ?? {}).reduce((fieldsAcc, fieldKey) => {
|
||||
return {
|
||||
...fieldsAcc,
|
||||
[fieldKey]: {
|
||||
required: fields[fieldKey]?.required,
|
||||
allowedValues: fields[fieldKey]?.allowedValues ?? [],
|
||||
defaultValue: fields[fieldKey]?.defaultValue ?? {},
|
||||
schema: fields[fieldKey]?.schema,
|
||||
},
|
||||
};
|
||||
}, {});
|
||||
|
@ -326,7 +335,6 @@ export const createExternalService = (
|
|||
const getIssueTypes = async () => {
|
||||
const capabilitiesResponse = await getCapabilities();
|
||||
const supportsNewAPI = hasSupportForNewAPI(capabilitiesResponse);
|
||||
|
||||
try {
|
||||
if (!supportsNewAPI) {
|
||||
const res = await request({
|
||||
|
@ -366,7 +374,6 @@ export const createExternalService = (
|
|||
const getFieldsByIssueType = async (issueTypeId: string) => {
|
||||
const capabilitiesResponse = await getCapabilities();
|
||||
const supportsNewAPI = hasSupportForNewAPI(capabilitiesResponse);
|
||||
|
||||
try {
|
||||
if (!supportsNewAPI) {
|
||||
const res = await request({
|
||||
|
@ -378,6 +385,7 @@ export const createExternalService = (
|
|||
});
|
||||
|
||||
const fields = res.data.projects[0]?.issuetypes[0]?.fields || {};
|
||||
|
||||
return normalizeFields(fields);
|
||||
} else {
|
||||
const res = await request({
|
||||
|
@ -409,6 +417,30 @@ export const createExternalService = (
|
|||
}
|
||||
};
|
||||
|
||||
const getFields = async () => {
|
||||
try {
|
||||
const issueTypes = await getIssueTypes();
|
||||
const fieldsPerIssueType = await Promise.all(
|
||||
issueTypes.map((issueType) => getFieldsByIssueType(issueType.id))
|
||||
);
|
||||
return fieldsPerIssueType.reduce((acc: GetCommonFieldsResponse, fieldTypesByIssue) => {
|
||||
const currentListOfFields = Object.keys(acc);
|
||||
return currentListOfFields.length === 0
|
||||
? fieldTypesByIssue
|
||||
: currentListOfFields.reduce(
|
||||
(add: GetCommonFieldsResponse, field) =>
|
||||
Object.keys(fieldTypesByIssue).includes(field)
|
||||
? { ...add, [field]: acc[field] }
|
||||
: add,
|
||||
{}
|
||||
);
|
||||
}, {});
|
||||
} catch (error) {
|
||||
// errors that happen here would be thrown in the contained async calls
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const getIssues = async (title: string) => {
|
||||
const query = `${searchUrl}?jql=${encodeURIComponent(
|
||||
`project="${projectKey}" and summary ~"${title}"`
|
||||
|
@ -461,6 +493,7 @@ export const createExternalService = (
|
|||
};
|
||||
|
||||
return {
|
||||
getFields,
|
||||
getIncident,
|
||||
createIncident,
|
||||
updateIncident,
|
||||
|
|
|
@ -79,11 +79,34 @@ export interface CreateCommentParams {
|
|||
comment: Comment;
|
||||
}
|
||||
|
||||
export interface FieldsSchema {
|
||||
type: string;
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface ExternalServiceFields {
|
||||
clauseNames: string[];
|
||||
custom: boolean;
|
||||
id: string;
|
||||
key: string;
|
||||
name: string;
|
||||
navigatable: boolean;
|
||||
orderable: boolean;
|
||||
schema: FieldsSchema;
|
||||
searchable: boolean;
|
||||
}
|
||||
|
||||
export type GetIssueTypesResponse = Array<{ id: string; name: string }>;
|
||||
|
||||
export interface FieldSchema {
|
||||
type: string;
|
||||
items?: string;
|
||||
}
|
||||
export type GetFieldsByIssueTypeResponse = Record<
|
||||
string,
|
||||
{ allowedValues: Array<{}>; defaultValue: {} }
|
||||
{ allowedValues: Array<{}>; defaultValue: {}; required: boolean; schema: FieldSchema }
|
||||
>;
|
||||
export type GetCommonFieldsResponse = GetFieldsByIssueTypeResponse;
|
||||
|
||||
export type GetIssuesResponse = Array<{ id: string; key: string; title: string }>;
|
||||
export interface GetIssueResponse {
|
||||
|
@ -93,15 +116,16 @@ export interface GetIssueResponse {
|
|||
}
|
||||
|
||||
export interface ExternalService {
|
||||
getIncident: (id: string) => Promise<ExternalServiceParams | undefined>;
|
||||
createIncident: (params: CreateIncidentParams) => Promise<ExternalServiceIncidentResponse>;
|
||||
updateIncident: (params: UpdateIncidentParams) => Promise<ExternalServiceIncidentResponse>;
|
||||
createComment: (params: CreateCommentParams) => Promise<ExternalServiceCommentResponse>;
|
||||
createIncident: (params: CreateIncidentParams) => Promise<ExternalServiceIncidentResponse>;
|
||||
getFields: () => Promise<GetCommonFieldsResponse>;
|
||||
getCapabilities: () => Promise<ExternalServiceParams>;
|
||||
getIssueTypes: () => Promise<GetIssueTypesResponse>;
|
||||
getFieldsByIssueType: (issueTypeId: string) => Promise<GetFieldsByIssueTypeResponse>;
|
||||
getIssues: (title: string) => Promise<GetIssuesResponse>;
|
||||
getIncident: (id: string) => Promise<ExternalServiceParams | undefined>;
|
||||
getIssue: (id: string) => Promise<GetIssueResponse>;
|
||||
getIssues: (title: string) => Promise<GetIssuesResponse>;
|
||||
getIssueTypes: () => Promise<GetIssueTypesResponse>;
|
||||
updateIncident: (params: UpdateIncidentParams) => Promise<ExternalServiceIncidentResponse>;
|
||||
}
|
||||
|
||||
export interface PushToServiceApiParams extends ExecutorSubActionPushParams {
|
||||
|
@ -157,6 +181,11 @@ export interface GetIssueTypesHandlerArgs {
|
|||
params: ExecutorSubActionGetIssueTypesParams;
|
||||
}
|
||||
|
||||
export interface GetCommonFieldsHandlerArgs {
|
||||
externalService: ExternalService;
|
||||
params: ExecutorSubActionGetIssueTypesParams;
|
||||
}
|
||||
|
||||
export interface GetFieldsByIssueTypeHandlerArgs {
|
||||
externalService: ExternalService;
|
||||
params: ExecutorSubActionGetFieldsByIssueTypeParams;
|
||||
|
@ -177,15 +206,16 @@ export interface GetIssueHandlerArgs {
|
|||
}
|
||||
|
||||
export interface ExternalServiceApi {
|
||||
handshake: (args: HandshakeApiHandlerArgs) => Promise<void>;
|
||||
pushToService: (args: PushToServiceApiHandlerArgs) => Promise<PushToServiceResponse>;
|
||||
getFields: (args: GetCommonFieldsHandlerArgs) => Promise<GetCommonFieldsResponse>;
|
||||
getIncident: (args: GetIncidentApiHandlerArgs) => Promise<void>;
|
||||
handshake: (args: HandshakeApiHandlerArgs) => Promise<void>;
|
||||
issueTypes: (args: GetIssueTypesHandlerArgs) => Promise<GetIssueTypesResponse>;
|
||||
pushToService: (args: PushToServiceApiHandlerArgs) => Promise<PushToServiceResponse>;
|
||||
fieldsByIssueType: (
|
||||
args: GetFieldsByIssueTypeHandlerArgs
|
||||
) => Promise<GetFieldsByIssueTypeResponse>;
|
||||
issues: (args: GetIssuesHandlerArgs) => Promise<GetIssuesResponse>;
|
||||
issue: (args: GetIssueHandlerArgs) => Promise<GetIssueResponse>;
|
||||
issues: (args: GetIssuesHandlerArgs) => Promise<GetIssuesResponse>;
|
||||
}
|
||||
|
||||
export type JiraExecutorResultData =
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
GetSeverityHandlerArgs,
|
||||
PushToServiceApiParams,
|
||||
PushToServiceResponse,
|
||||
GetCommonFieldsHandlerArgs,
|
||||
} from './types';
|
||||
|
||||
// TODO: to remove, need to support Case
|
||||
|
@ -32,6 +33,10 @@ const getIncidentHandler = async ({
|
|||
params,
|
||||
}: GetIncidentApiHandlerArgs) => {};
|
||||
|
||||
const getFieldsHandler = async ({ externalService }: GetCommonFieldsHandlerArgs) => {
|
||||
const res = await externalService.getFields();
|
||||
return res;
|
||||
};
|
||||
const getIncidentTypesHandler = async ({ externalService }: GetIncidentTypesHandlerArgs) => {
|
||||
const res = await externalService.getIncidentTypes();
|
||||
return res;
|
||||
|
@ -136,9 +141,10 @@ const pushToServiceHandler = async ({
|
|||
};
|
||||
|
||||
export const api: ExternalServiceApi = {
|
||||
handshake: handshakeHandler,
|
||||
pushToService: pushToServiceHandler,
|
||||
getFields: getFieldsHandler,
|
||||
getIncident: getIncidentHandler,
|
||||
handshake: handshakeHandler,
|
||||
incidentTypes: getIncidentTypesHandler,
|
||||
pushToService: pushToServiceHandler,
|
||||
severity: getSeverityHandler,
|
||||
};
|
||||
|
|
|
@ -25,6 +25,7 @@ import {
|
|||
ResilientExecutorResultData,
|
||||
ExecutorSubActionGetIncidentTypesParams,
|
||||
ExecutorSubActionGetSeverityParams,
|
||||
ExecutorSubActionCommonFieldsParams,
|
||||
} from './types';
|
||||
import * as i18n from './translations';
|
||||
import { Logger } from '../../../../../../src/core/server';
|
||||
|
@ -37,7 +38,7 @@ interface GetActionTypeParams {
|
|||
configurationUtilities: ActionsConfigurationUtilities;
|
||||
}
|
||||
|
||||
const supportedSubActions: string[] = ['pushToService', 'incidentTypes', 'severity'];
|
||||
const supportedSubActions: string[] = ['getFields', 'pushToService', 'incidentTypes', 'severity'];
|
||||
|
||||
// action type definition
|
||||
export function getActionType(
|
||||
|
@ -122,6 +123,14 @@ async function executor(
|
|||
logger.debug(`response push to service for incident id: ${data.id}`);
|
||||
}
|
||||
|
||||
if (subAction === 'getFields') {
|
||||
const getFieldsParams = subActionParams as ExecutorSubActionCommonFieldsParams;
|
||||
data = await api.getFields({
|
||||
externalService,
|
||||
params: getFieldsParams,
|
||||
});
|
||||
}
|
||||
|
||||
if (subAction === 'incidentTypes') {
|
||||
const incidentTypesParams = subActionParams as ExecutorSubActionGetIncidentTypesParams;
|
||||
data = await api.incidentTypes({
|
||||
|
|
|
@ -8,8 +8,275 @@ import { ExternalService, PushToServiceApiParams, ExecutorSubActionPushParams }
|
|||
|
||||
import { MapRecord } from '../case/types';
|
||||
|
||||
export const resilientFields = [
|
||||
{
|
||||
id: 17,
|
||||
name: 'name',
|
||||
text: 'Name',
|
||||
prefix: null,
|
||||
type_id: 0,
|
||||
tooltip: 'A unique name to identify this particular incident.',
|
||||
input_type: 'text',
|
||||
required: 'always',
|
||||
hide_notification: false,
|
||||
chosen: false,
|
||||
default_chosen_by_server: false,
|
||||
blank_option: false,
|
||||
internal: true,
|
||||
uuid: 'ad6ed4f2-8d87-4ba2-81fa-03568a9326cc',
|
||||
operations: [
|
||||
'equals',
|
||||
'not_equals',
|
||||
'contains',
|
||||
'not_contains',
|
||||
'changed',
|
||||
'changed_to',
|
||||
'not_changed_to',
|
||||
'has_a_value',
|
||||
'not_has_a_value',
|
||||
],
|
||||
operation_perms: {
|
||||
changed_to: {
|
||||
show_in_manual_actions: false,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
has_a_value: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
not_changed_to: {
|
||||
show_in_manual_actions: false,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
equals: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
changed: {
|
||||
show_in_manual_actions: false,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
contains: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
not_contains: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
not_equals: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
not_has_a_value: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
},
|
||||
values: [],
|
||||
perms: {
|
||||
delete: false,
|
||||
modify_name: false,
|
||||
modify_values: false,
|
||||
modify_blank: false,
|
||||
modify_required: false,
|
||||
modify_operations: false,
|
||||
modify_chosen: false,
|
||||
modify_default: false,
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
show_in_scripts: true,
|
||||
modify_type: ['text'],
|
||||
sort: true,
|
||||
},
|
||||
read_only: false,
|
||||
changeable: true,
|
||||
rich_text: false,
|
||||
templates: [],
|
||||
deprecated: false,
|
||||
tags: [],
|
||||
calculated: false,
|
||||
is_tracked: false,
|
||||
allow_default_value: false,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
name: 'description',
|
||||
text: 'Description',
|
||||
prefix: null,
|
||||
type_id: 0,
|
||||
tooltip: 'A free form text description of the incident.',
|
||||
input_type: 'textarea',
|
||||
hide_notification: false,
|
||||
chosen: false,
|
||||
default_chosen_by_server: false,
|
||||
blank_option: false,
|
||||
internal: true,
|
||||
uuid: '420d70b1-98f9-4681-a20b-84f36a9e5e48',
|
||||
operations: [
|
||||
'equals',
|
||||
'not_equals',
|
||||
'contains',
|
||||
'not_contains',
|
||||
'changed',
|
||||
'changed_to',
|
||||
'not_changed_to',
|
||||
'has_a_value',
|
||||
'not_has_a_value',
|
||||
],
|
||||
operation_perms: {
|
||||
changed_to: {
|
||||
show_in_manual_actions: false,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
has_a_value: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
not_changed_to: {
|
||||
show_in_manual_actions: false,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
equals: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
changed: {
|
||||
show_in_manual_actions: false,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
contains: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
not_contains: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
not_equals: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
not_has_a_value: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
},
|
||||
values: [],
|
||||
perms: {
|
||||
delete: false,
|
||||
modify_name: false,
|
||||
modify_values: false,
|
||||
modify_blank: false,
|
||||
modify_required: false,
|
||||
modify_operations: false,
|
||||
modify_chosen: false,
|
||||
modify_default: false,
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
show_in_scripts: true,
|
||||
modify_type: ['textarea'],
|
||||
sort: true,
|
||||
},
|
||||
read_only: false,
|
||||
changeable: true,
|
||||
rich_text: true,
|
||||
templates: [],
|
||||
deprecated: false,
|
||||
tags: [],
|
||||
calculated: false,
|
||||
is_tracked: false,
|
||||
allow_default_value: false,
|
||||
},
|
||||
{
|
||||
id: 65,
|
||||
name: 'create_date',
|
||||
text: 'Date Created',
|
||||
prefix: null,
|
||||
type_id: 0,
|
||||
tooltip: 'The date the incident was created. This field is read-only.',
|
||||
input_type: 'datetimepicker',
|
||||
hide_notification: false,
|
||||
chosen: false,
|
||||
default_chosen_by_server: false,
|
||||
blank_option: false,
|
||||
internal: true,
|
||||
uuid: 'b4faf728-881a-4e8b-bf0b-d39b720392a1',
|
||||
operations: ['due_within', 'overdue_by', 'has_a_value', 'not_has_a_value'],
|
||||
operation_perms: {
|
||||
has_a_value: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
not_has_a_value: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
due_within: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
overdue_by: {
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
},
|
||||
},
|
||||
values: [],
|
||||
perms: {
|
||||
delete: false,
|
||||
modify_name: false,
|
||||
modify_values: false,
|
||||
modify_blank: false,
|
||||
modify_required: false,
|
||||
modify_operations: false,
|
||||
modify_chosen: false,
|
||||
modify_default: false,
|
||||
show_in_manual_actions: true,
|
||||
show_in_auto_actions: true,
|
||||
show_in_notifications: true,
|
||||
show_in_scripts: true,
|
||||
modify_type: ['datetimepicker'],
|
||||
sort: true,
|
||||
},
|
||||
read_only: true,
|
||||
changeable: false,
|
||||
rich_text: false,
|
||||
templates: [],
|
||||
deprecated: false,
|
||||
tags: [],
|
||||
calculated: false,
|
||||
is_tracked: false,
|
||||
allow_default_value: false,
|
||||
},
|
||||
];
|
||||
|
||||
const createMock = (): jest.Mocked<ExternalService> => {
|
||||
const service = {
|
||||
getFields: jest.fn().mockImplementation(() => Promise.resolve(resilientFields)),
|
||||
getIncident: jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
id: '1',
|
||||
|
|
|
@ -53,11 +53,16 @@ export const ExecutorSubActionGetIncidentParamsSchema = schema.object({
|
|||
});
|
||||
|
||||
// Reserved for future implementation
|
||||
export const ExecutorSubActionCommonFieldsParamsSchema = schema.object({});
|
||||
export const ExecutorSubActionHandshakeParamsSchema = schema.object({});
|
||||
export const ExecutorSubActionGetIncidentTypesParamsSchema = schema.object({});
|
||||
export const ExecutorSubActionGetSeverityParamsSchema = schema.object({});
|
||||
|
||||
export const ExecutorParamsSchema = schema.oneOf([
|
||||
schema.object({
|
||||
subAction: schema.literal('getFields'),
|
||||
subActionParams: ExecutorSubActionCommonFieldsParamsSchema,
|
||||
}),
|
||||
schema.object({
|
||||
subAction: schema.literal('getIncident'),
|
||||
subActionParams: ExecutorSubActionGetIncidentParamsSchema,
|
||||
|
|
|
@ -11,7 +11,7 @@ import * as utils from '../lib/axios_utils';
|
|||
import { ExternalService } from './types';
|
||||
import { Logger } from '../../../../../../src/core/server';
|
||||
import { loggingSystemMock } from '../../../../../../src/core/server/mocks';
|
||||
import { incidentTypes, severity } from './mocks';
|
||||
import { incidentTypes, resilientFields, severity } from './mocks';
|
||||
|
||||
const logger = loggingSystemMock.create().get() as jest.Mocked<Logger>;
|
||||
|
||||
|
@ -231,7 +231,7 @@ describe('IBM Resilient service', () => {
|
|||
requestMock.mockImplementation(() => {
|
||||
throw new Error('An error has occurred');
|
||||
});
|
||||
expect(service.getIncident('1')).rejects.toThrow(
|
||||
await expect(service.getIncident('1')).rejects.toThrow(
|
||||
'Unable to get incident with id 1. Error: An error has occurred'
|
||||
);
|
||||
});
|
||||
|
@ -310,7 +310,7 @@ describe('IBM Resilient service', () => {
|
|||
throw new Error('An error has occurred');
|
||||
});
|
||||
|
||||
expect(
|
||||
await expect(
|
||||
service.createIncident({
|
||||
incident: {
|
||||
name: 'title',
|
||||
|
@ -418,7 +418,7 @@ describe('IBM Resilient service', () => {
|
|||
test('it should throw an error', async () => {
|
||||
mockIncidentUpdate(true);
|
||||
|
||||
expect(
|
||||
await expect(
|
||||
service.updateIncident({
|
||||
incidentId: '1',
|
||||
incident: {
|
||||
|
@ -502,7 +502,7 @@ describe('IBM Resilient service', () => {
|
|||
throw new Error('An error has occurred');
|
||||
});
|
||||
|
||||
expect(
|
||||
await expect(
|
||||
service.createComment({
|
||||
incidentId: '1',
|
||||
comment: {
|
||||
|
@ -541,7 +541,7 @@ describe('IBM Resilient service', () => {
|
|||
throw new Error('An error has occurred');
|
||||
});
|
||||
|
||||
expect(service.getIncidentTypes()).rejects.toThrow(
|
||||
await expect(service.getIncidentTypes()).rejects.toThrow(
|
||||
'[Action][IBM Resilient]: Unable to get incident types. Error: An error has occurred.'
|
||||
);
|
||||
});
|
||||
|
@ -578,9 +578,40 @@ describe('IBM Resilient service', () => {
|
|||
throw new Error('An error has occurred');
|
||||
});
|
||||
|
||||
expect(service.getIncidentTypes()).rejects.toThrow(
|
||||
await expect(service.getIncidentTypes()).rejects.toThrow(
|
||||
'[Action][IBM Resilient]: Unable to get incident types. Error: An error has occurred.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFields', () => {
|
||||
test('it should call request with correct arguments', async () => {
|
||||
requestMock.mockImplementation(() => ({
|
||||
data: resilientFields,
|
||||
}));
|
||||
await service.getFields();
|
||||
|
||||
expect(requestMock).toHaveBeenCalledWith({
|
||||
axios,
|
||||
logger,
|
||||
url: 'https://resilient.elastic.co/rest/orgs/201/types/incident/fields',
|
||||
});
|
||||
});
|
||||
test('it returns common fields correctly', async () => {
|
||||
requestMock.mockImplementation(() => ({
|
||||
data: resilientFields,
|
||||
}));
|
||||
const res = await service.getFields();
|
||||
expect(res).toEqual(resilientFields);
|
||||
});
|
||||
|
||||
test('it should throw an error', async () => {
|
||||
requestMock.mockImplementation(() => {
|
||||
throw new Error('An error has occurred');
|
||||
});
|
||||
await expect(service.getFields()).rejects.toThrow(
|
||||
'Unable to get fields. Error: An error has occurred'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -303,12 +303,27 @@ export const createExternalService = (
|
|||
}
|
||||
};
|
||||
|
||||
const getFields = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
axios: axiosInstance,
|
||||
url: incidentFieldsUrl,
|
||||
logger,
|
||||
proxySettings,
|
||||
});
|
||||
return res.data ?? [];
|
||||
} catch (error) {
|
||||
throw new Error(getErrorMessage(i18n.NAME, `Unable to get fields. Error: ${error.message}.`));
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
getIncident,
|
||||
createIncident,
|
||||
updateIncident,
|
||||
createComment,
|
||||
createIncident,
|
||||
getFields,
|
||||
getIncident,
|
||||
getIncidentTypes,
|
||||
getSeverity,
|
||||
updateIncident,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,14 +8,15 @@
|
|||
|
||||
import { TypeOf } from '@kbn/config-schema';
|
||||
import {
|
||||
ExternalIncidentServiceConfigurationSchema,
|
||||
ExternalIncidentServiceSecretConfigurationSchema,
|
||||
ExecutorParamsSchema,
|
||||
ExecutorSubActionPushParamsSchema,
|
||||
ExecutorSubActionCommonFieldsParamsSchema,
|
||||
ExecutorSubActionGetIncidentParamsSchema,
|
||||
ExecutorSubActionHandshakeParamsSchema,
|
||||
ExecutorSubActionGetIncidentTypesParamsSchema,
|
||||
ExecutorSubActionGetSeverityParamsSchema,
|
||||
ExecutorSubActionHandshakeParamsSchema,
|
||||
ExecutorSubActionPushParamsSchema,
|
||||
ExternalIncidentServiceConfigurationSchema,
|
||||
ExternalIncidentServiceSecretConfigurationSchema,
|
||||
} from './schema';
|
||||
|
||||
import { ActionsConfigurationUtilities } from '../../actions_config';
|
||||
|
@ -31,6 +32,10 @@ export type ResilientSecretConfigurationType = TypeOf<
|
|||
typeof ExternalIncidentServiceSecretConfigurationSchema
|
||||
>;
|
||||
|
||||
export type ExecutorSubActionCommonFieldsParams = TypeOf<
|
||||
typeof ExecutorSubActionCommonFieldsParamsSchema
|
||||
>;
|
||||
|
||||
export type ExecutorParams = TypeOf<typeof ExecutorParamsSchema>;
|
||||
export type ExecutorSubActionPushParams = TypeOf<typeof ExecutorSubActionPushParamsSchema>;
|
||||
|
||||
|
@ -60,6 +65,14 @@ export interface ExternalServiceCommentResponse {
|
|||
}
|
||||
|
||||
export type ExternalServiceParams = Record<string, unknown>;
|
||||
export interface ExternalServiceFields {
|
||||
id: string;
|
||||
input_type: string;
|
||||
name: string;
|
||||
read_only: boolean;
|
||||
required?: string;
|
||||
}
|
||||
export type GetCommonFieldsResponse = ExternalServiceFields[];
|
||||
|
||||
export type Incident = Pick<
|
||||
ExecutorSubActionPushParams,
|
||||
|
@ -86,12 +99,13 @@ export type GetIncidentTypesResponse = Array<{ id: string; name: string }>;
|
|||
export type GetSeverityResponse = Array<{ id: string; name: string }>;
|
||||
|
||||
export interface ExternalService {
|
||||
getIncident: (id: string) => Promise<ExternalServiceParams | undefined>;
|
||||
createIncident: (params: CreateIncidentParams) => Promise<ExternalServiceIncidentResponse>;
|
||||
updateIncident: (params: UpdateIncidentParams) => Promise<ExternalServiceIncidentResponse>;
|
||||
createComment: (params: CreateCommentParams) => Promise<ExternalServiceCommentResponse>;
|
||||
createIncident: (params: CreateIncidentParams) => Promise<ExternalServiceIncidentResponse>;
|
||||
getFields: () => Promise<GetCommonFieldsResponse>;
|
||||
getIncident: (id: string) => Promise<ExternalServiceParams | undefined>;
|
||||
getIncidentTypes: () => Promise<GetIncidentTypesResponse>;
|
||||
getSeverity: () => Promise<GetSeverityResponse>;
|
||||
updateIncident: (params: UpdateIncidentParams) => Promise<ExternalServiceIncidentResponse>;
|
||||
}
|
||||
|
||||
export interface PushToServiceApiParams extends ExecutorSubActionPushParams {
|
||||
|
@ -132,6 +146,11 @@ export interface HandshakeApiHandlerArgs extends ExternalServiceApiHandlerArgs {
|
|||
params: ExecutorSubActionHandshakeParams;
|
||||
}
|
||||
|
||||
export interface GetCommonFieldsHandlerArgs {
|
||||
externalService: ExternalService;
|
||||
params: ExecutorSubActionCommonFieldsParams;
|
||||
}
|
||||
|
||||
export interface GetIncidentTypesHandlerArgs {
|
||||
externalService: ExternalService;
|
||||
params: ExecutorSubActionGetIncidentTypesParams;
|
||||
|
@ -147,6 +166,7 @@ export interface PushToServiceResponse extends ExternalServiceIncidentResponse {
|
|||
}
|
||||
|
||||
export interface ExternalServiceApi {
|
||||
getFields: (args: GetCommonFieldsHandlerArgs) => Promise<GetCommonFieldsResponse>;
|
||||
handshake: (args: HandshakeApiHandlerArgs) => Promise<void>;
|
||||
pushToService: (args: PushToServiceApiHandlerArgs) => Promise<PushToServiceResponse>;
|
||||
getIncident: (args: GetIncidentApiHandlerArgs) => Promise<void>;
|
||||
|
@ -156,6 +176,7 @@ export interface ExternalServiceApi {
|
|||
|
||||
export type ResilientExecutorResultData =
|
||||
| PushToServiceResponse
|
||||
| GetCommonFieldsResponse
|
||||
| GetIncidentTypesResponse
|
||||
| GetSeverityResponse;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -12,6 +12,8 @@ import {
|
|||
PushToServiceApiParams,
|
||||
PushToServiceResponse,
|
||||
Incident,
|
||||
GetCommonFieldsHandlerArgs,
|
||||
GetCommonFieldsResponse,
|
||||
} from './types';
|
||||
|
||||
// TODO: to remove, need to support Case
|
||||
|
@ -127,8 +129,16 @@ const pushToServiceHandler = async ({
|
|||
return res;
|
||||
};
|
||||
|
||||
const getFieldsHandler = async ({
|
||||
externalService,
|
||||
}: GetCommonFieldsHandlerArgs): Promise<GetCommonFieldsResponse> => {
|
||||
const res = await externalService.getFields();
|
||||
return res;
|
||||
};
|
||||
|
||||
export const api: ExternalServiceApi = {
|
||||
getFields: getFieldsHandler,
|
||||
getIncident: getIncidentHandler,
|
||||
handshake: handshakeHandler,
|
||||
pushToService: pushToServiceHandler,
|
||||
getIncident: getIncidentHandler,
|
||||
};
|
||||
|
|
|
@ -25,6 +25,8 @@ import {
|
|||
ServiceNowPublicConfigurationType,
|
||||
ServiceNowSecretConfigurationType,
|
||||
PushToServiceResponse,
|
||||
ExecutorSubActionCommonFieldsParams,
|
||||
ServiceNowExecutorResultData,
|
||||
} from './types';
|
||||
|
||||
// TODO: to remove, need to support Case
|
||||
|
@ -63,7 +65,7 @@ export function getActionType(
|
|||
}
|
||||
|
||||
// action executor
|
||||
|
||||
const supportedSubActions: string[] = ['getFields', 'pushToService'];
|
||||
async function executor(
|
||||
{ logger }: { logger: Logger },
|
||||
execOptions: ActionTypeExecutorOptions<
|
||||
|
@ -71,10 +73,10 @@ async function executor(
|
|||
ServiceNowSecretConfigurationType,
|
||||
ExecutorParams
|
||||
>
|
||||
): Promise<ActionTypeExecutorResult<PushToServiceResponse | {}>> {
|
||||
): Promise<ActionTypeExecutorResult<ServiceNowExecutorResultData | {}>> {
|
||||
const { actionId, config, params, secrets } = execOptions;
|
||||
const { subAction, subActionParams } = params;
|
||||
let data: PushToServiceResponse | null = null;
|
||||
let data: ServiceNowExecutorResultData | null = null;
|
||||
|
||||
const externalService = createExternalService(
|
||||
{
|
||||
|
@ -91,7 +93,7 @@ async function executor(
|
|||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
if (subAction !== 'pushToService') {
|
||||
if (!supportedSubActions.includes(subAction)) {
|
||||
const errorMessage = `[Action][ExternalService] subAction ${subAction} not implemented.`;
|
||||
logger.error(errorMessage);
|
||||
throw new Error(errorMessage);
|
||||
|
@ -117,5 +119,13 @@ async function executor(
|
|||
logger.debug(`response push to service for incident id: ${data.id}`);
|
||||
}
|
||||
|
||||
if (subAction === 'getFields') {
|
||||
const getFieldsParams = subActionParams as ExecutorSubActionCommonFieldsParams;
|
||||
data = await api.getFields({
|
||||
externalService,
|
||||
params: getFieldsParams,
|
||||
});
|
||||
}
|
||||
|
||||
return { status: 'ok', data: data ?? {}, actionId };
|
||||
}
|
||||
|
|
|
@ -7,8 +7,36 @@
|
|||
import { ExternalService, PushToServiceApiParams, ExecutorSubActionPushParams } from './types';
|
||||
import { MapRecord } from '../case/types';
|
||||
|
||||
export const serviceNowCommonFields = [
|
||||
{
|
||||
column_label: 'Close notes',
|
||||
max_length: '4000',
|
||||
element: 'close_notes',
|
||||
},
|
||||
{
|
||||
column_label: 'Description',
|
||||
max_length: '4000',
|
||||
element: 'description',
|
||||
},
|
||||
{
|
||||
column_label: 'Short description',
|
||||
max_length: '160',
|
||||
element: 'short_description',
|
||||
},
|
||||
{
|
||||
column_label: 'Created by',
|
||||
max_length: '40',
|
||||
element: 'sys_created_by',
|
||||
},
|
||||
{
|
||||
column_label: 'Updated by',
|
||||
max_length: '40',
|
||||
element: 'sys_updated_by',
|
||||
},
|
||||
];
|
||||
const createMock = (): jest.Mocked<ExternalService> => {
|
||||
const service = {
|
||||
getFields: jest.fn().mockImplementation(() => Promise.resolve(serviceNowCommonFields)),
|
||||
getIncident: jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
short_description: 'title from servicenow',
|
||||
|
|
|
@ -28,6 +28,7 @@ export const ExternalIncidentServiceSecretConfigurationSchema = schema.object(
|
|||
);
|
||||
|
||||
export const ExecutorSubActionSchema = schema.oneOf([
|
||||
schema.literal('getFields'),
|
||||
schema.literal('getIncident'),
|
||||
schema.literal('pushToService'),
|
||||
schema.literal('handshake'),
|
||||
|
@ -53,8 +54,13 @@ export const ExecutorSubActionGetIncidentParamsSchema = schema.object({
|
|||
|
||||
// Reserved for future implementation
|
||||
export const ExecutorSubActionHandshakeParamsSchema = schema.object({});
|
||||
export const ExecutorSubActionCommonFieldsParamsSchema = schema.object({});
|
||||
|
||||
export const ExecutorParamsSchema = schema.oneOf([
|
||||
schema.object({
|
||||
subAction: schema.literal('getFields'),
|
||||
subActionParams: ExecutorSubActionCommonFieldsParamsSchema,
|
||||
}),
|
||||
schema.object({
|
||||
subAction: schema.literal('getIncident'),
|
||||
subActionParams: ExecutorSubActionGetIncidentParamsSchema,
|
||||
|
|
|
@ -11,6 +11,7 @@ import * as utils from '../lib/axios_utils';
|
|||
import { ExternalService } from './types';
|
||||
import { Logger } from '../../../../../../src/core/server';
|
||||
import { loggingSystemMock } from '../../../../../../src/core/server/mocks';
|
||||
import { serviceNowCommonFields } from './mocks';
|
||||
const logger = loggingSystemMock.create().get() as jest.Mocked<Logger>;
|
||||
|
||||
jest.mock('axios');
|
||||
|
@ -108,7 +109,7 @@ describe('ServiceNow service', () => {
|
|||
requestMock.mockImplementation(() => {
|
||||
throw new Error('An error has occurred');
|
||||
});
|
||||
expect(service.getIncident('1')).rejects.toThrow(
|
||||
await expect(service.getIncident('1')).rejects.toThrow(
|
||||
'Unable to get incident with id 1. Error: An error has occurred'
|
||||
);
|
||||
});
|
||||
|
@ -155,7 +156,7 @@ describe('ServiceNow service', () => {
|
|||
throw new Error('An error has occurred');
|
||||
});
|
||||
|
||||
expect(
|
||||
await expect(
|
||||
service.createIncident({
|
||||
incident: { short_description: 'title', description: 'desc' },
|
||||
})
|
||||
|
@ -207,7 +208,7 @@ describe('ServiceNow service', () => {
|
|||
throw new Error('An error has occurred');
|
||||
});
|
||||
|
||||
expect(
|
||||
await expect(
|
||||
service.updateIncident({
|
||||
incidentId: '1',
|
||||
incident: { short_description: 'title', description: 'desc' },
|
||||
|
@ -234,4 +235,36 @@ describe('ServiceNow service', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFields', () => {
|
||||
test('it should call request with correct arguments', async () => {
|
||||
requestMock.mockImplementation(() => ({
|
||||
data: { result: serviceNowCommonFields },
|
||||
}));
|
||||
await service.getFields();
|
||||
|
||||
expect(requestMock).toHaveBeenCalledWith({
|
||||
axios,
|
||||
logger,
|
||||
url:
|
||||
'https://dev102283.service-now.com/api/now/v2/table/sys_dictionary?sysparm_query=name=task^internal_type=string&active=true&read_only=false&sysparm_fields=max_length,element,column_label',
|
||||
});
|
||||
});
|
||||
test('it returns common fields correctly', async () => {
|
||||
requestMock.mockImplementation(() => ({
|
||||
data: { result: serviceNowCommonFields },
|
||||
}));
|
||||
const res = await service.getFields();
|
||||
expect(res).toEqual(serviceNowCommonFields);
|
||||
});
|
||||
|
||||
test('it should throw an error', async () => {
|
||||
requestMock.mockImplementation(() => {
|
||||
throw new Error('An error has occurred');
|
||||
});
|
||||
await expect(service.getFields()).rejects.toThrow(
|
||||
'Unable to get common fields. Error: An error has occurred'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,6 +16,7 @@ import { ProxySettings } from '../../types';
|
|||
|
||||
const API_VERSION = 'v2';
|
||||
const INCIDENT_URL = `api/now/${API_VERSION}/table/incident`;
|
||||
const SYS_DICTIONARY = `api/now/${API_VERSION}/table/sys_dictionary`;
|
||||
|
||||
// Based on: https://docs.servicenow.com/bundle/orlando-platform-user-interface/page/use/navigation/reference/r_NavigatingByURLExamples.html
|
||||
const VIEW_INCIDENT_URL = `nav_to.do?uri=incident.do?sys_id=`;
|
||||
|
@ -33,6 +34,7 @@ export const createExternalService = (
|
|||
}
|
||||
|
||||
const incidentUrl = `${url}/${INCIDENT_URL}`;
|
||||
const fieldsUrl = `${url}/${SYS_DICTIONARY}?sysparm_query=name=task^internal_type=string&active=true&read_only=false&sysparm_fields=max_length,element,column_label`;
|
||||
const axiosInstance = axios.create({
|
||||
auth: { username, password },
|
||||
});
|
||||
|
@ -126,10 +128,28 @@ export const createExternalService = (
|
|||
}
|
||||
};
|
||||
|
||||
const getFields = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
axios: axiosInstance,
|
||||
url: fieldsUrl,
|
||||
logger,
|
||||
proxySettings,
|
||||
});
|
||||
|
||||
return res.data.result.length > 0 ? res.data.result : [];
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
getErrorMessage(i18n.NAME, `Unable to get common fields. Error: ${error.message}`)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
getIncident,
|
||||
createIncident,
|
||||
updateIncident,
|
||||
findIncidents,
|
||||
getFields,
|
||||
getIncident,
|
||||
updateIncident,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,12 +8,13 @@
|
|||
|
||||
import { TypeOf } from '@kbn/config-schema';
|
||||
import {
|
||||
ExternalIncidentServiceConfigurationSchema,
|
||||
ExternalIncidentServiceSecretConfigurationSchema,
|
||||
ExecutorParamsSchema,
|
||||
ExecutorSubActionPushParamsSchema,
|
||||
ExecutorSubActionCommonFieldsParamsSchema,
|
||||
ExecutorSubActionGetIncidentParamsSchema,
|
||||
ExecutorSubActionHandshakeParamsSchema,
|
||||
ExecutorSubActionPushParamsSchema,
|
||||
ExternalIncidentServiceConfigurationSchema,
|
||||
ExternalIncidentServiceSecretConfigurationSchema,
|
||||
} from './schema';
|
||||
import { ActionsConfigurationUtilities } from '../../actions_config';
|
||||
import { ExternalServiceCommentResponse } from '../case/types';
|
||||
|
@ -27,6 +28,12 @@ export type ServiceNowSecretConfigurationType = TypeOf<
|
|||
typeof ExternalIncidentServiceSecretConfigurationSchema
|
||||
>;
|
||||
|
||||
export type ExecutorSubActionCommonFieldsParams = TypeOf<
|
||||
typeof ExecutorSubActionCommonFieldsParamsSchema
|
||||
>;
|
||||
|
||||
export type ServiceNowExecutorResultData = PushToServiceResponse | GetCommonFieldsResponse;
|
||||
|
||||
export interface CreateCommentRequest {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
@ -59,6 +66,7 @@ export interface PushToServiceResponse extends ExternalServiceIncidentResponse {
|
|||
export type ExternalServiceParams = Record<string, unknown>;
|
||||
|
||||
export interface ExternalService {
|
||||
getFields: () => Promise<GetCommonFieldsResponse>;
|
||||
getIncident: (id: string) => Promise<ExternalServiceParams | undefined>;
|
||||
createIncident: (params: ExternalServiceParams) => Promise<ExternalServiceIncidentResponse>;
|
||||
updateIncident: (params: ExternalServiceParams) => Promise<ExternalServiceIncidentResponse>;
|
||||
|
@ -102,8 +110,24 @@ export interface GetIncidentApiHandlerArgs extends ExternalServiceApiHandlerArgs
|
|||
export interface HandshakeApiHandlerArgs extends ExternalServiceApiHandlerArgs {
|
||||
params: ExecutorSubActionHandshakeParams;
|
||||
}
|
||||
export interface ExternalServiceFields {
|
||||
column_label: string;
|
||||
name: string;
|
||||
internal_type: {
|
||||
link: string;
|
||||
value: string;
|
||||
};
|
||||
max_length: string;
|
||||
element: string;
|
||||
}
|
||||
export type GetCommonFieldsResponse = ExternalServiceFields[];
|
||||
export interface GetCommonFieldsHandlerArgs {
|
||||
externalService: ExternalService;
|
||||
params: ExecutorSubActionCommonFieldsParams;
|
||||
}
|
||||
|
||||
export interface ExternalServiceApi {
|
||||
getFields: (args: GetCommonFieldsHandlerArgs) => Promise<GetCommonFieldsResponse>;
|
||||
handshake: (args: HandshakeApiHandlerArgs) => Promise<void>;
|
||||
pushToService: (args: PushToServiceApiHandlerArgs) => Promise<PushToServiceResponse>;
|
||||
getIncident: (args: GetIncidentApiHandlerArgs) => Promise<void>;
|
||||
|
|
|
@ -333,7 +333,7 @@ export default function jiraTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subAction]: expected value to equal [pushToService]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]\n- [5.subAction]: expected value to equal [issues]\n- [6.subAction]: expected value to equal [issue]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -351,7 +351,7 @@ export default function jiraTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]\n- [5.subAction]: expected value to equal [issues]\n- [6.subAction]: expected value to equal [issue]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -374,7 +374,7 @@ export default function jiraTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]\n- [5.subAction]: expected value to equal [issues]\n- [6.subAction]: expected value to equal [issue]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -402,7 +402,7 @@ export default function jiraTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]\n- [5.subAction]: expected value to equal [issues]\n- [6.subAction]: expected value to equal [issue]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -430,7 +430,7 @@ export default function jiraTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]\n- [5.subAction]: expected value to equal [issues]\n- [6.subAction]: expected value to equal [issue]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [issueTypes]\n- [5.subAction]: expected value to equal [fieldsByIssueType]\n- [6.subAction]: expected value to equal [issues]\n- [7.subAction]: expected value to equal [issue]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -334,7 +334,7 @@ export default function resilientTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subAction]: expected value to equal [pushToService]\n- [3.subAction]: expected value to equal [incidentTypes]\n- [4.subAction]: expected value to equal [severity]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -352,7 +352,7 @@ export default function resilientTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]\n- [3.subAction]: expected value to equal [incidentTypes]\n- [4.subAction]: expected value to equal [severity]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -375,7 +375,7 @@ export default function resilientTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]\n- [3.subAction]: expected value to equal [incidentTypes]\n- [4.subAction]: expected value to equal [severity]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -403,7 +403,7 @@ export default function resilientTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [3.subAction]: expected value to equal [incidentTypes]\n- [4.subAction]: expected value to equal [severity]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -431,7 +431,7 @@ export default function resilientTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [3.subAction]: expected value to equal [incidentTypes]\n- [4.subAction]: expected value to equal [severity]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [incidentTypes]\n- [5.subAction]: expected value to equal [severity]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -328,7 +328,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subAction]: expected value to equal [pushToService]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -346,7 +346,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -369,7 +369,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.title]: expected value of type [string] but got [undefined]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -397,7 +397,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments.0.commentId]: expected value of type [string] but got [undefined]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments.0.commentId]: expected value of type [string] but got [undefined]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -425,7 +425,7 @@ export default function servicenowTest({ getService }: FtrProviderContext) {
|
|||
status: 'error',
|
||||
retry: false,
|
||||
message:
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments.0.comment]: expected value of type [string] but got [undefined]',
|
||||
'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments.0.comment]: expected value of type [string] but got [undefined]',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue