mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Cases] Adding new external services field for get connectors API (#149535)
This PR adds a new `externalServices` field for the get connector API. This is needed to show the "View <incident>" link in the case's action's menu. I moved all push related fields under a new `push` field as well. I also ran into some circular references since the API response now needs the external services type from the cases.ts file and the cases.ts file imports the connector index.ts so I refactored them. Example response ``` { "4175c370-9cd4-11ed-975e-43fe3caaded6": { "name": "Jira", "type": ".jira", "fields": { "issueType": "10001", "parent": null, "priority": null }, "id": "4175c370-9cd4-11ed-975e-43fe3caaded6", "push": { "needsToBePushed": false, "hasBeenPushed": true, "externalService": { "pushed_at": "2023-01-25T17:18:47.770Z", "pushed_by": { "username": "elastic", "full_name": null, "email": null, "profile_uid": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0" }, "connector_name": "Jira", "external_id": "10026", "external_title": "TPN-27", "external_url": "<url>", "connector_id": "4175c370-9cd4-11ed-975e-43fe3caaded6" }, "latestUserActionPushDate": "2023-01-25T17:18:47.819Z", "oldestUserActionPushDate": "2023-01-25T17:18:47.819Z" } } } ```
This commit is contained in:
parent
063850817b
commit
82afa05699
6 changed files with 315 additions and 172 deletions
|
@ -11,7 +11,7 @@ import { NumberFromString } from '../saved_object';
|
|||
import { UserRT } from '../user';
|
||||
import { CommentResponseRt } from './comment';
|
||||
import { CasesStatusResponseRt, CaseStatusRt } from './status';
|
||||
import { CaseConnectorRt } from '../connectors';
|
||||
import { CaseConnectorRt } from '../connectors/connector';
|
||||
import { CaseAssigneesRt } from './assignee';
|
||||
|
||||
export const AttachmentTotalsRt = rt.type({
|
||||
|
|
119
x-pack/plugins/cases/common/api/connectors/connector.ts
Normal file
119
x-pack/plugins/cases/common/api/connectors/connector.ts
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
|
||||
import type { ActionType } from '@kbn/actions-plugin/common';
|
||||
import type { ActionResult } from '@kbn/actions-plugin/server/types';
|
||||
import { JiraFieldsRT } from './jira';
|
||||
import { ResilientFieldsRT } from './resilient';
|
||||
import { ServiceNowITSMFieldsRT } from './servicenow_itsm';
|
||||
import { ServiceNowSIRFieldsRT } from './servicenow_sir';
|
||||
import { SwimlaneFieldsRT } from './swimlane';
|
||||
|
||||
export type ActionConnector = ActionResult;
|
||||
export type ActionTypeConnector = ActionType;
|
||||
|
||||
export const ConnectorFieldsRt = rt.union([
|
||||
JiraFieldsRT,
|
||||
ResilientFieldsRT,
|
||||
ServiceNowITSMFieldsRT,
|
||||
ServiceNowSIRFieldsRT,
|
||||
rt.null,
|
||||
]);
|
||||
|
||||
export enum ConnectorTypes {
|
||||
casesWebhook = '.cases-webhook',
|
||||
jira = '.jira',
|
||||
none = '.none',
|
||||
resilient = '.resilient',
|
||||
serviceNowITSM = '.servicenow',
|
||||
serviceNowSIR = '.servicenow-sir',
|
||||
swimlane = '.swimlane',
|
||||
}
|
||||
|
||||
const ConnectorCasesWebhookTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.casesWebhook),
|
||||
fields: rt.null,
|
||||
});
|
||||
|
||||
const ConnectorJiraTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.jira),
|
||||
fields: rt.union([JiraFieldsRT, rt.null]),
|
||||
});
|
||||
|
||||
const ConnectorResilientTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.resilient),
|
||||
fields: rt.union([ResilientFieldsRT, rt.null]),
|
||||
});
|
||||
|
||||
const ConnectorServiceNowITSMTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.serviceNowITSM),
|
||||
fields: rt.union([ServiceNowITSMFieldsRT, rt.null]),
|
||||
});
|
||||
|
||||
const ConnectorSwimlaneTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.swimlane),
|
||||
fields: rt.union([SwimlaneFieldsRT, rt.null]),
|
||||
});
|
||||
|
||||
const ConnectorServiceNowSIRTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.serviceNowSIR),
|
||||
fields: rt.union([ServiceNowSIRFieldsRT, rt.null]),
|
||||
});
|
||||
|
||||
const ConnectorNoneTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.none),
|
||||
fields: rt.null,
|
||||
});
|
||||
|
||||
export const NONE_CONNECTOR_ID: string = 'none';
|
||||
|
||||
export const ConnectorTypeFieldsRt = rt.union([
|
||||
ConnectorCasesWebhookTypeFieldsRt,
|
||||
ConnectorJiraTypeFieldsRt,
|
||||
ConnectorNoneTypeFieldsRt,
|
||||
ConnectorResilientTypeFieldsRt,
|
||||
ConnectorServiceNowITSMTypeFieldsRt,
|
||||
ConnectorServiceNowSIRTypeFieldsRt,
|
||||
ConnectorSwimlaneTypeFieldsRt,
|
||||
]);
|
||||
|
||||
/**
|
||||
* This type represents the connector's format when it is encoded within a user action.
|
||||
*/
|
||||
export const CaseUserActionConnectorRt = rt.union([
|
||||
rt.intersection([ConnectorCasesWebhookTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
rt.intersection([ConnectorJiraTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
rt.intersection([ConnectorNoneTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
rt.intersection([ConnectorResilientTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
rt.intersection([ConnectorServiceNowITSMTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
rt.intersection([ConnectorServiceNowSIRTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
rt.intersection([ConnectorSwimlaneTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
]);
|
||||
|
||||
export const CaseConnectorRt = rt.intersection([
|
||||
rt.type({
|
||||
id: rt.string,
|
||||
}),
|
||||
CaseUserActionConnectorRt,
|
||||
]);
|
||||
|
||||
export type CaseUserActionConnector = rt.TypeOf<typeof CaseUserActionConnectorRt>;
|
||||
export type CaseConnector = rt.TypeOf<typeof CaseConnectorRt>;
|
||||
export type ConnectorTypeFields = rt.TypeOf<typeof ConnectorTypeFieldsRt>;
|
||||
export type ConnectorCasesWebhookTypeFields = rt.TypeOf<typeof ConnectorCasesWebhookTypeFieldsRt>;
|
||||
export type ConnectorJiraTypeFields = rt.TypeOf<typeof ConnectorJiraTypeFieldsRt>;
|
||||
export type ConnectorResilientTypeFields = rt.TypeOf<typeof ConnectorResilientTypeFieldsRt>;
|
||||
export type ConnectorSwimlaneTypeFields = rt.TypeOf<typeof ConnectorSwimlaneTypeFieldsRt>;
|
||||
export type ConnectorServiceNowITSMTypeFields = rt.TypeOf<
|
||||
typeof ConnectorServiceNowITSMTypeFieldsRt
|
||||
>;
|
||||
export type ConnectorServiceNowSIRTypeFields = rt.TypeOf<typeof ConnectorServiceNowSIRTypeFieldsRt>;
|
||||
|
||||
// we need to change these types back and forth for storing in ES (arrays overwrite, objects merge)
|
||||
export type ConnectorFields = rt.TypeOf<typeof ConnectorFieldsRt>;
|
34
x-pack/plugins/cases/common/api/connectors/get_connectors.ts
Normal file
34
x-pack/plugins/cases/common/api/connectors/get_connectors.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { CaseConnectorRt } from './connector';
|
||||
import { CaseExternalServiceBasicRt } from '../cases';
|
||||
|
||||
const CaseConnectorPushInfoRt = rt.intersection([
|
||||
rt.type({
|
||||
needsToBePushed: rt.boolean,
|
||||
hasBeenPushed: rt.boolean,
|
||||
}),
|
||||
rt.partial({
|
||||
latestUserActionPushDate: rt.string,
|
||||
oldestUserActionPushDate: rt.string,
|
||||
externalService: CaseExternalServiceBasicRt,
|
||||
}),
|
||||
]);
|
||||
|
||||
export const GetCaseConnectorsResponseRt = rt.record(
|
||||
rt.string,
|
||||
rt.intersection([
|
||||
rt.type({
|
||||
push: CaseConnectorPushInfoRt,
|
||||
}),
|
||||
CaseConnectorRt,
|
||||
])
|
||||
);
|
||||
|
||||
export type GetCaseConnectorsResponse = rt.TypeOf<typeof GetCaseConnectorsResponseRt>;
|
|
@ -5,139 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
|
||||
import type { ActionType } from '@kbn/actions-plugin/common';
|
||||
/**
|
||||
* ActionResult type from the common folder is outdated.
|
||||
* The type from server is not exported properly so we
|
||||
* disable the linting for the moment
|
||||
*/
|
||||
|
||||
import type { ActionResult } from '@kbn/actions-plugin/server/types';
|
||||
import { JiraFieldsRT } from './jira';
|
||||
import { ResilientFieldsRT } from './resilient';
|
||||
import { ServiceNowITSMFieldsRT } from './servicenow_itsm';
|
||||
import { ServiceNowSIRFieldsRT } from './servicenow_sir';
|
||||
import { SwimlaneFieldsRT } from './swimlane';
|
||||
|
||||
export * from './jira';
|
||||
export * from './servicenow_itsm';
|
||||
export * from './servicenow_sir';
|
||||
export * from './resilient';
|
||||
export * from './mappings';
|
||||
export * from './swimlane';
|
||||
|
||||
export type ActionConnector = ActionResult;
|
||||
export type ActionTypeConnector = ActionType;
|
||||
|
||||
export const ConnectorFieldsRt = rt.union([
|
||||
JiraFieldsRT,
|
||||
ResilientFieldsRT,
|
||||
ServiceNowITSMFieldsRT,
|
||||
ServiceNowSIRFieldsRT,
|
||||
rt.null,
|
||||
]);
|
||||
|
||||
export enum ConnectorTypes {
|
||||
casesWebhook = '.cases-webhook',
|
||||
jira = '.jira',
|
||||
none = '.none',
|
||||
resilient = '.resilient',
|
||||
serviceNowITSM = '.servicenow',
|
||||
serviceNowSIR = '.servicenow-sir',
|
||||
swimlane = '.swimlane',
|
||||
}
|
||||
|
||||
const ConnectorCasesWebhookTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.casesWebhook),
|
||||
fields: rt.null,
|
||||
});
|
||||
|
||||
const ConnectorJiraTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.jira),
|
||||
fields: rt.union([JiraFieldsRT, rt.null]),
|
||||
});
|
||||
|
||||
const ConnectorResilientTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.resilient),
|
||||
fields: rt.union([ResilientFieldsRT, rt.null]),
|
||||
});
|
||||
|
||||
const ConnectorServiceNowITSMTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.serviceNowITSM),
|
||||
fields: rt.union([ServiceNowITSMFieldsRT, rt.null]),
|
||||
});
|
||||
|
||||
const ConnectorSwimlaneTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.swimlane),
|
||||
fields: rt.union([SwimlaneFieldsRT, rt.null]),
|
||||
});
|
||||
|
||||
const ConnectorServiceNowSIRTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.serviceNowSIR),
|
||||
fields: rt.union([ServiceNowSIRFieldsRT, rt.null]),
|
||||
});
|
||||
|
||||
const ConnectorNoneTypeFieldsRt = rt.type({
|
||||
type: rt.literal(ConnectorTypes.none),
|
||||
fields: rt.null,
|
||||
});
|
||||
|
||||
export const NONE_CONNECTOR_ID: string = 'none';
|
||||
|
||||
export const ConnectorTypeFieldsRt = rt.union([
|
||||
ConnectorCasesWebhookTypeFieldsRt,
|
||||
ConnectorJiraTypeFieldsRt,
|
||||
ConnectorNoneTypeFieldsRt,
|
||||
ConnectorResilientTypeFieldsRt,
|
||||
ConnectorServiceNowITSMTypeFieldsRt,
|
||||
ConnectorServiceNowSIRTypeFieldsRt,
|
||||
ConnectorSwimlaneTypeFieldsRt,
|
||||
]);
|
||||
|
||||
/**
|
||||
* This type represents the connector's format when it is encoded within a user action.
|
||||
*/
|
||||
export const CaseUserActionConnectorRt = rt.union([
|
||||
rt.intersection([ConnectorCasesWebhookTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
rt.intersection([ConnectorJiraTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
rt.intersection([ConnectorNoneTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
rt.intersection([ConnectorResilientTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
rt.intersection([ConnectorServiceNowITSMTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
rt.intersection([ConnectorServiceNowSIRTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
rt.intersection([ConnectorSwimlaneTypeFieldsRt, rt.type({ name: rt.string })]),
|
||||
]);
|
||||
|
||||
export const CaseConnectorRt = rt.intersection([
|
||||
rt.type({
|
||||
id: rt.string,
|
||||
}),
|
||||
CaseUserActionConnectorRt,
|
||||
]);
|
||||
|
||||
export const GetCaseConnectorsResponseRt = rt.record(
|
||||
rt.string,
|
||||
rt.intersection([
|
||||
rt.type({ needsToBePushed: rt.boolean, hasBeenPushed: rt.boolean }),
|
||||
rt.partial(rt.type({ latestPushDate: rt.string, oldestPushDate: rt.string }).props),
|
||||
CaseConnectorRt,
|
||||
])
|
||||
);
|
||||
|
||||
export type CaseUserActionConnector = rt.TypeOf<typeof CaseUserActionConnectorRt>;
|
||||
export type CaseConnector = rt.TypeOf<typeof CaseConnectorRt>;
|
||||
export type ConnectorTypeFields = rt.TypeOf<typeof ConnectorTypeFieldsRt>;
|
||||
export type ConnectorCasesWebhookTypeFields = rt.TypeOf<typeof ConnectorCasesWebhookTypeFieldsRt>;
|
||||
export type ConnectorJiraTypeFields = rt.TypeOf<typeof ConnectorJiraTypeFieldsRt>;
|
||||
export type ConnectorResilientTypeFields = rt.TypeOf<typeof ConnectorResilientTypeFieldsRt>;
|
||||
export type ConnectorSwimlaneTypeFields = rt.TypeOf<typeof ConnectorSwimlaneTypeFieldsRt>;
|
||||
export type ConnectorServiceNowITSMTypeFields = rt.TypeOf<
|
||||
typeof ConnectorServiceNowITSMTypeFieldsRt
|
||||
>;
|
||||
export type ConnectorServiceNowSIRTypeFields = rt.TypeOf<typeof ConnectorServiceNowSIRTypeFieldsRt>;
|
||||
|
||||
// we need to change these types back and forth for storing in ES (arrays overwrite, objects merge)
|
||||
export type ConnectorFields = rt.TypeOf<typeof ConnectorFieldsRt>;
|
||||
|
||||
export type GetCaseConnectorsResponse = rt.TypeOf<typeof GetCaseConnectorsResponseRt>;
|
||||
export * from './get_connectors';
|
||||
export * from './connector';
|
||||
|
|
|
@ -14,9 +14,14 @@ import type {
|
|||
GetCaseConnectorsResponse,
|
||||
CaseConnector,
|
||||
CaseUserActionInjectedAttributesWithoutActionId,
|
||||
CaseExternalServiceBasic,
|
||||
} from '../../../common/api';
|
||||
import { GetCaseConnectorsResponseRt } from '../../../common/api';
|
||||
import { isConnectorUserAction, isCreateCaseUserAction } from '../../../common/utils/user_actions';
|
||||
import {
|
||||
isConnectorUserAction,
|
||||
isCreateCaseUserAction,
|
||||
isPushedUserAction,
|
||||
} from '../../../common/utils/user_actions';
|
||||
import { createCaseError } from '../../common/error';
|
||||
import type { CasesClientArgs } from '..';
|
||||
import type { Authorization, OwnerEntity } from '../../authorization';
|
||||
|
@ -106,6 +111,7 @@ const checkConnectorsAuthorization = async ({
|
|||
interface EnrichedPushInfo {
|
||||
latestPushDate: Date;
|
||||
oldestPushDate: Date;
|
||||
externalService: CaseExternalServiceBasic;
|
||||
connectorFieldsUsedInPush: CaseConnector;
|
||||
}
|
||||
|
||||
|
@ -125,20 +131,21 @@ const getConnectorsInfo = async ({
|
|||
const connectorIds = connectors.map((connector) => connector.connectorId);
|
||||
|
||||
const [pushInfo, actionConnectors] = await Promise.all([
|
||||
getPushInfo({ caseId, activity: connectors, userActionService }),
|
||||
getEnrichedPushInfo({ caseId, activity: connectors, userActionService }),
|
||||
actionsClient.getBulk(connectorIds),
|
||||
]);
|
||||
|
||||
return createConnectorInfoResult({ actionConnectors, connectors, pushInfo, latestUserAction });
|
||||
};
|
||||
|
||||
interface PushTimeFrameDetails {
|
||||
interface PushDetails {
|
||||
connectorId: string;
|
||||
externalService: CaseExternalServiceBasic;
|
||||
mostRecentPush: Date;
|
||||
oldestPush: Date;
|
||||
}
|
||||
|
||||
const getPushInfo = async ({
|
||||
const getEnrichedPushInfo = async ({
|
||||
caseId,
|
||||
activity,
|
||||
userActionService,
|
||||
|
@ -147,24 +154,7 @@ const getPushInfo = async ({
|
|||
activity: CaseConnectorActivity[];
|
||||
userActionService: CaseUserActionService;
|
||||
}): Promise<Map<string, EnrichedPushInfo>> => {
|
||||
const pushDetails: PushTimeFrameDetails[] = [];
|
||||
|
||||
for (const connectorInfo of activity) {
|
||||
const mostRecentPushCreatedAt = getDate(connectorInfo.push?.mostRecent.attributes.created_at);
|
||||
const oldestPushCreatedAt = getDate(connectorInfo.push?.oldest.attributes.created_at);
|
||||
|
||||
if (
|
||||
connectorInfo.push != null &&
|
||||
mostRecentPushCreatedAt != null &&
|
||||
oldestPushCreatedAt != null
|
||||
) {
|
||||
pushDetails.push({
|
||||
connectorId: connectorInfo.connectorId,
|
||||
mostRecentPush: mostRecentPushCreatedAt,
|
||||
oldestPush: oldestPushCreatedAt,
|
||||
});
|
||||
}
|
||||
}
|
||||
const pushDetails = getPushDetails(activity);
|
||||
|
||||
const connectorFieldsForPushes = await userActionService.getConnectorFieldsBeforeLatestPush(
|
||||
caseId,
|
||||
|
@ -180,6 +170,7 @@ const getPushInfo = async ({
|
|||
enrichedPushInfo.set(pushInfo.connectorId, {
|
||||
latestPushDate: pushInfo.mostRecentPush,
|
||||
oldestPushDate: pushInfo.oldestPush,
|
||||
externalService: pushInfo.externalService,
|
||||
connectorFieldsUsedInPush: connectorFields,
|
||||
});
|
||||
}
|
||||
|
@ -188,6 +179,40 @@ const getPushInfo = async ({
|
|||
return enrichedPushInfo;
|
||||
};
|
||||
|
||||
const getPushDetails = (activity: CaseConnectorActivity[]) => {
|
||||
const pushDetails: PushDetails[] = [];
|
||||
|
||||
for (const connectorInfo of activity) {
|
||||
const externalService = getExternalServiceFromSavedObject(connectorInfo.push?.mostRecent);
|
||||
const mostRecentPushCreatedAt = getDate(connectorInfo.push?.mostRecent.attributes.created_at);
|
||||
const oldestPushCreatedAt = getDate(connectorInfo.push?.oldest.attributes.created_at);
|
||||
|
||||
if (
|
||||
connectorInfo.push != null &&
|
||||
externalService != null &&
|
||||
mostRecentPushCreatedAt != null &&
|
||||
oldestPushCreatedAt != null
|
||||
) {
|
||||
pushDetails.push({
|
||||
connectorId: connectorInfo.connectorId,
|
||||
externalService,
|
||||
mostRecentPush: mostRecentPushCreatedAt,
|
||||
oldestPush: oldestPushCreatedAt,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return pushDetails;
|
||||
};
|
||||
|
||||
const getExternalServiceFromSavedObject = (
|
||||
savedObject: SavedObject<CaseUserActionInjectedAttributesWithoutActionId> | undefined
|
||||
): CaseExternalServiceBasic | undefined => {
|
||||
if (savedObject != null && isPushedUserAction(savedObject.attributes)) {
|
||||
return savedObject.attributes.payload.externalService;
|
||||
}
|
||||
};
|
||||
|
||||
const getDate = (timestamp: string | undefined): Date | undefined => {
|
||||
if (timestamp == null) {
|
||||
return;
|
||||
|
@ -247,10 +272,13 @@ const createConnectorInfoResult = ({
|
|||
results[connector.id] = {
|
||||
...connector,
|
||||
name: connectorDetails.name,
|
||||
needsToBePushed,
|
||||
latestPushDate: enrichedPushInfo?.latestPushDate.toISOString(),
|
||||
oldestPushDate: enrichedPushInfo?.oldestPushDate.toISOString(),
|
||||
hasBeenPushed: hasBeenPushed(enrichedPushInfo),
|
||||
push: {
|
||||
needsToBePushed,
|
||||
hasBeenPushed: hasBeenPushed(enrichedPushInfo),
|
||||
externalService: enrichedPushInfo?.externalService,
|
||||
latestUserActionPushDate: enrichedPushInfo?.latestPushDate.toISOString(),
|
||||
oldestUserActionPushDate: enrichedPushInfo?.oldestPushDate.toISOString(),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
urgency: '2',
|
||||
});
|
||||
|
||||
expect(snConnector.needsToBePushed).to.be(false);
|
||||
expect(snConnector.push.needsToBePushed).to.be(false);
|
||||
expect(snConnector.name).to.be('ServiceNow Connector');
|
||||
expect(snConnector.id).to.be(connector.id);
|
||||
});
|
||||
|
@ -232,6 +232,92 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
});
|
||||
|
||||
describe('push', () => {
|
||||
describe('externalService', () => {
|
||||
it('sets externalService field to the most recent push info', async () => {
|
||||
const { postedCase, connector } = await createCaseWithConnector({
|
||||
supertest,
|
||||
serviceNowSimulatorURL,
|
||||
actionsRemover,
|
||||
});
|
||||
|
||||
await pushCase({
|
||||
supertest,
|
||||
caseId: postedCase.id,
|
||||
connectorId: connector.id,
|
||||
});
|
||||
|
||||
const pachedCase = await createComment({
|
||||
supertest,
|
||||
caseId: postedCase.id,
|
||||
params: postCommentUserReq,
|
||||
});
|
||||
|
||||
const serviceNow2 = await createConnector({
|
||||
supertest,
|
||||
req: {
|
||||
...getServiceNowConnector(),
|
||||
name: 'ServiceNow 2 Connector',
|
||||
config: { apiUrl: serviceNowSimulatorURL },
|
||||
},
|
||||
});
|
||||
|
||||
actionsRemover.add('default', serviceNow2.id, 'action', 'actions');
|
||||
|
||||
// change to serviceNow2 connector
|
||||
await updateCase({
|
||||
supertest,
|
||||
params: {
|
||||
cases: [
|
||||
{
|
||||
id: pachedCase.id,
|
||||
version: pachedCase.version,
|
||||
connector: {
|
||||
id: serviceNow2.id,
|
||||
name: 'ServiceNow 2 Connector',
|
||||
type: ConnectorTypes.serviceNowITSM,
|
||||
fields: {
|
||||
urgency: '2',
|
||||
impact: '2',
|
||||
severity: '2',
|
||||
category: 'software',
|
||||
subcategory: 'os',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
await pushCase({
|
||||
supertest,
|
||||
caseId: pachedCase.id,
|
||||
connectorId: serviceNow2.id,
|
||||
});
|
||||
|
||||
const [userActions, connectors] = await Promise.all([
|
||||
getCaseUserActions({ supertest, caseID: postedCase.id }),
|
||||
getConnectors({ caseId: postedCase.id, supertest }),
|
||||
]);
|
||||
|
||||
const pushes = userActions.filter((ua) => ua.type === ActionTypes.pushed);
|
||||
const latestPush = pushes[pushes.length - 1];
|
||||
|
||||
expect(Object.keys(connectors).length).to.be(2);
|
||||
expect(connectors[serviceNow2.id].push.latestUserActionPushDate).to.eql(
|
||||
latestPush.created_at
|
||||
);
|
||||
expect(connectors[serviceNow2.id].push.externalService?.connector_id).to.eql(
|
||||
serviceNow2.id
|
||||
);
|
||||
expect(connectors[serviceNow2.id].push.externalService?.connector_name).to.eql(
|
||||
serviceNow2.name
|
||||
);
|
||||
expect(connectors[serviceNow2.id].push.externalService?.connector_name).to.not.eql(
|
||||
connector.name
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('latestPushDate', () => {
|
||||
it('does not set latestPushDate or oldestPushDate when the connector has not been used to push', async () => {
|
||||
const { postedCase, connector } = await createCaseWithConnector({
|
||||
|
@ -244,8 +330,8 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
expect(Object.keys(connectors).length).to.be(1);
|
||||
expect(connectors).to.have.property(connector.id);
|
||||
expect(connectors[connector.id].latestPushDate).to.be(undefined);
|
||||
expect(connectors[connector.id].oldestPushDate).to.be(undefined);
|
||||
expect(connectors[connector.id].push.latestUserActionPushDate).to.be(undefined);
|
||||
expect(connectors[connector.id].push.oldestUserActionPushDate).to.be(undefined);
|
||||
});
|
||||
|
||||
it('sets latestPushDate to the most recent push date and oldestPushDate to the first push date', async () => {
|
||||
|
@ -283,8 +369,12 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
const latestPush = pushes[pushes.length - 1];
|
||||
|
||||
expect(Object.keys(connectors).length).to.be(1);
|
||||
expect(connectors[connector.id].latestPushDate).to.eql(latestPush.created_at);
|
||||
expect(connectors[connector.id].oldestPushDate).to.eql(oldestPush.created_at);
|
||||
expect(connectors[connector.id].push.latestUserActionPushDate).to.eql(
|
||||
latestPush.created_at
|
||||
);
|
||||
expect(connectors[connector.id].push.oldestUserActionPushDate).to.eql(
|
||||
oldestPush.created_at
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -299,7 +389,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
const connectors = await getConnectors({ caseId: postedCase.id, supertest });
|
||||
|
||||
expect(Object.keys(connectors).length).to.be(1);
|
||||
expect(connectors[connector.id].hasBeenPushed).to.be(false);
|
||||
expect(connectors[connector.id].push.hasBeenPushed).to.be(false);
|
||||
});
|
||||
|
||||
it('sets hasBeenPushed to true when the connector was used to push', async () => {
|
||||
|
@ -318,7 +408,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
const connectors = await getConnectors({ caseId: postedCase.id, supertest });
|
||||
|
||||
expect(Object.keys(connectors).length).to.be(1);
|
||||
expect(connectors[connector.id].hasBeenPushed).to.be(true);
|
||||
expect(connectors[connector.id].push.hasBeenPushed).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -334,7 +424,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
expect(Object.keys(connectors).length).to.be(1);
|
||||
expect(connectors[connector.id].id).to.be(connector.id);
|
||||
expect(connectors[connector.id].needsToBePushed).to.be(true);
|
||||
expect(connectors[connector.id].push.needsToBePushed).to.be(true);
|
||||
});
|
||||
|
||||
it('sets needs to push to false when a push has occurred', async () => {
|
||||
|
@ -354,7 +444,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
expect(Object.keys(connectors).length).to.be(1);
|
||||
expect(connectors[connector.id].id).to.be(connector.id);
|
||||
expect(connectors[connector.id].needsToBePushed).to.be(false);
|
||||
expect(connectors[connector.id].push.needsToBePushed).to.be(false);
|
||||
});
|
||||
|
||||
it('sets needs to push to true when a comment was created after the last push', async () => {
|
||||
|
@ -380,7 +470,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
expect(Object.keys(connectors).length).to.be(1);
|
||||
expect(connectors[connector.id].id).to.be(connector.id);
|
||||
expect(connectors[connector.id].needsToBePushed).to.be(true);
|
||||
expect(connectors[connector.id].push.needsToBePushed).to.be(true);
|
||||
});
|
||||
|
||||
it('sets needs to push to false when the severity of a case was changed after the last push', async () => {
|
||||
|
@ -413,7 +503,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
expect(Object.keys(connectors).length).to.be(1);
|
||||
expect(connectors[connector.id].id).to.be(connector.id);
|
||||
expect(connectors[connector.id].needsToBePushed).to.be(false);
|
||||
expect(connectors[connector.id].push.needsToBePushed).to.be(false);
|
||||
});
|
||||
|
||||
it('sets needs to push to false the service now connector and true for jira', async () => {
|
||||
|
@ -461,9 +551,9 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
expect(Object.keys(connectors).length).to.be(2);
|
||||
expect(connectors[serviceNowConnector.id].id).to.be(serviceNowConnector.id);
|
||||
expect(connectors[serviceNowConnector.id].needsToBePushed).to.be(false);
|
||||
expect(connectors[serviceNowConnector.id].push.needsToBePushed).to.be(false);
|
||||
expect(connectors[jiraConnector.id].id).to.be(jiraConnector.id);
|
||||
expect(connectors[jiraConnector.id].needsToBePushed).to.be(true);
|
||||
expect(connectors[jiraConnector.id].push.needsToBePushed).to.be(true);
|
||||
});
|
||||
|
||||
describe('changing connector fields', () => {
|
||||
|
@ -564,7 +654,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
expect(Object.keys(connectors).length).to.be(1);
|
||||
expect(connectors[serviceNowConnector.id].id).to.be(serviceNowConnector.id);
|
||||
expect(connectors[serviceNowConnector.id].needsToBePushed).to.be(false);
|
||||
expect(connectors[serviceNowConnector.id].push.needsToBePushed).to.be(false);
|
||||
});
|
||||
|
||||
it('sets needs to push to true when the latest connector fields do not match those used in the push', async () => {
|
||||
|
@ -609,7 +699,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
expect(Object.keys(connectors).length).to.be(1);
|
||||
expect(connectors[serviceNowConnector.id].id).to.be(serviceNowConnector.id);
|
||||
expect(connectors[serviceNowConnector.id].needsToBePushed).to.be(true);
|
||||
expect(connectors[serviceNowConnector.id].push.needsToBePushed).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue