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 committed Nov 5, 2024
1 parent ba9f4a5 commit 88e68ff
Show file tree
Hide file tree
Showing 5 changed files with 224 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";

Check failure on line 1 in lib/camunda-cloud/CreateZeebeUserTaskBehavior.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, 20)

Strings must use singlequote
import { getZeebeUserTaskElement } from "./util/ZeebeUserTaskUtil";

Check failure on line 2 in lib/camunda-cloud/CreateZeebeUserTaskBehavior.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, 20)

Strings must use singlequote
import { getBusinessObject, is } from "bpmn-js/lib/util/ModelUtil";

Check failure on line 3 in lib/camunda-cloud/CreateZeebeUserTaskBehavior.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, 20)

Strings must use singlequote
import CommandInterceptor from "diagram-js/lib/command/CommandInterceptor";

Check failure on line 4 in lib/camunda-cloud/CreateZeebeUserTaskBehavior.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, 20)

Strings must use singlequote

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",

Check failure on line 19 in lib/camunda-cloud/CreateZeebeUserTaskBehavior.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, 20)

Strings must use singlequote
HIGH_PRIORITY,
function (context) {

Check failure on line 21 in lib/camunda-cloud/CreateZeebeUserTaskBehavior.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, 20)

Unexpected space before function parentheses
const { shape } = context;

if (!is(shape, "bpmn:UserTask")) {

Check failure on line 24 in lib/camunda-cloud/CreateZeebeUserTaskBehavior.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, 20)

Strings must use singlequote
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");

Check failure on line 34 in lib/camunda-cloud/CreateZeebeUserTaskBehavior.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, 20)

Strings must use singlequote

if (!extensionElements) {
extensionElements = createElement(
"bpmn:ExtensionElements",

Check failure on line 38 in lib/camunda-cloud/CreateZeebeUserTaskBehavior.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, 20)

Strings must use singlequote
{
values: [],
},
businessObject,
bpmnFactory
);

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

userTaskElement = createElement(
"zeebe:UserTask",

Check failure on line 50 in lib/camunda-cloud/CreateZeebeUserTaskBehavior.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, 20)

Strings must use singlequote
{},
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 @@ -5,6 +5,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 @@ -20,6 +21,7 @@ export default {
'cleanUpTimerExpressionBehavior',
'copyPasteBehavior',
'createZeebeCallActivityBehavior',
'createZeebeUserTaskBehavior',
'deleteParticipantBehaviour',
'formsBehavior',
'removeAssignmentDefinitionBehavior',
Expand All @@ -33,6 +35,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);
}
104 changes: 104 additions & 0 deletions test/camunda-cloud/CreateZeebeUserTaskBehaviorSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
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.only("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 @@ -83,6 +83,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 @@ -155,6 +160,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 88e68ff

Please sign in to comment.