Skip to content

Commit

Permalink
[Cases] Refactor the getConnectors push field (#149983)
Browse files Browse the repository at this point in the history
This PR moves all the optional fields from the get connectors API into a
single optional field. This better communicates that the API will return
all the fields as undefined for they will all be defined.

Example response
```
{
    "4175c370-9cd4-11ed-975e-43fe3caaded6": {
        ...
        "push": {
            "needsToBePushed": false,
            "hasBeenPushed": true,
            "details": {
                "externalService": {
                    ...
                },
                "latestUserActionPushDate": "2023-01-25T17:18:47.819Z",
                "oldestUserActionPushDate": "2023-01-25T17:18:47.819Z"
            }
        }
    }
}
```
  • Loading branch information
jonathan-buttner authored Feb 1, 2023
1 parent 3fbbbd4 commit 6ecac19
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 44 deletions.
11 changes: 8 additions & 3 deletions x-pack/plugins/cases/common/api/connectors/get_connectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ import * as rt from 'io-ts';
import { CaseConnectorRt } from './connector';
import { CaseExternalServiceBasicRt } from '../cases';

const PushDetailsRt = rt.type({
latestUserActionPushDate: rt.string,
oldestUserActionPushDate: rt.string,
externalService: CaseExternalServiceBasicRt,
});

const CaseConnectorPushInfoRt = rt.intersection([
rt.type({
needsToBePushed: rt.boolean,
hasBeenPushed: rt.boolean,
}),
rt.partial({
latestUserActionPushDate: rt.string,
oldestUserActionPushDate: rt.string,
externalService: CaseExternalServiceBasicRt,
details: PushDetailsRt,
}),
]);

Expand All @@ -32,3 +36,4 @@ export const GetCaseConnectorsResponseRt = rt.record(
);

export type GetCaseConnectorsResponse = rt.TypeOf<typeof GetCaseConnectorsResponseRt>;
export type GetCaseConnectorsPushDetails = rt.TypeOf<typeof PushDetailsRt>;
47 changes: 34 additions & 13 deletions x-pack/plugins/cases/public/common/mock/connectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import { set } from 'lodash';
import type { ActionConnector, ActionTypeConnector } from '../../../common/api';
import { basicPush } from '../../containers/mock';
import type { CaseConnectors } from '../../containers/types';
Expand Down Expand Up @@ -121,11 +122,23 @@ export const actionTypesMock: ActionTypeConnector[] = [
},
];

/**
* Construct a mock getConnectors response object
*
* @param overrides is an object where the key is the path for setting a field in the returned object. For example to set
* the externalService.connectorId pass the following overrides object:
*
* ```
* {
* 'push.details.externalService.connectorId': '123'
* }
* ```
*/
export const getCaseConnectorsMockResponse = (
overrides: Partial<CaseConnectors[string]['push']> = {}
overrides?: Record<string, unknown>
): CaseConnectors => {
return connectorsMock.reduce(
(acc, connector) => ({
return connectorsMock.reduce((acc, connector) => {
const newConnectors: CaseConnectors = {
...acc,
[connector.id]: {
id: connector.id,
Expand All @@ -134,18 +147,26 @@ export const getCaseConnectorsMockResponse = (
fields: null,
push: {
needsToBePushed: false,
oldestUserActionPushDate: '2023-01-17T09:46:29.813Z',
latestUserActionPushDate: '2023-01-17T09:46:29.813Z',
hasBeenPushed: true,
externalService: {
...basicPush,
connectorId: connector.id,
connectorName: connector.name,
details: {
oldestUserActionPushDate: '2023-01-17T09:46:29.813Z',
latestUserActionPushDate: '2023-01-17T09:46:29.813Z',
externalService: {
...basicPush,
connectorId: connector.id,
connectorName: connector.name,
},
},
...overrides,
},
},
}),
{}
);
};

if (overrides != null) {
for (const path of Object.keys(overrides)) {
set(newConnectors[connector.id], path, overrides[path]);
}
}

return newConnectors;
}, {});
};
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const CaseActionBarComponent: React.FC<CaseActionBarProps> = ({
);

const currentExternalIncident =
caseConnectors?.[caseData.connector.id]?.push.externalService ?? null;
caseConnectors?.[caseData.connector.id]?.push.details?.externalService ?? null;

const onSyncAlertsChanged = useCallback(
(syncAlerts: boolean) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ describe(`UserActions`, () => {
});

it('Renders service now update line with top and bottom when push is required', async () => {
const caseConnectors = getCaseConnectorsMockResponse({ needsToBePushed: true });
const caseConnectors = getCaseConnectorsMockResponse({ 'push.needsToBePushed': true });

const ourActions = [
getUserAction('pushed', 'push_to_service', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ describe('createPushedUserActionBuilder ', () => {

it('renders correctly if oldestUserActionPushDate is not defined', async () => {
const userAction = getUserAction('pushed', Actions.push_to_service);
const caseConnectors = getCaseConnectorsMockResponse({ oldestUserActionPushDate: undefined });
const caseConnectors = getCaseConnectorsMockResponse({
'push.details.oldestUserActionPushDate': undefined,
});
const builder = createPushedUserActionBuilder({
...builderArgs,
caseConnectors,
Expand All @@ -69,7 +71,7 @@ describe('createPushedUserActionBuilder ', () => {
it('renders correctly when updating an external service', async () => {
const userAction = getUserAction('pushed', Actions.push_to_service);
const caseConnectors = getCaseConnectorsMockResponse({
oldestUserActionPushDate: '2023-01-16T09:46:29.813Z',
'push.details.oldestUserActionPushDate': '2023-01-16T09:46:29.813Z',
});

const builder = createPushedUserActionBuilder({
Expand Down Expand Up @@ -113,7 +115,7 @@ describe('createPushedUserActionBuilder ', () => {

it('shows both footers if the connectors needs to be pushed and is the latest push', async () => {
const caseConnectors = getCaseConnectorsMockResponse({
needsToBePushed: true,
'push.needsToBePushed': true,
});

const userAction = getUserAction('pushed', Actions.push_to_service, {
Expand Down Expand Up @@ -164,8 +166,8 @@ describe('createPushedUserActionBuilder ', () => {

it('does not show the footers if latestUserActionPushDate is not defined', async () => {
const caseConnectors = getCaseConnectorsMockResponse({
needsToBePushed: true,
latestUserActionPushDate: undefined,
'push.needsToBePushed': true,
'push.details.latestUserActionPushDate': undefined,
});

const userAction = getUserAction('pushed', Actions.push_to_service, {
Expand Down Expand Up @@ -195,7 +197,7 @@ describe('createPushedUserActionBuilder ', () => {
});

it('does not show the push information if the connector is none', async () => {
const caseConnectors = getCaseConnectorsMockResponse({ needsToBePushed: true });
const caseConnectors = getCaseConnectorsMockResponse({ 'push.needsToBePushed': true });
const userAction = getUserAction('pushed', Actions.push_to_service, {
createdAt: '2023-01-17T09:46:29.813Z',
payload: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const getFooters = ({
const footers: EuiCommentProps[] = [];
const latestPush = isLatestPush(
userAction.createdAt,
connectorInfo.push.latestUserActionPushDate
connectorInfo.push.details?.latestUserActionPushDate
);

const showTopFooter = userAction.action === Actions.push_to_service && latestPush;
Expand Down Expand Up @@ -135,7 +135,7 @@ export const createPushedUserActionBuilder: UserActionBuilder = ({

const firstPush = isFirstPush(
userAction.createdAt,
connectorInfo.push.oldestUserActionPushDate
connectorInfo.push.details?.oldestUserActionPushDate
);
const footers = getFooters({ userAction: pushedUserAction, connectorInfo });
const label = getLabelTitle(pushedUserAction, firstPush);
Expand Down
7 changes: 3 additions & 4 deletions x-pack/plugins/cases/public/containers/api.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import {
import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from './use_get_cases';
import { getCasesStatus } from '../api';
import { getCaseConnectorsMockResponse } from '../common/mock/connectors';
import { cloneDeep, set } from 'lodash';

const abortCtrl = new AbortController();
const mockKibanaServices = KibanaServices.get as jest.Mock;
Expand Down Expand Up @@ -855,10 +856,8 @@ describe('Cases API', () => {
const caseConnectors = getCaseConnectorsMockResponse();
const connectorCamelCase = caseConnectors['servicenow-1'];

const snakeCaseConnector = {
...connectorCamelCase,
push: { ...connectorCamelCase.push, externalService: basicPushSnake },
};
const snakeCaseConnector = cloneDeep(connectorCamelCase);
set(snakeCaseConnector, 'push.details.externalService', basicPushSnake);

beforeEach(() => {
fetchMock.mockClear();
Expand Down
21 changes: 18 additions & 3 deletions x-pack/plugins/cases/server/client/user_actions/connectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
CaseConnector,
CaseUserActionInjectedAttributes,
CaseExternalServiceBasic,
GetCaseConnectorsPushDetails,
} from '../../../common/api';
import { GetCaseConnectorsResponseRt } from '../../../common/api';
import {
Expand Down Expand Up @@ -288,15 +289,15 @@ const createConnectorInfoResult = ({
latestUserActionDate: latestUserActionCreatedAt,
});

const pushDetails = convertEnrichedPushInfoToDetails(enrichedPushInfo);

results[connector.id] = {
...connector,
name: connectorDetails?.name ?? connector.name,
push: {
needsToBePushed,
hasBeenPushed: hasBeenPushed(enrichedPushInfo),
externalService: enrichedPushInfo?.externalService,
latestUserActionPushDate: enrichedPushInfo?.latestPushDate.toISOString(),
oldestUserActionPushDate: enrichedPushInfo?.oldestPushDate.toISOString(),
...(pushDetails && { details: pushDetails }),
},
};
}
Expand Down Expand Up @@ -338,3 +339,17 @@ const hasDataToPush = ({
const hasBeenPushed = (pushInfo: EnrichedPushInfo | undefined): boolean => {
return pushInfo != null;
};

const convertEnrichedPushInfoToDetails = (
info: EnrichedPushInfo | undefined
): GetCaseConnectorsPushDetails | undefined => {
if (info == null) {
return;
}

return {
latestUserActionPushDate: info.latestPushDate.toISOString(),
oldestUserActionPushDate: info.oldestPushDate.toISOString(),
externalService: info.externalService,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -308,19 +308,19 @@ export default ({ getService }: FtrProviderContext): void => {
const latestPush = pushes[pushes.length - 1];

expect(Object.keys(connectors).length).to.be(2);
expect(connectors[serviceNow2.id].push.latestUserActionPushDate).to.eql(
expect(connectors[serviceNow2.id].push.details?.latestUserActionPushDate).to.eql(
latestPush.created_at
);
expect(connectors[serviceNow2.id].push.externalService?.connector_id).to.eql(
expect(connectors[serviceNow2.id].push.details?.externalService?.connector_id).to.eql(
serviceNow2.id
);
expect(connectors[serviceNow2.id].push.externalService?.connector_name).to.eql(
expect(connectors[serviceNow2.id].push.details?.externalService?.connector_name).to.eql(
serviceNow2.name
);
expect(connectors[serviceNow2.id].push.externalService?.connector_name).to.not.eql(
connector.name
);
expect(connectors[serviceNow2.id].push.externalService?.connector_id).to.not.eql(
expect(
connectors[serviceNow2.id].push.details?.externalService?.connector_name
).to.not.eql(connector.name);
expect(connectors[serviceNow2.id].push.details?.externalService?.connector_id).to.not.eql(
connector.id
);
});
Expand All @@ -338,8 +338,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].push.latestUserActionPushDate).to.be(undefined);
expect(connectors[connector.id].push.oldestUserActionPushDate).to.be(undefined);
expect(connectors[connector.id].push.details?.latestUserActionPushDate).to.be(undefined);
expect(connectors[connector.id].push.details?.oldestUserActionPushDate).to.be(undefined);
});

it('sets latestUserActionPushDate to the most recent push date and oldestPushDate to the first push date', async () => {
Expand Down Expand Up @@ -377,10 +377,10 @@ export default ({ getService }: FtrProviderContext): void => {
const latestPush = pushes[pushes.length - 1];

expect(Object.keys(connectors).length).to.be(1);
expect(connectors[connector.id].push.latestUserActionPushDate).to.eql(
expect(connectors[connector.id].push.details?.latestUserActionPushDate).to.eql(
latestPush.created_at
);
expect(connectors[connector.id].push.oldestUserActionPushDate).to.eql(
expect(connectors[connector.id].push.details?.oldestUserActionPushDate).to.eql(
oldestPush.created_at
);
});
Expand Down

0 comments on commit 6ecac19

Please sign in to comment.