Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
barmac committed Dec 6, 2023
1 parent 2c560e4 commit dbb002e
Show file tree
Hide file tree
Showing 16 changed files with 663 additions and 5 deletions.
12 changes: 12 additions & 0 deletions src/cloud-element-templates/CreateHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,18 @@ export function createZeebeProperty(binding, value = '', bpmnFactory) {
});
}

/**
* Create a called element representing the given value.
*
* @param {object} attrs
* @param {BpmnFactory} bpmnFactory
*
* @return {ModdleElement}
*/
export function createCalledElement(attrs = {}, bpmnFactory) {
return bpmnFactory.create('zeebe:CalledElement', attrs);
}

/**
* Retrieves whether an element should be updated for a given property.
*
Expand Down
107 changes: 106 additions & 1 deletion src/cloud-element-templates/cmd/ChangeElementTemplateHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from '../Helper';

import {
createCalledElement,
createInputParameter,
createOutputParameter,
createTaskDefinition,
Expand All @@ -29,7 +30,8 @@ import {
MESSAGE_BINDING_TYPES,
MESSAGE_PROPERTY_TYPE,
MESSAGE_ZEEBE_SUBSCRIPTION_PROPERTY_TYPE,
TASK_DEFINITION_TYPES
TASK_DEFINITION_TYPES,
ZEEBE_CALLED_ELEMENT
} from '../util/bindingTypes';

import {
Expand Down Expand Up @@ -125,6 +127,8 @@ export default class ChangeElementTemplateHandler {
this._updateZeebePropertyProperties(element, oldTemplate, newTemplate);

this._updateMessage(element, oldTemplate, newTemplate);

this._updateCalledElement(element, oldTemplate, newTemplate);
}
}

Expand Down Expand Up @@ -902,6 +906,107 @@ export default class ChangeElementTemplateHandler {
}



/**
* Update `zeebe:CalledElement` properties of specified business object. This
* can only exist in `bpmn:ExtensionElements`.
*
* @param {djs.model.Base} element
* @param {Object} oldTemplate
* @param {Object} newTemplate
*/
_updateCalledElement(element, oldTemplate, newTemplate) {
const bpmnFactory = this._bpmnFactory,
commandStack = this._commandStackWrapper;

const newProperties = newTemplate.properties.filter((newProperty) => {
const newBinding = newProperty.binding,
newBindingType = newBinding.type;

return newBindingType === ZEEBE_CALLED_ELEMENT;
});

const businessObject = this._getOrCreateExtensionElements(element);
let calledElement = findExtension(businessObject, 'zeebe:CalledElement');

// (1) remove old called element if no new properties specified
if (!newProperties.length) {
commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: businessObject,
properties: {
values: without(businessObject.get('values'), calledElement)
}
});

return;
}


newProperties.forEach((newProperty) => {
const oldProperty = findOldProperty(oldTemplate, newProperty),
newPropertyValue = getDefaultValue(newProperty),
propertyName = newProperty.binding.property;

// (2) update old called element
if (calledElement) {

if (!shouldKeepValue(calledElement, oldProperty, newProperty)) {
const properties = {
[propertyName]: newPropertyValue
};

commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: calledElement,
properties
});
}
}

// (3) add new called element
else {
const properties = {
[propertyName]: newPropertyValue
};

calledElement = createCalledElement(properties, bpmnFactory);

calledElement.$parent = businessObject;

commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: businessObject,
properties: {
values: [ ...businessObject.get('values'), calledElement ]
}
});
}
});

// (4) remove properties no longer templated
const oldProperties = oldTemplate && oldTemplate.properties.filter((oldProperty) => {
const oldBinding = oldProperty.binding,
oldBindingType = oldBinding.type;

return oldBindingType === ZEEBE_CALLED_ELEMENT && !newProperties.find(
(newProperty) => newProperty.binding.property === oldProperty.binding.property
);
}) || [];

oldProperties.forEach((oldProperty) => {
const properties = {
[oldProperty.binding.property]: undefined
};

commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: calledElement,
properties
});
});
}

/**
* Replaces the element with the specified elementType.
* Takes into account the eventDefinition for events.
Expand Down
33 changes: 33 additions & 0 deletions src/cloud-element-templates/create/CalledElementBindingProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
ensureExtension
} from '../CreateHelper';
import { getDefaultValue } from '../Helper';

import { ensureNoPropagation } from '../util/calledElement';


export class CalledElementBindingProvider {
static create(element, options) {
const {
property,
bpmnFactory
} = options;

const {
binding
} = property;

const {
property: propertyName
} = binding;

const value = getDefaultValue(property);

const calledElement = ensureExtension(element, 'zeebe:CalledElement', bpmnFactory);

// TODO(@barmac): remove if we decide to support propagation in templates
ensureNoPropagation(calledElement);

calledElement.set(propertyName, value);
}
}
7 changes: 5 additions & 2 deletions src/cloud-element-templates/create/TemplateElementFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import TaskHeaderBindingProvider from './TaskHeaderBindingProvider';
import ZeebePropertiesProvider from './ZeebePropertiesProvider';
import { MessagePropertyBindingProvider } from './MessagePropertyBindingProvider';
import { MessageZeebeSubscriptionBindingProvider } from './MessageZeebeSubscriptionBindingProvider';
import { CalledElementBindingProvider } from './CalledElementBindingProvider';

import {
MESSAGE_PROPERTY_TYPE,
Expand All @@ -22,7 +23,8 @@ import {
ZEBBE_INPUT_TYPE,
ZEEBE_OUTPUT_TYPE,
ZEEBE_TASK_HEADER_TYPE,
ZEBBE_PROPERTY_TYPE
ZEBBE_PROPERTY_TYPE,
ZEEBE_CALLED_ELEMENT
} from '../util/bindingTypes';

import {
Expand All @@ -44,7 +46,8 @@ export default class TemplateElementFactory {
[ZEEBE_OUTPUT_TYPE]: OutputBindingProvider,
[ZEEBE_TASK_HEADER_TYPE]: TaskHeaderBindingProvider,
[MESSAGE_PROPERTY_TYPE]: MessagePropertyBindingProvider,
[MESSAGE_ZEEBE_SUBSCRIPTION_PROPERTY_TYPE]: MessageZeebeSubscriptionBindingProvider
[MESSAGE_ZEEBE_SUBSCRIPTION_PROPERTY_TYPE]: MessageZeebeSubscriptionBindingProvider,
[ZEEBE_CALLED_ELEMENT]: CalledElementBindingProvider
};
}

Expand Down
4 changes: 3 additions & 1 deletion src/cloud-element-templates/util/bindingTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const ZEEBE_TASK_DEFINITION = 'zeebe:taskDefinition';
export const ZEEBE_TASK_HEADER_TYPE = 'zeebe:taskHeader';
export const MESSAGE_PROPERTY_TYPE = 'bpmn:Message#property';
export const MESSAGE_ZEEBE_SUBSCRIPTION_PROPERTY_TYPE = 'bpmn:Message#zeebe:subscription#property';
export const ZEEBE_CALLED_ELEMENT = 'zeebe:calledElement';

export const EXTENSION_BINDING_TYPES = [
MESSAGE_ZEEBE_SUBSCRIPTION_PROPERTY_TYPE,
Expand All @@ -17,7 +18,8 @@ export const EXTENSION_BINDING_TYPES = [
ZEEBE_PROPERTY_TYPE,
ZEEBE_TASK_DEFINITION_TYPE_TYPE,
ZEEBE_TASK_DEFINITION,
ZEEBE_TASK_HEADER_TYPE
ZEEBE_TASK_HEADER_TYPE,
ZEEBE_CALLED_ELEMENT
];

export const TASK_DEFINITION_TYPES = [
Expand Down
4 changes: 4 additions & 0 deletions src/cloud-element-templates/util/calledElement.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export function ensureNoPropagation(calledElement) {
calledElement.set('propagateAllChildVariables', false);
calledElement.set('propagateAllParentVariables', false);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import updateTemplates from './fixtures/condition-update.json';
import messageTemplates from './fixtures/condition-message.json';
import messageCorrelationTemplate from './fixtures/message-correlation-key.json';

import calledElementTemplate from './fixtures/condition-called-element.json';

import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil';
import { findExtension, findMessage, findZeebeSubscription } from 'src/cloud-element-templates/Helper';
import ElementTemplatesConditionChecker from 'src/cloud-element-templates/ElementTemplatesConditionChecker';
Expand Down Expand Up @@ -1108,6 +1110,140 @@ describe('provider/cloud-element-templates - ElementTemplatesConditionChecker',
});


describe('update zeebe:calledElement', function() {

it('should add conditional entries', inject(
async function(elementRegistry, modeling) {

// given
const element = elementRegistry.get('Task_1');
changeTemplate(element, calledElementTemplate);

const businessObject = getBusinessObject(element);

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

const calledElement = findExtension(businessObject, 'zeebe:CalledElement');

// then
expect(calledElement).to.jsonEqual({
$type: 'zeebe:CalledElement',
processId: 'one',
propagateAllChildVariables: false,
propagateAllParentVariables: false
});
})
);


it('should remove conditional entries', inject(
async function(elementRegistry, modeling) {

// given
const element = elementRegistry.get('Task_1');
changeTemplate(element, calledElementTemplate);

const businessObject = getBusinessObject(element);
modeling.updateProperties(element, {
name: 'foo'
});

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

const calledElement = findExtension(businessObject, 'zeebe:CalledElement');

// then
expect(calledElement).not.to.exist;
})
);


it('should switch between conditional properties', inject(
async function(elementRegistry, modeling) {

// given
const element = elementRegistry.get('Task_1');
changeTemplate(element, calledElementTemplate);

const businessObject = getBusinessObject(element);
modeling.updateProperties(element, {
name: 'foo'
});

// when
modeling.updateProperties(element, {
name: 'bar'
});

const calledElement = findExtension(businessObject, 'zeebe:CalledElement');

// then
expect(calledElement).to.jsonEqual({
$type: 'zeebe:CalledElement',
processId: 'two',
propagateAllChildVariables: false,
propagateAllParentVariables: false
});
})
);


it('undo', inject(function(commandStack, elementRegistry, modeling) {

// given
const element = elementRegistry.get('Task_1');
changeTemplate(element, calledElementTemplate);

const businessObject = getBusinessObject(element);
modeling.updateProperties(element, {
name: 'foo'
});

// when
commandStack.undo();

const calledElement = findExtension(businessObject, 'zeebe:CalledElement');

// then
expect(calledElement).not.to.exist;
}));


it('redo', inject(function(commandStack, elementRegistry, modeling) {

// given
const element = elementRegistry.get('Task_1');
changeTemplate(element, calledElementTemplate);

const businessObject = getBusinessObject(element);
modeling.updateProperties(element, {
name: 'foo'
});
commandStack.undo();

// when
commandStack.redo();

const calledElement = findExtension(businessObject, 'zeebe:CalledElement');

// then
expect(calledElement).to.jsonEqual({
$type: 'zeebe:CalledElement',
processId: 'one',
propagateAllChildVariables: false,
propagateAllParentVariables: false
});
}));

});


describe('update referenced element', function() {

const template = messageTemplates[2];
Expand Down
Loading

0 comments on commit dbb002e

Please sign in to comment.