mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Cases] Adding oldestPushDate field to get connectors API (#149451)
This PR adds the `oldestPushDate` field to the `_connectors` API. This is needed to determine whether to show the text `pushed as new incident <name>` or `updated incident <name>`. Update response ``` { "8548e270-9c26-11ed-8376-87998de9968e": { "name": "Jira", "type": ".jira", "fields": { "issueType": "10001", "parent": null, "priority": null }, "id": "8548e270-9c26-11ed-8376-87998de9968e", "needsToBePushed": false, "latestPushDate": "2023-01-24T20:35:54.325Z", "oldestPushDate": "2023-01-24T20:35:43.730Z", <--- New field "hasBeenPushed": true } } ```
This commit is contained in:
parent
026d347305
commit
e6f24a2272
5 changed files with 118 additions and 49 deletions
|
@ -120,7 +120,7 @@ export const GetCaseConnectorsResponseRt = rt.record(
|
|||
rt.string,
|
||||
rt.intersection([
|
||||
rt.type({ needsToBePushed: rt.boolean, hasBeenPushed: rt.boolean }),
|
||||
rt.partial(rt.type({ latestPushDate: rt.string }).props),
|
||||
rt.partial(rt.type({ latestPushDate: rt.string, oldestPushDate: rt.string }).props),
|
||||
CaseConnectorRt,
|
||||
])
|
||||
);
|
||||
|
|
|
@ -22,7 +22,7 @@ import type { CasesClientArgs } from '..';
|
|||
import type { Authorization, OwnerEntity } from '../../authorization';
|
||||
import { Operations } from '../../authorization';
|
||||
import type { GetConnectorsRequest } from './types';
|
||||
import type { CaseConnectorActivity, PushInfo } from '../../services/user_actions/types';
|
||||
import type { CaseConnectorActivity } from '../../services/user_actions/types';
|
||||
import type { CaseUserActionService } from '../../services';
|
||||
|
||||
export const getConnectors = async (
|
||||
|
@ -82,10 +82,18 @@ const checkConnectorsAuthorization = async ({
|
|||
});
|
||||
|
||||
if (connector.push) {
|
||||
entities.push({
|
||||
owner: connector.push.attributes.owner,
|
||||
id: connector.connectorId,
|
||||
});
|
||||
entities.push(
|
||||
...[
|
||||
{
|
||||
owner: connector.push.mostRecent.attributes.owner,
|
||||
id: connector.connectorId,
|
||||
},
|
||||
{
|
||||
owner: connector.push.oldest.attributes.owner,
|
||||
id: connector.connectorId,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +104,8 @@ const checkConnectorsAuthorization = async ({
|
|||
};
|
||||
|
||||
interface EnrichedPushInfo {
|
||||
pushDate: Date;
|
||||
latestPushDate: Date;
|
||||
oldestPushDate: Date;
|
||||
connectorFieldsUsedInPush: CaseConnector;
|
||||
}
|
||||
|
||||
|
@ -123,6 +132,12 @@ const getConnectorsInfo = async ({
|
|||
return createConnectorInfoResult({ actionConnectors, connectors, pushInfo, latestUserAction });
|
||||
};
|
||||
|
||||
interface PushTimeFrameDetails {
|
||||
connectorId: string;
|
||||
mostRecentPush: Date;
|
||||
oldestPush: Date;
|
||||
}
|
||||
|
||||
const getPushInfo = async ({
|
||||
caseId,
|
||||
activity,
|
||||
|
@ -132,29 +147,39 @@ const getPushInfo = async ({
|
|||
activity: CaseConnectorActivity[];
|
||||
userActionService: CaseUserActionService;
|
||||
}): Promise<Map<string, EnrichedPushInfo>> => {
|
||||
const pushRequest: PushInfo[] = [];
|
||||
const pushDetails: PushTimeFrameDetails[] = [];
|
||||
|
||||
for (const connectorInfo of activity) {
|
||||
const pushCreatedAt = getDate(connectorInfo.push?.attributes.created_at);
|
||||
const mostRecentPushCreatedAt = getDate(connectorInfo.push?.mostRecent.attributes.created_at);
|
||||
const oldestPushCreatedAt = getDate(connectorInfo.push?.oldest.attributes.created_at);
|
||||
|
||||
if (connectorInfo.push != null && pushCreatedAt != null) {
|
||||
pushRequest.push({ connectorId: connectorInfo.connectorId, date: pushCreatedAt });
|
||||
if (
|
||||
connectorInfo.push != null &&
|
||||
mostRecentPushCreatedAt != null &&
|
||||
oldestPushCreatedAt != null
|
||||
) {
|
||||
pushDetails.push({
|
||||
connectorId: connectorInfo.connectorId,
|
||||
mostRecentPush: mostRecentPushCreatedAt,
|
||||
oldestPush: oldestPushCreatedAt,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const connectorFieldsForPushes = await userActionService.getConnectorFieldsBeforeLatestPush(
|
||||
caseId,
|
||||
pushRequest
|
||||
pushDetails.map((push) => ({ connectorId: push.connectorId, date: push.mostRecentPush }))
|
||||
);
|
||||
|
||||
const enrichedPushInfo = new Map<string, EnrichedPushInfo>();
|
||||
for (const request of pushRequest) {
|
||||
const connectorFieldsSO = connectorFieldsForPushes.get(request.connectorId);
|
||||
for (const pushInfo of pushDetails) {
|
||||
const connectorFieldsSO = connectorFieldsForPushes.get(pushInfo.connectorId);
|
||||
const connectorFields = getConnectorInfoFromSavedObject(connectorFieldsSO);
|
||||
|
||||
if (connectorFields != null) {
|
||||
enrichedPushInfo.set(request.connectorId, {
|
||||
pushDate: request.date,
|
||||
enrichedPushInfo.set(pushInfo.connectorId, {
|
||||
latestPushDate: pushInfo.mostRecentPush,
|
||||
oldestPushDate: pushInfo.oldestPush,
|
||||
connectorFieldsUsedInPush: connectorFields,
|
||||
});
|
||||
}
|
||||
|
@ -223,7 +248,8 @@ const createConnectorInfoResult = ({
|
|||
...connector,
|
||||
name: connectorDetails.name,
|
||||
needsToBePushed,
|
||||
latestPushDate: enrichedPushInfo?.pushDate.toISOString(),
|
||||
latestPushDate: enrichedPushInfo?.latestPushDate.toISOString(),
|
||||
oldestPushDate: enrichedPushInfo?.oldestPushDate.toISOString(),
|
||||
hasBeenPushed: hasBeenPushed(enrichedPushInfo),
|
||||
};
|
||||
}
|
||||
|
@ -256,7 +282,9 @@ const hasDataToPush = ({
|
|||
* push fields will be undefined which will not equal the latest connector fields anyway.
|
||||
*/
|
||||
!isEqual(connector, pushInfo?.connectorFieldsUsedInPush) ||
|
||||
(pushInfo != null && latestUserActionDate != null && latestUserActionDate > pushInfo.pushDate)
|
||||
(pushInfo != null &&
|
||||
latestUserActionDate != null &&
|
||||
latestUserActionDate > pushInfo.latestPushDate)
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,13 @@ import {
|
|||
MAX_DOCS_PER_PAGE,
|
||||
} from '../../../common/constants';
|
||||
import { buildFilter, combineFilters } from '../../client/utils';
|
||||
import type { CaseConnectorActivity, CaseConnectorFields, PushInfo, ServiceContext } from './types';
|
||||
import type {
|
||||
CaseConnectorActivity,
|
||||
CaseConnectorFields,
|
||||
PushInfo,
|
||||
PushTimeFrameInfo,
|
||||
ServiceContext,
|
||||
} from './types';
|
||||
import { defaultSortField } from '../../common/utils';
|
||||
import { UserActionPersister } from './operations/create';
|
||||
import { UserActionFinder } from './operations/find';
|
||||
|
@ -37,15 +43,18 @@ export interface UserActionItem {
|
|||
references: SavedObjectReference[];
|
||||
}
|
||||
|
||||
interface MostRecentResults {
|
||||
mostRecent: {
|
||||
hits: {
|
||||
total: number;
|
||||
hits: SavedObjectsRawDoc[];
|
||||
};
|
||||
interface TopHits {
|
||||
hits: {
|
||||
total: number;
|
||||
hits: SavedObjectsRawDoc[];
|
||||
};
|
||||
}
|
||||
|
||||
interface TimeFrameInfo {
|
||||
mostRecent: TopHits;
|
||||
oldest: TopHits;
|
||||
}
|
||||
|
||||
interface ConnectorActivityAggsResult {
|
||||
references: {
|
||||
connectors: {
|
||||
|
@ -55,9 +64,9 @@ interface ConnectorActivityAggsResult {
|
|||
reverse: {
|
||||
connectorActivity: {
|
||||
buckets: {
|
||||
changeConnector: MostRecentResults;
|
||||
createCase: MostRecentResults;
|
||||
pushInfo: MostRecentResults;
|
||||
changeConnector: TimeFrameInfo;
|
||||
createCase: TimeFrameInfo;
|
||||
pushInfo: TimeFrameInfo;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -72,7 +81,7 @@ interface ConnectorFieldsBeforePushAggsResult {
|
|||
connectors: {
|
||||
reverse: {
|
||||
ids: {
|
||||
buckets: Record<string, MostRecentResults>;
|
||||
buckets: Record<string, TimeFrameInfo>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -381,28 +390,13 @@ export class CaseUserActionService {
|
|||
);
|
||||
}
|
||||
|
||||
const pushInfo = connectorInfo.reverse.connectorActivity.buckets.pushInfo;
|
||||
let pushDoc: SavedObject<CaseUserActionInjectedAttributesWithoutActionId> | undefined;
|
||||
|
||||
if (pushInfo.mostRecent.hits.hits.length > 0) {
|
||||
const rawPushDoc = pushInfo.mostRecent.hits.hits[0];
|
||||
|
||||
const doc =
|
||||
this.context.savedObjectsSerializer.rawToSavedObject<CaseUserActionAttributesWithoutConnectorId>(
|
||||
rawPushDoc
|
||||
);
|
||||
|
||||
pushDoc = transformToExternalModel(
|
||||
doc,
|
||||
this.context.persistableStateAttachmentTypeRegistry
|
||||
);
|
||||
}
|
||||
const pushDocs = this.getPushDocs(connectorInfo.reverse.connectorActivity.buckets.pushInfo);
|
||||
|
||||
if (fieldsDoc != null) {
|
||||
caseConnectorInfo.push({
|
||||
connectorId: connectorInfo.key,
|
||||
fields: fieldsDoc,
|
||||
push: pushDoc,
|
||||
push: pushDocs,
|
||||
});
|
||||
} else {
|
||||
this.context.log.warn(`Unable to find fields for connector id: ${connectorInfo.key}`);
|
||||
|
@ -412,6 +406,33 @@ export class CaseUserActionService {
|
|||
return caseConnectorInfo;
|
||||
}
|
||||
|
||||
private getPushDocs(pushTimeFrameInfo: TimeFrameInfo): PushTimeFrameInfo | undefined {
|
||||
const mostRecentPushDoc = this.getTopHitsDoc(pushTimeFrameInfo.mostRecent);
|
||||
const oldestPushDoc = this.getTopHitsDoc(pushTimeFrameInfo.oldest);
|
||||
|
||||
if (mostRecentPushDoc && oldestPushDoc) {
|
||||
return {
|
||||
mostRecent: mostRecentPushDoc,
|
||||
oldest: oldestPushDoc,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private getTopHitsDoc(
|
||||
topHits: TopHits
|
||||
): SavedObject<CaseUserActionInjectedAttributesWithoutActionId> | undefined {
|
||||
if (topHits.hits.hits.length > 0) {
|
||||
const rawPushDoc = topHits.hits.hits[0];
|
||||
|
||||
const doc =
|
||||
this.context.savedObjectsSerializer.rawToSavedObject<CaseUserActionAttributesWithoutConnectorId>(
|
||||
rawPushDoc
|
||||
);
|
||||
|
||||
return transformToExternalModel(doc, this.context.persistableStateAttachmentTypeRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
private static buildConnectorInfoAggs(): Record<
|
||||
string,
|
||||
estypes.AggregationsAggregationContainer
|
||||
|
@ -480,6 +501,18 @@ export class CaseUserActionService {
|
|||
size: 1,
|
||||
},
|
||||
},
|
||||
oldest: {
|
||||
top_hits: {
|
||||
sort: [
|
||||
{
|
||||
[`${CASE_USER_ACTION_SAVED_OBJECT}.created_at`]: {
|
||||
order: 'asc',
|
||||
},
|
||||
},
|
||||
],
|
||||
size: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -143,10 +143,15 @@ export interface ServiceContext {
|
|||
auditLogger: AuditLogger;
|
||||
}
|
||||
|
||||
export interface PushTimeFrameInfo {
|
||||
mostRecent: SavedObject<CaseUserActionInjectedAttributesWithoutActionId>;
|
||||
oldest: SavedObject<CaseUserActionInjectedAttributesWithoutActionId>;
|
||||
}
|
||||
|
||||
export interface CaseConnectorActivity {
|
||||
connectorId: string;
|
||||
fields: SavedObject<CaseUserActionInjectedAttributesWithoutActionId>;
|
||||
push?: SavedObject<CaseUserActionInjectedAttributesWithoutActionId>;
|
||||
push?: PushTimeFrameInfo;
|
||||
}
|
||||
|
||||
export type CaseConnectorFields = Map<
|
||||
|
|
|
@ -233,7 +233,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
|
||||
describe('push', () => {
|
||||
describe('latestPushDate', () => {
|
||||
it('does not set latestPushDate when the connector has not been used to push', async () => {
|
||||
it('does not set latestPushDate or oldestPushDate when the connector has not been used to push', async () => {
|
||||
const { postedCase, connector } = await createCaseWithConnector({
|
||||
supertest,
|
||||
serviceNowSimulatorURL,
|
||||
|
@ -245,9 +245,10 @@ 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);
|
||||
});
|
||||
|
||||
it('sets latestPushDate to the most recent push date', async () => {
|
||||
it('sets latestPushDate to the most recent push date and oldestPushDate to the first push date', async () => {
|
||||
const { postedCase, connector } = await createCaseWithConnector({
|
||||
supertest,
|
||||
serviceNowSimulatorURL,
|
||||
|
@ -278,10 +279,12 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
]);
|
||||
|
||||
const pushes = userActions.filter((ua) => ua.type === ActionTypes.pushed);
|
||||
const oldestPush = pushes[0];
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue