Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(ProcessEditor): Decouple integration with BFF when adding tasks in the process editor. #12894

Merged
merged 22 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ export const ProcessEditor = (): React.ReactElement => {
org,
app,
currentPolicy,
addLayoutSet,
mutateApplicationPolicy,
addDataTypeToAppMetadata,
);
onProcessTaskAddHandler.handleOnProcessTaskAdd(taskMetadata);
};
Expand All @@ -132,7 +134,10 @@ export const ProcessEditor = (): React.ReactElement => {
org,
app,
currentPolicy,
layoutSets,
mutateApplicationPolicy,
deleteDataTypeFromAppMetadata,
deleteLayoutSet,
);
onProcessTaskRemoveHandler.handleOnProcessTaskRemove(taskMetadata);
};
Expand All @@ -155,8 +160,6 @@ export const ProcessEditor = (): React.ReactElement => {
appLibVersion={appLibData.backendVersion}
bpmnXml={hasBpmnQueryError ? null : bpmnXml}
mutateDataType={mutateDataType}
addDataTypeToAppMetadata={addDataTypeToAppMetadata}
deleteDataTypeFromAppMetadata={deleteDataTypeFromAppMetadata}
saveBpmn={saveBpmnXml}
openPolicyEditor={() => {
setSettingsModalSelectedTab('policy');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,80 @@
import type { Policy } from 'app-shared/types/Policy';
import type { OnProcessTaskEvent } from '@altinn/process-editor/types/OnProcessTask';
import type { TaskEvent } from '@altinn/process-editor/utils/ProcessTaskManager';
import { OnProcessTaskAddHandler } from './OnProcessTaskAddHandler';
import { BpmnTypeEnum } from '@altinn/process-editor/enum/BpmnTypeEnum';
import type { TaskEvent } from '@altinn/process-editor/types/TaskEvent';
import type { BpmnTaskType } from '@altinn/process-editor/types/BpmnTaskType';
import { app as appMock, org } from '@studio/testing/testids';
Fixed Show fixed Hide fixed

const currentPolicyMock: Policy = {
requiredAuthenticationLevelOrg: '3',
requiredAuthenticationLevelEndUser: '3',
rules: [],
};
const addLayoutSetMock = jest.fn();
const mutateApplicationPolicyMock = jest.fn();
const addDataTypeToAppMetadataMock = jest.fn();

const createOnProcessTaskHandler = () =>
new OnProcessTaskAddHandler(
orgMock,
appMock,
currentPolicyMock,
addLayoutSetMock,
mutateApplicationPolicyMock,
addDataTypeToAppMetadataMock,
);

const createTaskEvent = (extensionConfig?: object): TaskEvent =>
({
element: {
id: 'testId',
businessObject: {
id: 'testEventId',
$type: BpmnTypeEnum.Task,
extensionElements: extensionConfig ? { values: [extensionConfig] } : undefined,
},
},
}) as TaskEvent;

describe('OnProcessTaskAddHandler', () => {
it('should add default payment policy to current policy when task type is payment', () => {
const org = 'testOrg';
const app = 'testApp';
const currentPolicy: Policy = {
requiredAuthenticationLevelOrg: '3',
requiredAuthenticationLevelEndUser: '3',
rules: [],
};
beforeEach(() => {
jest.clearAllMocks();
});

const mutateApplicationPolicy = jest.fn();
it('should add layoutSet when data-task is added', () => {
const onProcessTaskAddHandler = createOnProcessTaskHandler();

onProcessTaskAddHandler.handleOnProcessTaskAdd({
taskEvent: createTaskEvent(),
taskType: 'data',
});

expect(addLayoutSetMock).toHaveBeenCalledWith({
This conversation was marked as resolved.
Show resolved Hide resolved
layoutSetConfig: { id: 'testId', tasks: ['testId'] },
layoutSetIdToUpdate: 'testId',
});
expect(addDataTypeToAppMetadataMock).not.toHaveBeenCalled();
expect(mutateApplicationPolicyMock).not.toHaveBeenCalled();
});

it('should add layoutSet, dataType and default policy when payment task is added', () => {
const taskMetadata: OnProcessTaskEvent = {
taskType: 'payment',
taskEvent: {
element: {
id: 'testElementId',
businessObject: {},
businessObject: {
id: 'testEventId',
$type: BpmnTypeEnum.Task,
extensionElements: {
values: [
{
paymentConfig: { paymentDataType: 'paymentInformation' },
},
],
},
},
},
} as TaskEvent,
};
Expand All @@ -41,14 +96,69 @@
],
};

const onProcessTaskAddHandler = new OnProcessTaskAddHandler(
org,
app,
currentPolicy,
mutateApplicationPolicy,
);
const onProcessTaskAddHandler = createOnProcessTaskHandler();
onProcessTaskAddHandler.handleOnProcessTaskAdd(taskMetadata);

expect(addLayoutSetMock).toHaveBeenCalledWith({
layoutSetConfig: {
id: 'testElementId',
tasks: ['testElementId'],
},
layoutSetIdToUpdate: 'testElementId',
});
expect(addDataTypeToAppMetadataMock).toHaveBeenCalledWith({
dataTypeId: 'paymentInformation',
taskId: 'testElementId',
});
expect(mutateApplicationPolicyMock).toHaveBeenCalledWith(expectedResponse);
});

it('should add datatype when signing task is added', () => {
const onProcessTaskAddHandler = createOnProcessTaskHandler();

const taskMetadata: OnProcessTaskEvent = {
taskType: 'signing',
taskEvent: {
element: {
id: 'testElementId',
businessObject: {
id: 'testEventId',
$type: BpmnTypeEnum.Task,
extensionElements: {
values: [
{
signatureConfig: { signatureDataType: 'signingInformation' },
},
],
},
},
},
} as TaskEvent,
};

onProcessTaskAddHandler.handleOnProcessTaskAdd(taskMetadata);
expect(mutateApplicationPolicy).toHaveBeenCalledWith(expectedResponse);

expect(addDataTypeToAppMetadataMock).toHaveBeenCalledWith({
dataTypeId: 'signingInformation',
taskId: 'testElementId',
});
expect(addLayoutSetMock).not.toHaveBeenCalled();
expect(mutateApplicationPolicyMock).not.toHaveBeenCalled();
});

it.each(['confirmation', 'feedback'])(
'should not add layoutSet, dataType or default policy when task type is %s',
(task) => {
const onProcessTaskAddHandler = createOnProcessTaskHandler();

onProcessTaskAddHandler.handleOnProcessTaskAdd({
taskEvent: createTaskEvent(),
taskType: task as BpmnTaskType,
});

expect(addLayoutSetMock).not.toHaveBeenCalled();
expect(addDataTypeToAppMetadataMock).not.toHaveBeenCalled();
expect(mutateApplicationPolicyMock).not.toHaveBeenCalled();
},
);
});
Original file line number Diff line number Diff line change
@@ -1,26 +1,73 @@
import type { OnProcessTaskEvent } from '@altinn/process-editor/types/OnProcessTask';
import { PaymentPolicyBuilder } from '../../../utils/policy';
import type { OnProcessTaskEvent } from '@altinn/process-editor/types/OnProcessTask';
import type { Policy } from 'app-shared/types/Policy';
import { getDataTypeIdFromBusinessObject } from '@altinn/process-editor/utils/hookUtils/hookUtils';
import type {
AddLayoutSetMutation,
AddLayoutSetMutationPayload,
} from '../../../hooks/mutations/useAddLayoutSetMutation';

export class OnProcessTaskAddHandler {
constructor(
private readonly org: string,
private readonly app: string,
private readonly currentPolicy: Policy,
private readonly addLayoutSet: AddLayoutSetMutation,
private readonly mutateApplicationPolicy: (policy: Policy) => void,
private readonly addDataTypeToAppMetadata: (data: {
dataTypeId: string;
taskId: string;
}) => void,
) {}

/**
* This handler is responsible to react on task add event, to mutate files that are related to the task, but not a part of process-editor domain.
* @param taskMetadata
*/
public handleOnProcessTaskAdd(taskMetadata: OnProcessTaskEvent): void {
if (taskMetadata.taskType === 'data') {
this.handleDataTaskAdd(taskMetadata);
}

if (taskMetadata.taskType === 'payment') {
this.handlePaymentTaskAdd(taskMetadata);
}

if (taskMetadata.taskType === 'signing') {
this.handleSigningTaskAdd(taskMetadata);
}
}

/**
* Adds a layout set to the added data task
* @param taskMetadata
* @private
*/
private handleDataTaskAdd(taskMetadata: OnProcessTaskEvent): void {
this.addLayoutSet(this.createLayoutSetConfig(taskMetadata.taskEvent));
}

/**
* Adds a dataType, layoutSet and default policy to the added payment task
* @param taskMetadata
* @private
*/
private handlePaymentTaskAdd(taskMetadata: OnProcessTaskEvent): void {
// Add layoutSet for the task
this.addLayoutSet(this.createLayoutSetConfig(taskMetadata.taskEvent));
This conversation was marked as resolved.
Show resolved Hide resolved

// Add dataType
const dataTypeId = getDataTypeIdFromBusinessObject(
taskMetadata.taskType,
taskMetadata.taskEvent.element.businessObject,
);

this.addDataTypeToAppMetadata({
dataTypeId,
taskId: taskMetadata.taskEvent.element.id,
});

// Add default policy
const paymentPolicyBuilder = new PaymentPolicyBuilder(this.org, this.app);
const defaultPaymentPolicy = paymentPolicyBuilder.getDefaultPaymentPolicy(
taskMetadata.taskEvent.element.id,
Expand All @@ -32,4 +79,37 @@ export class OnProcessTaskAddHandler {
rules: [...this.currentPolicy.rules, ...defaultPaymentPolicy.rules],
});
}

/**
* Adds a dataType to the added signing task
* @param taskMetadata
* @private
*/
private handleSigningTaskAdd(taskMetadata: OnProcessTaskEvent): void {
// Add DataType
const dataTypeId = getDataTypeIdFromBusinessObject(
This conversation was marked as resolved.
Show resolved Hide resolved
taskMetadata.taskType,
taskMetadata.taskEvent.element.businessObject,
);

this.addDataTypeToAppMetadata({
dataTypeId,
taskId: taskMetadata.taskEvent.element.id,
});
}

/**
* Creates the layout set config for the task
* @returns {{layoutSetIdToUpdate: string, layoutSetConfig: LayoutSetConfig}}
* @private
*/
private createLayoutSetConfig(
taskEvent: OnProcessTaskEvent['taskEvent'],
): AddLayoutSetMutationPayload {
const elementId = taskEvent.element.id;
return {
layoutSetIdToUpdate: elementId,
layoutSetConfig: { id: elementId, tasks: [elementId] },
};
}
}
Loading
Loading