Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add elementTemplates.createElement for Camunda Cloud #605

Merged
merged 2 commits into from
Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/provider/cloud-element-templates/CreateHelper.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil';

import { findExtension } from './Helper';


/**
* Create an input parameter representing the given
* binding and value.
Expand Down Expand Up @@ -90,4 +95,27 @@ export function shouldUpdate(value, property) {
const { optional } = property;

return value || !optional;
}

/**
* Gets or, in case not existent, creates extension element for given element.
*
* @param {djs.model.Base} element
* @param {String} type
* @param {BpmnFactory} bpmnFactory
* @returns {ModdleElement}
*/
export function ensureExtension(element, type, bpmnFactory) {
const businessObject = getBusinessObject(element);
const extensionElements = businessObject.get('extensionElements');

let extension = findExtension(extensionElements, type);

if (!extension) {
extension = bpmnFactory.create(type);
extension.$parent = extensionElements;
extensionElements.get('values').push(extension);
}

return extension;
}
21 changes: 20 additions & 1 deletion src/provider/cloud-element-templates/ElementTemplates.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import { default as DefaultElementTemplates } from '../element-templates/Element
* Registry for element templates.
*/
export default class ElementTemplates extends DefaultElementTemplates {
constructor() {
constructor(templateElementFactory) {
super();
this._templates = {};
this._templateElementFactory = templateElementFactory;
}

_getTemplateId(element) {
Expand All @@ -22,4 +23,22 @@ export default class ElementTemplates extends DefaultElementTemplates {
return getTemplateVersion(element);
}

/**
* Create an element based on an element template.
*
* @param {ElementTemplate} template
* @returns {djs.model.Base}
*/
createElement(template) {
if (!template) {
throw new Error('template is missing');
}

const element = this._templateElementFactory.create(template);

return element;
}

}

ElementTemplates.$inject = [ 'templateElementFactory' ];
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
createInputParameter,
ensureExtension,
shouldUpdate
} from '../CreateHelper';


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

const {
binding,
value
} = property;

const ioMapping = ensureExtension(element, 'zeebe:IoMapping', bpmnFactory);

if (!shouldUpdate(value, property)) {
return;
}

const input = createInputParameter(binding, value, bpmnFactory);
input.$parent = ioMapping;
ioMapping.get('inputParameters').push(input);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
createOutputParameter,
ensureExtension,
shouldUpdate
} from '../CreateHelper';


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

const {
binding,
value
} = property;

const ioMapping = ensureExtension(element, 'zeebe:IoMapping', bpmnFactory);

if (!shouldUpdate(value, property)) {
return;
}

const output = createOutputParameter(binding, value, bpmnFactory);
output.$parent = ioMapping;
ioMapping.get('outputParameters').push(output);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil';


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

const {
binding,
value
} = property;

const {
name
} = binding;

const businessObject = getBusinessObject(element);

businessObject[name] = value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil';

import { createTaskDefinitionWithType } from '../CreateHelper';


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

const {
value
} = property;

const extensionElements = getBusinessObject(element).get('extensionElements');

const taskDefinition = createTaskDefinitionWithType(value, bpmnFactory);
taskDefinition.$parent = extensionElements;
extensionElements.get('values').push(taskDefinition);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {
createTaskHeader,
ensureExtension
} from '../CreateHelper';


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

const {
binding,
value
} = property;

const taskHeaders = ensureExtension(element, 'zeebe:TaskHeaders', bpmnFactory);

const header = createTaskHeader(binding, value, bpmnFactory);
header.$parent = taskHeaders;
taskHeaders.get('values').push(header);
}
}
148 changes: 148 additions & 0 deletions src/provider/cloud-element-templates/create/TemplateElementFactory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import {
getBusinessObject
} from 'bpmn-js/lib/util/ModelUtil';

import { find } from 'min-dash';

import validate from '../util/validate';

import PropertyBindingProvider from './PropertyBindingProvider';
import TaskDefinitionTypeBindingProvider from './TaskDefinitionTypeBindingProvider';
import InputBindingProvider from './InputBindingProvider';
import OutputBindingProvider from './OutputBindingProvider';
import TaskHeaderBindingProvider from './TaskHeaderBindingProvider';

import {
EXTENSION_BINDING_TYPES,
PROPERTY_TYPE,
ZEEBE_TASK_DEFINITION_TYPE_TYPE,
ZEBBE_INPUT_TYPE,
ZEEBE_OUTPUT_TYPE,
ZEEBE_TASK_HEADER_TYPE
} from '../util/bindingTypes';


export default class TemplateElementFactory {

constructor(bpmnFactory, elementFactory) {
this._bpmnFactory = bpmnFactory;
this._elementFactory = elementFactory;

this._providers = {
[PROPERTY_TYPE]: PropertyBindingProvider,
[ZEEBE_TASK_DEFINITION_TYPE_TYPE]: TaskDefinitionTypeBindingProvider,
[ZEBBE_INPUT_TYPE]: InputBindingProvider,
[ZEEBE_OUTPUT_TYPE]: OutputBindingProvider,
[ZEEBE_TASK_HEADER_TYPE]: TaskHeaderBindingProvider
};
}

/**
* Create an element based on an element template.
*
* @param {ElementTemplate} template
* @returns {djs.model.Base}
*/
create(template) {

const {
appliesTo,
properties
} = template;

const elementFactory = this._elementFactory;
const bpmnFactory = this._bpmnFactory;
const providers = this._providers;

// (0) make sure template is valid
const errors = validate([ template ]);

// todo(pinussilvestrus): return validation errors
if (errors && errors.length) {
throw new Error('template is invalid');
}

const type = appliesTo[0];

// (1) create element from appliesTo
const element = elementFactory.createShape({ type });

// (2) ensure extension elements
if (hasExtensionBindings(template)) {
this._ensureExtensionElements(element);
}

// (3) apply template
this._setModelerTemplate(element, template);

// (4) apply properties
properties.forEach(function(property) {

const {
binding
} = property;

const {
type: bindingType
} = binding;

const bindingProvider = providers[bindingType];

bindingProvider.create(element, {
property,
bpmnFactory
});
});

return element;
}

_ensureExtensionElements(element) {
const bpmnFactory = this._bpmnFactory;
const businessObject = getBusinessObject(element);

let extensionElements = businessObject.get('extensionElements');

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

extensionElements.$parent = businessObject;
businessObject.set('extensionElements', extensionElements);
}

return extensionElements;
}

_setModelerTemplate(element, template) {
const {
id,
version
} = template;

const businessObject = getBusinessObject(element);

businessObject.set('zeebe:modelerTemplate', id);
businessObject.set('zeebe:modelerTemplateVersion', version);
}
}

TemplateElementFactory.$inject = [ 'bpmnFactory', 'elementFactory' ];


// helper ////////////////

function hasExtensionBindings(template) {
const {
properties
} = template;

return find(properties, function(property) {
const {
binding
} = property;

return EXTENSION_BINDING_TYPES.includes(binding.type);
});
}
8 changes: 8 additions & 0 deletions src/provider/cloud-element-templates/create/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import TemplateElementFactory from './TemplateElementFactory';

export default {
__init__: [
'templateElementFactory'
],
templateElementFactory: [ 'type', TemplateElementFactory ]
};
2 changes: 2 additions & 0 deletions src/provider/cloud-element-templates/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import ElementTemplates from './ElementTemplates';
import ElementTemplatesLoader from './ElementTemplatesLoader';
import ReplaceBehavior from '../element-templates/ReplaceBehavior';
import commandsModule from './cmd';
import templateElementFactoryModule from './create';
import ElementTemplatesPropertiesProvider from './ElementTemplatesPropertiesProvider';

import zeebePropertiesProviderModule from '../zeebe';

export default {
__depends__: [
commandsModule,
templateElementFactoryModule,
translateModule,
zeebePropertiesProviderModule
],
Expand Down
Loading