Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
barmac committed Dec 7, 2023
1 parent fd7e1ac commit aca3dad
Show file tree
Hide file tree
Showing 14 changed files with 377 additions and 94 deletions.
41 changes: 28 additions & 13 deletions src/cloud-element-templates/CalledElementBehavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,30 @@ import { findExtension } from './Helper';
* Enforces no variable propagation for templated call activities.
*/
export class CalledElementBehavior extends CommandInterceptor {
constructor(eventBus, modeling) {
super(eventBus, modeling);

/**
* @param {*} eventBus
* @param {*} modeling
* @param {import('./ElementTemplates').default} elementTemplates
*/
constructor(eventBus, modeling, elementTemplates) {
super(eventBus);

this._modeling = modeling;
this._elementTemplates = elementTemplates;

this.postExecuted(
'propertiesPanel.zeebe.changeTemplate', this._handleTemplateChange, true, this);
this.postExecuted([
'element.updateProperties', 'element.updateModdleProperties'
], this._ensureNoPropagation, true, this);
}

_handleTemplateChange(context) {
if (!context.newTemplate) {
_ensureNoPropagation(context) {
const { element } = context;

if (!this._elementTemplates.get(element)) {
return;
}

const { element } = context;

if (!is(element, 'bpmn:CallActivity')) {
return;
}
Expand All @@ -33,14 +41,21 @@ export class CalledElementBehavior extends CommandInterceptor {
return;
}

this._modeling.updateModdleProperties(element, calledElement, {
propagateAllChildVariables: false,
propagateAllParentVariables: false
});
for (const property of [
'propagateAllChildVariables',
'propagateAllParentVariables'
]) {
if (calledElement.get(property) !== false) {
this._modeling.updateModdleProperties(element, calledElement, {
[property]: false
});
}
}
}
}

CalledElementBehavior.$inject = [
'eventBus',
'modeling'
'modeling',
'elementTemplates'
];
42 changes: 41 additions & 1 deletion src/cloud-element-templates/util/propertyUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import {
ZEBBE_INPUT_TYPE,
ZEEBE_OUTPUT_TYPE,
ZEEBE_PROPERTY_TYPE,
ZEEBE_TASK_HEADER_TYPE
ZEEBE_TASK_HEADER_TYPE,
ZEEBE_CALLED_ELEMENT
} from './bindingTypes';

import {
Expand Down Expand Up @@ -194,6 +195,13 @@ export function getPropertyValue(element, property, scope) {
return defaultValue;
}

// zeebe:calledElement
if (type === ZEEBE_CALLED_ELEMENT) {
const calledElement = findExtension(businessObject, 'zeebe:CalledElement');

return calledElement ? calledElement.get(bindingProperty) : defaultValue;
}

// should never throw as templates are validated beforehand
throw unknownBindingError(element, property);
}
Expand Down Expand Up @@ -528,6 +536,38 @@ export function setPropertyValue(bpmnFactory, commandStack, element, property, v
}
}

// zeebe:calledElement
if (type === ZEEBE_CALLED_ELEMENT) {
let calledElement = findExtension(element, 'zeebe:CalledElement');
const propertyName = binding.property;

const properties = {
[ propertyName ]: value || ''
};

if (calledElement) {
commands.push({
cmd: 'element.updateModdleProperties',
context: {
element,
properties,
moddleElement: calledElement
}
});
} else {
calledElement = createElement('zeebe:CalledElement', properties, extensionElements, bpmnFactory);

commands.push({
cmd: 'element.updateModdleProperties',
context: {
...context,
moddleElement: extensionElements,
properties: { values: [ ...extensionElements.get('values'), calledElement ] }
}
});
}
}

if (commands.length) {
const commandsToExecute = commands.filter((command) => command !== NO_OP);

Expand Down
37 changes: 37 additions & 0 deletions test/spec/cloud-element-templates/CalledElementBehavior.bpmn
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_16zi3v6" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.16.0" modeler:executionPlatform="Camunda Cloud" modeler:executionPlatformVersion="8.3.0">
<bpmn:process id="Process_0kgt465" isExecutable="true">
<bpmn:callActivity id="Templated" name="foo" zeebe:modelerTemplate="io.camunda.examples.Payment">
<bpmn:extensionElements>
<zeebe:calledElement processId="one" propagateAllChildVariables="false" propagateAllParentVariables="false" />
</bpmn:extensionElements>
</bpmn:callActivity>
<bpmn:callActivity id="TemplatedNoProperty" name="TemplatedNoProperty" zeebe:modelerTemplate="io.camunda.examples.Payment" />
<bpmn:callActivity id="NonTemplated" name="NonTemplated">
<bpmn:extensionElements>
<zeebe:calledElement propagateAllChildVariables="false" />
</bpmn:extensionElements>
</bpmn:callActivity>
<bpmn:task id="Task" name="foo" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_0kgt465">
<bpmndi:BPMNShape id="Activity_01llrle_di" bpmnElement="Templated">
<dc:Bounds x="160" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="CA_di" bpmnElement="TemplatedNoProperty">
<dc:Bounds x="160" y="200" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_002cijc_di" bpmnElement="NonTemplated">
<dc:Bounds x="310" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_di" bpmnElement="Task">
<dc:Bounds x="310" y="200" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
50 changes: 50 additions & 0 deletions test/spec/cloud-element-templates/CalledElementBehavior.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[
{
"$schema": "https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json",
"id": "io.camunda.examples.Payment",
"name": "Payment",
"description": "Payment process call activity",
"appliesTo": [
"bpmn:Task",
"bpmn:CallActivity"
],
"elementType": {
"value": "bpmn:CallActivity"
},
"properties": [
{
"id": "nameProp",
"label": "name",
"type": "String",
"binding": {
"type": "property",
"name": "name"
}
},
{
"type": "Hidden",
"value": "one",
"binding": {
"type": "zeebe:calledElement",
"property": "processId"
},
"condition": {
"equals": "foo",
"property": "nameProp"
}
},
{
"type": "Hidden",
"value": "two",
"binding": {
"type": "zeebe:calledElement",
"property": "processId"
},
"condition": {
"equals": "bar",
"property": "nameProp"
}
}
]
}
]
152 changes: 152 additions & 0 deletions test/spec/cloud-element-templates/CalledElementBehavior.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import TestContainer from 'mocha-test-container-support';
import coreModule from 'bpmn-js/lib/core';
import modelingModule from 'bpmn-js/lib/features/modeling';
import { BpmnPropertiesPanelModule } from 'bpmn-js-properties-panel';
import zeebeModdlePackage from 'zeebe-bpmn-moddle/resources/zeebe';
import ZeebeBehaviorsModule from 'camunda-bpmn-js-behaviors/lib/camunda-cloud';

import {
bootstrapModeler,
inject
} from 'test/TestHelper';

import elementTemplatesModule from 'src/cloud-element-templates';
import { findExtension } from 'src/cloud-element-templates/Helper';

import diagramXML from './CalledElementBehavior.bpmn';
import templates from './CalledElementBehavior.json';


describe('CalledElementBehavior', function() {

let container;

beforeEach(function() {
container = TestContainer.get(this);
});


beforeEach(bootstrapModeler(diagramXML, {
container,
modules: [
coreModule,
elementTemplatesModule,
modelingModule,
BpmnPropertiesPanelModule,
{
propertiesPanel: [ 'value', { registerProvider() {} } ]
},
ZeebeBehaviorsModule
],
moddleExtensions: {
zeebe: zeebeModdlePackage
},
elementTemplates: templates
}));


describe('variable propagation', function() {

it('should ensure no variable propagation when template is applied', inject(
function(elementRegistry, elementTemplates) {

// given
let callActivity = elementRegistry.get('Task');

// when
callActivity = elementTemplates.applyTemplate(callActivity, templates[0]);

// then
expect(getPropagation(callActivity)).to.eql({
propagateAllChildVariables: false,
propagateAllParentVariables: false
});
})
);


it('should ensure no variable propagation when property is activated via condition', inject(
function(elementRegistry, modeling) {

// given
const callActivity = elementRegistry.get('TemplatedNoProperty');

// when
modeling.updateProperties(callActivity, {
name: 'foo'
});

expect(getPropagation(callActivity)).to.eql({
propagateAllChildVariables: false,
propagateAllParentVariables: false
});
})
);


it('should NOT create called element if property is deactivated', inject(
function(elementRegistry, modeling) {

// given
const callActivity = elementRegistry.get('Templated');

// when
modeling.updateProperties(callActivity, {
name: 'baz'
});

expect(getPropagation(callActivity)).to.be.null;
})
);


it('should NOT affect non-templated call activities', inject(
function(elementRegistry, modeling) {

// given
const callActivity = elementRegistry.get('NonTemplated');
const initialPropagation = getPropagation(callActivity);

// when
modeling.updateProperties(callActivity, {
name: 'foo'
});

// then
expect(getPropagation(callActivity)).to.eql(initialPropagation);
})
);


it('should NOT affect non-call-activity', inject(
function(elementRegistry, modeling) {

// given
const task = elementRegistry.get('Task');

// when
modeling.updateProperties(task, {
name: 'newName'
});

// then
expect(getPropagation(task)).to.be.null;
})
);
});
});


// helpers //////////

function getCalledElement(element) {
return findExtension(element, 'zeebe:CalledElement');
}

function getPropagation(callActivity) {
const calledElement = getCalledElement(callActivity);
return calledElement ? {
propagateAllChildVariables: calledElement.get('propagateAllChildVariables'),
propagateAllParentVariables: calledElement.get('propagateAllParentVariables')
} : null;
}
Loading

0 comments on commit aca3dad

Please sign in to comment.