mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
* Push ITSM comments as work notes * Fix cases mapping * Improve error messages * Fix tests
This commit is contained in:
parent
4c5a7f9860
commit
93142f3904
6 changed files with 110 additions and 13 deletions
|
@ -78,7 +78,9 @@ describe('ServiceNow', () => {
|
|||
services,
|
||||
} as unknown) as ServiceNowActionTypeExecutorOptions;
|
||||
await actionType.executor(executorOptions);
|
||||
expect((api.pushToService as jest.Mock).mock.calls[0][0].commentFieldKey).toBe('comments');
|
||||
expect((api.pushToService as jest.Mock).mock.calls[0][0].commentFieldKey).toBe(
|
||||
'work_notes'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -76,7 +76,12 @@ export function getServiceNowITSMActionType(params: GetActionTypeParams): Servic
|
|||
}),
|
||||
params: ExecutorParamsSchemaITSM,
|
||||
},
|
||||
executor: curry(executor)({ logger, configurationUtilities, table: serviceNowITSMTable }),
|
||||
executor: curry(executor)({
|
||||
logger,
|
||||
configurationUtilities,
|
||||
table: serviceNowITSMTable,
|
||||
commentFieldKey: 'work_notes',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,11 @@ import { ExternalServiceCredentials, ExternalService, ExternalServiceParams } fr
|
|||
|
||||
import * as i18n from './translations';
|
||||
import { Logger } from '../../../../../../src/core/server';
|
||||
import { ServiceNowPublicConfigurationType, ServiceNowSecretConfigurationType } from './types';
|
||||
import {
|
||||
ServiceNowPublicConfigurationType,
|
||||
ServiceNowSecretConfigurationType,
|
||||
ResponseError,
|
||||
} from './types';
|
||||
import { request, getErrorMessage, addTimeZoneToDate, patch } from '../lib/axios_utils';
|
||||
import { ActionsConfigurationUtilities } from '../../actions_config';
|
||||
|
||||
|
@ -62,6 +66,15 @@ export const createExternalService = (
|
|||
}
|
||||
};
|
||||
|
||||
const createErrorMessage = (errorResponse: ResponseError): string => {
|
||||
if (errorResponse == null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const { error } = errorResponse;
|
||||
return error != null ? `${error?.message}: ${error?.detail}` : '';
|
||||
};
|
||||
|
||||
const getIncident = async (id: string) => {
|
||||
try {
|
||||
const res = await request({
|
||||
|
@ -76,7 +89,9 @@ export const createExternalService = (
|
|||
throw new Error(
|
||||
getErrorMessage(
|
||||
i18n.SERVICENOW,
|
||||
`Unable to get incident with id ${id}. Error: ${error.message}`
|
||||
`Unable to get incident with id ${id}. Error: ${
|
||||
error.message
|
||||
} Reason: ${createErrorMessage(error.response?.data)}`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -97,7 +112,9 @@ export const createExternalService = (
|
|||
throw new Error(
|
||||
getErrorMessage(
|
||||
i18n.SERVICENOW,
|
||||
`Unable to find incidents by query. Error: ${error.message}`
|
||||
`Unable to find incidents by query. Error: ${error.message} Reason: ${createErrorMessage(
|
||||
error.response?.data
|
||||
)}`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -122,7 +139,12 @@ export const createExternalService = (
|
|||
};
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
getErrorMessage(i18n.SERVICENOW, `Unable to create incident. Error: ${error.message}`)
|
||||
getErrorMessage(
|
||||
i18n.SERVICENOW,
|
||||
`Unable to create incident. Error: ${error.message} Reason: ${createErrorMessage(
|
||||
error.response?.data
|
||||
)}`
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@ -147,7 +169,9 @@ export const createExternalService = (
|
|||
throw new Error(
|
||||
getErrorMessage(
|
||||
i18n.SERVICENOW,
|
||||
`Unable to update incident with id ${incidentId}. Error: ${error.message}`
|
||||
`Unable to update incident with id ${incidentId}. Error: ${
|
||||
error.message
|
||||
} Reason: ${createErrorMessage(error.response?.data)}`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -165,7 +189,12 @@ export const createExternalService = (
|
|||
return res.data.result.length > 0 ? res.data.result : [];
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
getErrorMessage(i18n.SERVICENOW, `Unable to get fields. Error: ${error.message}`)
|
||||
getErrorMessage(
|
||||
i18n.SERVICENOW,
|
||||
`Unable to get fields. Error: ${error.message} Reason: ${createErrorMessage(
|
||||
error.response?.data
|
||||
)}`
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@ -182,7 +211,12 @@ export const createExternalService = (
|
|||
return res.data.result;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
getErrorMessage(i18n.SERVICENOW, `Unable to get choices. Error: ${error.message}`)
|
||||
getErrorMessage(
|
||||
i18n.SERVICENOW,
|
||||
`Unable to get choices. Error: ${error.message} Reason: ${createErrorMessage(
|
||||
error.response?.data
|
||||
)}`
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -171,3 +171,12 @@ export interface ExternalServiceCommentResponse {
|
|||
pushedDate: string;
|
||||
externalCommentId?: string;
|
||||
}
|
||||
|
||||
type TypeNullOrUndefined<T> = T | null | undefined;
|
||||
export interface ResponseError {
|
||||
error: TypeNullOrUndefined<{
|
||||
message: TypeNullOrUndefined<string>;
|
||||
detail: TypeNullOrUndefined<string>;
|
||||
}>;
|
||||
status: TypeNullOrUndefined<string>;
|
||||
}
|
||||
|
|
|
@ -83,7 +83,24 @@ export const mappings: TestMappings = {
|
|||
},
|
||||
{
|
||||
source: 'comments',
|
||||
target: 'comments',
|
||||
target: 'work_notes',
|
||||
action_type: 'append',
|
||||
},
|
||||
],
|
||||
[ConnectorTypes.serviceNowSIR]: [
|
||||
{
|
||||
source: 'title',
|
||||
target: 'short_description',
|
||||
action_type: 'overwrite',
|
||||
},
|
||||
{
|
||||
source: 'description',
|
||||
target: 'description',
|
||||
action_type: 'overwrite',
|
||||
},
|
||||
{
|
||||
source: 'comments',
|
||||
target: 'work_notes',
|
||||
action_type: 'append',
|
||||
},
|
||||
],
|
||||
|
@ -613,6 +630,24 @@ export const formatFieldsTestData: FormatFieldsTestData[] = [
|
|||
fields: serviceNowFields,
|
||||
type: ConnectorTypes.serviceNowITSM,
|
||||
},
|
||||
{
|
||||
expected: [
|
||||
{ id: 'approval', name: 'Approval', required: false, type: 'text' },
|
||||
{ id: 'close_notes', name: 'Close notes', required: false, type: 'textarea' },
|
||||
{ id: 'contact_type', name: 'Contact type', required: false, type: 'text' },
|
||||
{ id: 'correlation_display', name: 'Correlation display', required: false, type: 'text' },
|
||||
{ id: 'correlation_id', name: 'Correlation ID', required: false, type: 'text' },
|
||||
{ id: 'description', name: 'Description', required: false, type: 'textarea' },
|
||||
{ id: 'number', name: 'Number', required: false, type: 'text' },
|
||||
{ id: 'short_description', name: 'Short description', required: false, type: 'text' },
|
||||
{ id: 'sys_created_by', name: 'Created by', required: false, type: 'text' },
|
||||
{ id: 'sys_updated_by', name: 'Updated by', required: false, type: 'text' },
|
||||
{ id: 'upon_approval', name: 'Upon approval', required: false, type: 'text' },
|
||||
{ id: 'upon_reject', name: 'Upon reject', required: false, type: 'text' },
|
||||
],
|
||||
fields: serviceNowFields,
|
||||
type: ConnectorTypes.serviceNowSIR,
|
||||
},
|
||||
];
|
||||
export const mockGetFieldsResponse = {
|
||||
status: 'ok',
|
||||
|
|
|
@ -93,21 +93,26 @@ const findTextAreaField = (fields: ConnectorField[]): string =>
|
|||
const getPreferredFields = (theType: string) => {
|
||||
let title: string = '';
|
||||
let description: string = '';
|
||||
let comments: string = '';
|
||||
|
||||
if (theType === ConnectorTypes.jira) {
|
||||
title = 'summary';
|
||||
description = 'description';
|
||||
comments = 'comments';
|
||||
} else if (theType === ConnectorTypes.resilient) {
|
||||
title = 'name';
|
||||
description = 'description';
|
||||
comments = 'comments';
|
||||
} else if (
|
||||
theType === ConnectorTypes.serviceNowITSM ||
|
||||
theType === ConnectorTypes.serviceNowSIR
|
||||
) {
|
||||
title = 'short_description';
|
||||
description = 'description';
|
||||
comments = 'work_notes';
|
||||
}
|
||||
|
||||
return { title, description };
|
||||
return { title, description, comments };
|
||||
};
|
||||
|
||||
const getRemainingFields = (fields: ConnectorField[], titleTarget: string) =>
|
||||
|
@ -143,9 +148,16 @@ export const createDefaultMapping = (
|
|||
theType: string
|
||||
): ConnectorMappingsAttributes[] => {
|
||||
const { description: dynamicDescription, title: dynamicTitle } = getDynamicFields(fields);
|
||||
const { description: preferredDescription, title: preferredTitle } = getPreferredFields(theType);
|
||||
|
||||
const {
|
||||
description: preferredDescription,
|
||||
title: preferredTitle,
|
||||
comments: preferredComments,
|
||||
} = getPreferredFields(theType);
|
||||
|
||||
let titleTarget = dynamicTitle;
|
||||
let descriptionTarget = dynamicDescription;
|
||||
|
||||
if (preferredTitle.length > 0 && preferredDescription.length > 0) {
|
||||
if (shouldTargetBePreferred(fields, dynamicTitle, preferredTitle)) {
|
||||
const { description: dynamicDescriptionOverwrite } = getDynamicFields(fields, preferredTitle);
|
||||
|
@ -169,7 +181,7 @@ export const createDefaultMapping = (
|
|||
},
|
||||
{
|
||||
source: 'comments',
|
||||
target: 'comments',
|
||||
target: preferredComments,
|
||||
action_type: 'append',
|
||||
},
|
||||
];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue