Skip to content

Commit

Permalink
WIP: feat: template linkedResources
Browse files Browse the repository at this point in the history
  • Loading branch information
marstamm committed Jan 8, 2025
1 parent d9dcc09 commit 8dafb95
Show file tree
Hide file tree
Showing 6 changed files with 352 additions and 8 deletions.
149 changes: 147 additions & 2 deletions src/cloud-element-templates/cmd/ChangeElementTemplateHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ import {
MESSAGE_PROPERTY_TYPE,
MESSAGE_ZEEBE_SUBSCRIPTION_PROPERTY_TYPE,
TASK_DEFINITION_TYPES,
ZEEBE_CALLED_ELEMENT
ZEEBE_CALLED_ELEMENT,
ZEEBE_LINKED_RESOURCE_PROPERTY
} from '../util/bindingTypes';

import {
Expand Down Expand Up @@ -107,6 +108,8 @@ export default class ChangeElementTemplateHandler {
this._updateMessage(element, oldTemplate, newTemplate);

this._updateCalledElement(element, oldTemplate, newTemplate);

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

Expand Down Expand Up @@ -1032,6 +1035,118 @@ export default class ChangeElementTemplateHandler {

return replacedElement;
}


_updateLinkedResources(element, oldTemplate, newTemplate) {
const bpmnFactory = this._bpmnFactory,
commandStack = this._commandStack;

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

return newBindingType === 'zeebe:linkedResource#property';
});

const extensionElements = this._getOrCreateExtensionElements(element);

let linkedResources = findExtension(extensionElements, 'zeebe:LinkedResources');

// (1) remove linkedResourcess if no new specified
if (!newLinkedResources.length) {
if (!linkedResources) {
return;
}

commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: extensionElements,
properties: {
values: without(extensionElements.get('values'), linkedResources)
}
});
return;
}

if (!linkedResources) {
linkedResources = bpmnFactory.create('zeebe:LinkedResources');

linkedResources.$parent = extensionElements;

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

const oldLinkedResources = linkedResources.get('values')?.slice() || [];

newLinkedResources.forEach((newLinkedResource) => {
const oldProperty = findOldProperty(oldTemplate, newLinkedResource),
oldLinkedResource = findBusinessObject(extensionElements, newLinkedResource),
newPropertyValue = getDefaultValue(newLinkedResource),
newBinding = newLinkedResource.binding;

// (2) update old LinkesResources
if (oldLinkedResource) {

// debugger;
console.log(oldLinkedResource, oldLinkedResource, oldProperty, newLinkedResource, shouldKeepValue(oldLinkedResource, oldProperty, newLinkedResource));

if (
shouldUpdate(newPropertyValue, newLinkedResource)
|| shouldKeepValue(oldLinkedResource, oldProperty, newLinkedResource)
) {
remove(oldLinkedResources, oldLinkedResource);
}

if (!shouldKeepValue(oldLinkedResource, oldProperty, newLinkedResource)) {
commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: oldLinkedResource,
properties: {
[newBinding.property]: newPropertyValue
}
});
}
}

// (3) add new linkedResources
else if (shouldUpdate(newPropertyValue, newLinkedResource)) {
const newProperties = {
linkName: newBinding.linkName,
[newBinding.property]: newPropertyValue
};

const newLinkedResource = createElement('zeebe:LinkedResource', newProperties, extensionElements, bpmnFactory);

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


// (4) remove old linkedResources
// TODO: remove single properties as well as complete linkedResources elements
if (oldLinkedResources.length) {
commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: linkedResources,
properties: {
properties: without(linkedResources.get('values'), linkedResource => oldLinkedResources.includes(linkedResource))
}
});
}
}

}

ChangeElementTemplateHandler.$inject = [
Expand Down Expand Up @@ -1106,6 +1221,18 @@ function findBusinessObject(element, property) {
return value.get('name') === binding.name;
});
}

if (bindingType === ZEEBE_LINKED_RESOURCE_PROPERTY) {
const linkedResources = findExtension(businessObject, 'zeebe:LinkedResources');

if (!linkedResources) {
return;
}

return linkedResources.get('values').find((value) => {
return value.get('linkName') === binding.linkName;
});
}
}

/**
Expand Down Expand Up @@ -1224,6 +1351,19 @@ export function findOldProperty(oldTemplate, newProperty) {
return oldBinding.name === newBinding.name;
});
}

if (newBindingType === ZEEBE_LINKED_RESOURCE_PROPERTY) {
return oldProperties.find(oldProperty => {
const oldBinding = oldProperty.binding,
oldBindingType = oldBinding.type;

if (oldBindingType !== ZEEBE_LINKED_RESOURCE_PROPERTY) {
return;
}

return oldBinding.linkName === newBinding.linkName && oldBinding.property === newBinding.property;
});
}
}

/**
Expand Down Expand Up @@ -1289,7 +1429,8 @@ function getPropertyValue(element, property) {

const binding = property.binding,
bindingName = binding.name,
bindingType = binding.type;
bindingType = binding.type,
bindingProperty = binding.property;


if (bindingType === 'property') {
Expand Down Expand Up @@ -1323,6 +1464,10 @@ function getPropertyValue(element, property) {
if (bindingType === MESSAGE_ZEEBE_SUBSCRIPTION_PROPERTY_TYPE) {
return businessObject.get(bindingName);
}

if (bindingType === ZEEBE_LINKED_RESOURCE_PROPERTY) {
return businessObject.get(bindingProperty);
}
}

function remove(array, item) {
Expand Down
41 changes: 41 additions & 0 deletions src/cloud-element-templates/create/LinkedResourceProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil';
import { createElement } from '../../utils/ElementUtil';
import {
ensureExtension
} from '../CreateHelper';
import { getDefaultValue } from '../Helper';

import {
getTaskDefinitionPropertyName
} from '../util/taskDefinition';


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

const {
binding: {
property: bindingProperty,
linkName
}
} = property;

const value = getDefaultValue(property);

const bo = getBusinessObject(element);
const linkedResources = ensureExtension(element, 'zeebe:LinkedResources', bpmnFactory);

let linkedResource = linkedResources.get('values').find(linkedResource => linkedResource.get('linkName') === linkName);

if (!linkedResource) {
linkedResource = createElement('zeebe:LinkedResource', { linkName }, bo, bpmnFactory);
linkedResources.get('values').push(linkedResource);
}

linkedResource.set(bindingProperty, 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 @@ -13,6 +13,7 @@ import ZeebePropertiesProvider from './ZeebePropertiesProvider';
import { MessagePropertyBindingProvider } from './MessagePropertyBindingProvider';
import { MessageZeebeSubscriptionBindingProvider } from './MessageZeebeSubscriptionBindingProvider';
import { CalledElementBindingProvider } from './CalledElementBindingProvider';
import LinkedResourcePropertyBindingProvider from './LinkedResourceProvider';

import {
MESSAGE_PROPERTY_TYPE,
Expand All @@ -24,7 +25,8 @@ import {
ZEEBE_OUTPUT_TYPE,
ZEEBE_TASK_HEADER_TYPE,
ZEBBE_PROPERTY_TYPE,
ZEEBE_CALLED_ELEMENT
ZEEBE_CALLED_ELEMENT,
ZEEBE_LINKED_RESOURCE_PROPERTY
} from '../util/bindingTypes';

import {
Expand All @@ -47,7 +49,8 @@ export default class TemplateElementFactory {
[ZEEBE_TASK_HEADER_TYPE]: TaskHeaderBindingProvider,
[MESSAGE_PROPERTY_TYPE]: MessagePropertyBindingProvider,
[MESSAGE_ZEEBE_SUBSCRIPTION_PROPERTY_TYPE]: MessageZeebeSubscriptionBindingProvider,
[ZEEBE_CALLED_ELEMENT]: CalledElementBindingProvider
[ZEEBE_CALLED_ELEMENT]: CalledElementBindingProvider,
[ZEEBE_LINKED_RESOURCE_PROPERTY]: LinkedResourcePropertyBindingProvider
};
}

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 @@ -10,6 +10,7 @@ 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 ZEEBE_LINKED_RESOURCE_PROPERTY = 'zeebe:linkedResource#property';

export const EXTENSION_BINDING_TYPES = [
MESSAGE_ZEEBE_SUBSCRIPTION_PROPERTY_TYPE,
Expand All @@ -19,7 +20,8 @@ export const EXTENSION_BINDING_TYPES = [
ZEEBE_TASK_DEFINITION_TYPE_TYPE,
ZEEBE_TASK_DEFINITION,
ZEEBE_TASK_HEADER_TYPE,
ZEEBE_CALLED_ELEMENT
ZEEBE_CALLED_ELEMENT,
ZEEBE_LINKED_RESOURCE_PROPERTY
];

export const TASK_DEFINITION_TYPES = [
Expand Down
63 changes: 60 additions & 3 deletions src/cloud-element-templates/util/propertyUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {
ZEEBE_OUTPUT_TYPE,
ZEEBE_PROPERTY_TYPE,
ZEEBE_TASK_HEADER_TYPE,
ZEEBE_CALLED_ELEMENT
ZEEBE_CALLED_ELEMENT,
ZEEBE_LINKED_RESOURCE_PROPERTY
} from './bindingTypes';

import {
Expand Down Expand Up @@ -81,7 +82,8 @@ function getRawPropertyValue(element, property, scope) {
const {
name,
property: bindingProperty,
type
type,
linkName
} = binding;

// property
Expand Down Expand Up @@ -210,6 +212,18 @@ function getRawPropertyValue(element, property, scope) {
return calledElement ? calledElement.get(bindingProperty) : defaultValue;
}

if (type === ZEEBE_LINKED_RESOURCE_PROPERTY) {
const linkedResources = findExtension(businessObject, 'zeebe:LinkedResources');

if (!linkedResources) {
return defaultValue;
}

const linkedResource = linkedResources.get('values').find((value) => value.get('linkName') === linkName);

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

// should never throw as templates are validated beforehand
throw unknownBindingError(element, property);
}
Expand Down Expand Up @@ -242,7 +256,9 @@ export function setPropertyValue(bpmnFactory, commandStack, element, property, v

const {
name,
type
type,
property: bindingProperty,
linkName
} = binding;

let extensionElements;
Expand Down Expand Up @@ -593,6 +609,47 @@ export function setPropertyValue(bpmnFactory, commandStack, element, property, v
}
}

if (type === ZEEBE_LINKED_RESOURCE_PROPERTY) {
let linkedResources = findExtension(businessObject, 'zeebe:LinkedResources');

if (!linkedResources) {
linkedResources = createElement('zeebe:LinkedResources', null, businessObject, bpmnFactory);

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

let linkedResource = linkedResources.get('values').find((value) => value.get('linkName') === linkName);

if (!linkedResource) {
linkedResource = createElement('zeebe:LinkedResource', { linkName }, businessObject, bpmnFactory);

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

commands.push({
cmd: 'element.updateModdleProperties',
context: {
...context,
moddleElement: linkedResource,
properties: { [ bindingProperty ]: value }
}
});
}

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

Expand Down
Loading

0 comments on commit 8dafb95

Please sign in to comment.