Skip to content

Commit

Permalink
feat: default user tasks with zeebe:UserTask extension element
Browse files Browse the repository at this point in the history
  • Loading branch information
Skaiir authored and barmac committed Dec 2, 2024
1 parent 9ededd5 commit 6dbef38
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 0 deletions.
66 changes: 66 additions & 0 deletions lib/camunda-cloud/CreateZeebeUserTaskBehavior.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { createElement } from '../util/ElementUtil';
import { getZeebeUserTaskElement } from './util/ZeebeUserTaskUtil';
import { getBusinessObject, is } from 'bpmn-js/lib/util/ModelUtil';
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';

const HIGH_PRIORITY = 5000;

/**
* Zeebe BPMN specific behavior for creating user tasks.
*/
export default class CreateZeebeUserTaskBehavior extends CommandInterceptor {
constructor(bpmnFactory, eventBus, modeling) {
super(eventBus);

/**
* Add zeebe:userTask extension element when creating bpmn:UserTask.
*/
this.postExecuted(
'shape.create',
HIGH_PRIORITY,
function(context) {
const { shape } = context;

if (!is(shape, 'bpmn:UserTask')) {
return;
}

const businessObject = getBusinessObject(shape);

// Use getZeebeUserTaskElement to check if zeebe:userTask already exists
let userTaskElement = getZeebeUserTaskElement(businessObject);

if (!userTaskElement) {
let extensionElements = businessObject.get('extensionElements');

if (!extensionElements) {
extensionElements = createElement(
'bpmn:ExtensionElements',
{
values: [],
},
businessObject,
bpmnFactory
);

modeling.updateProperties(shape, { extensionElements });
}

userTaskElement = createElement(
'zeebe:UserTask',
{},
extensionElements,
bpmnFactory
);

modeling.updateModdleProperties(shape, extensionElements, {
values: [ ...(extensionElements.values || []), userTaskElement ],
});
}
},
true
);
}
}

CreateZeebeUserTaskBehavior.$inject = [ 'bpmnFactory', 'eventBus', 'modeling' ];
3 changes: 3 additions & 0 deletions lib/camunda-cloud/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import CleanUpSubscriptionBehavior from './CleanUpSubscriptionBehavior';
import CleanUpTimerExpressionBehavior from './CleanUpTimerExpressionBehavior';
import CopyPasteBehavior from './CopyPasteBehavior';
import CreateZeebeCallActivityBehavior from './CreateZeebeCallActivityBehavior';
import CreateZeebeUserTaskBehavior from './CreateZeebeUserTaskBehavior';
import DeleteParticipantBehaviour from '../shared/DeleteParticipantBehaviour';
import FormsBehavior from './FormsBehavior';
import RemoveAssignmentDefinitionBehavior from './RemoveAssignmentDefinitionBehavior';
Expand All @@ -22,6 +23,7 @@ export default {
'cleanUpTimerExpressionBehavior',
'copyPasteBehavior',
'createZeebeCallActivityBehavior',
'createZeebeUserTaskBehavior',
'deleteParticipantBehaviour',
'formsBehavior',
'removeAssignmentDefinitionBehavior',
Expand All @@ -36,6 +38,7 @@ export default {
cleanUpTimerExpressionBehavior: [ 'type', CleanUpTimerExpressionBehavior ],
copyPasteBehavior: [ 'type', CopyPasteBehavior ],
createZeebeCallActivityBehavior: [ 'type', CreateZeebeCallActivityBehavior ],
createZeebeUserTaskBehavior: [ 'type', CreateZeebeUserTaskBehavior ],
deleteParticipantBehaviour: [ 'type', DeleteParticipantBehaviour ],
formsBehavior: [ 'type', FormsBehavior ],
removeAssignmentDefinitionBehavior: [ 'type', RemoveAssignmentDefinitionBehavior ],
Expand Down
42 changes: 42 additions & 0 deletions lib/camunda-cloud/util/ZeebeUserTaskUtil.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { getExtensionElementsList } from '../../util/ExtensionElementsUtil';

import { getBusinessObject, is } from 'bpmn-js/lib/util/ModelUtil';

/**
* Get all zeebe:userTask elements of an element.
*
* @param {djs.model.Base|ModdleElement} element
*
* @returns {Array<ModdleElement>}
*/
export function getZeebeUserTaskElements(element) {
const businessObject = getBusinessObject(element);
return getExtensionElementsList(businessObject, 'zeebe:UserTask');
}

/**
* Get the first zeebe:userTask element of an element.
*
* @param {djs.model.Base|ModdleElement} element
*
* @returns {ModdleElement|null}
*/
export function getZeebeUserTaskElement(element) {
const userTaskElements = getZeebeUserTaskElements(element);
return userTaskElements[0] || null;
}

/**
* Check whether a zeebe:userTask extension element is set on an element.
*
* @param {djs.model.Base|ModdleElement} element
*
* @returns {boolean}
*/
export function hasZeebeUserTaskExtension(element) {
if (!is(element, 'bpmn:UserTask')) {
return false;
}

return !!getZeebeUserTaskElement(element);
}
107 changes: 107 additions & 0 deletions test/camunda-cloud/CreateZeebeUserTaskBehaviorSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { bootstrapCamundaCloudModeler, inject } from 'test/TestHelper';

import { find } from 'min-dash';

import {
getZeebeUserTaskElement,
getZeebeUserTaskElements,
} from '../../lib/camunda-cloud/util/ZeebeUserTaskUtil';

import { getBusinessObject, is } from 'bpmn-js/lib/util/ModelUtil';

import emptyProcessDiagramXML from './process-empty.bpmn';
import userTasksXML from './process-user-tasks.bpmn';

describe('camunda-cloud/features/modeling - CreateZeebeUserTaskBehavior', function() {
describe('populate zeebe:userTask', function() {
describe('when creating new shapes', function() {
beforeEach(bootstrapCamundaCloudModeler(emptyProcessDiagramXML));

it('should execute when creating bpmn:UserTask', inject(function(
canvas,
modeling
) {

// given
const rootElement = canvas.getRootElement();

// when
const newShape = modeling.createShape(
{ type: 'bpmn:UserTask' },
{ x: 100, y: 100 },
rootElement
);

// then
const businessObject = getBusinessObject(newShape),
extensionElements = businessObject.get('extensionElements'),
zeebeUserTaskExtension = getZeebeUserTaskElement(newShape);

expect(zeebeUserTaskExtension).to.exist;
expect(extensionElements).to.exist;
expect(zeebeUserTaskExtension.$parent).to.equal(extensionElements);
}));

it('should not execute when creating bpmn:Task', inject(function(
canvas,
modeling
) {

// given
const rootElement = canvas.getRootElement();

// when
const newShape = modeling.createShape(
{ type: 'bpmn:Task' },
{ x: 100, y: 100 },
rootElement
);

// then
const zeebeUserTaskExtension = getZeebeUserTaskElement(newShape);

expect(zeebeUserTaskExtension).not.to.exist;
}));
});

describe('when copying bpmn:UserTask', function() {
beforeEach(bootstrapCamundaCloudModeler(userTasksXML));

it('should re-use existing extensionElement', inject(function(
canvas,
copyPaste,
elementRegistry
) {

// given
const rootElement = canvas.getRootElement();
const userTask = elementRegistry.get('withZeebeUserTask');

// when
copyPaste.copy(userTask);

const elements = copyPaste.paste({
element: rootElement,
point: {
x: 1000,
y: 1000,
},
});

// then
const pastedUserTask = find(elements, (element) =>
is(element, 'bpmn:UserTask')
);

const businessObject = getBusinessObject(pastedUserTask),
extensionElements = businessObject.get('extensionElements'),
zeebeUserTaskExtensions = getZeebeUserTaskElements(pastedUserTask);

expect(zeebeUserTaskExtensions).to.exist;
expect(extensionElements).to.exist;
expect(zeebeUserTaskExtensions.length).to.equal(1);
expect(zeebeUserTaskExtensions[0].$parent).to.equal(extensionElements);
}));
});
});
});
9 changes: 9 additions & 0 deletions test/camunda-cloud/process-user-tasks.bpmn
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@
<zeebe:formDefinition externalReference="" />
</bpmn:extensionElements>
</bpmn:userTask>
<bpmn:userTask id="withZeebeUserTask" name="With zeebe user task">
<bpmn:extensionElements>
<zeebe:userTask />
</bpmn:extensionElements>
</bpmn:userTask>
<bpmn:userTask id="UserTask_13" name="UserTask_13">
<bpmn:extensionElements>
<zeebe:formDefinition formKey="" />
Expand Down Expand Up @@ -156,6 +161,10 @@
<dc:Bounds x="250" y="780" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_0xs9191" bpmnElement="withZeebeUserTask">
<dc:Bounds x="250" y="870" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_1ts16ji" bpmnElement="withEmptyExternalReference">
<dc:Bounds x="390" y="690" width="100" height="80" />
<bpmndi:BPMNLabel />
Expand Down

0 comments on commit 6dbef38

Please sign in to comment.