chore(copy-paste): rework and base upon diagram-js@5

* use <copyPaste.canCopyProperty> event to copy category value when copying group
* add camunda-bpmn-moddle for integration tests

BREAKING CHANGES

* CopyPaste: remove <property.clone>, add <moddleCopy.canCopyProperties>, <moddleCopy.canCopyProperty>, <moddleCopy.canSetCopiedProperty>
* BpmnRules: removed <elements.paste> rule in favor of <elements.create> rule
* BpmnRules: removed <element.paste> rule
* ElementFactory: use <attrs.di> property instead of <attrs.colors> for fill and stroke when creating element through ElementFactory#createBpmnElement
This commit is contained in:
Philipp Fromme 2019-08-07 15:17:28 +02:00 committed by merge-me[bot]
parent 14bf3a32ee
commit 194b963959
37 changed files with 4051 additions and 3645 deletions

View File

@ -3,143 +3,140 @@ import {
is
} from '../../util/ModelUtil';
import ModelCloneHelper from '../../util/model/ModelCloneHelper';
import {
getProperties,
IGNORED_PROPERTIES
} from '../../util/model/ModelCloneUtils';
import {
filter,
forEach
forEach,
isArray,
isUndefined,
omit,
reduce
} from 'min-dash';
function setProperties(descriptor, data, properties) {
function copyProperties(source, target, properties) {
if (!isArray(properties)) {
properties = [ properties ];
}
forEach(properties, function(property) {
if (data[property] !== undefined) {
descriptor[property] = data[property];
if (!isUndefined(source[property])) {
target[property] = source[property];
}
});
}
function removeProperties(element, properties) {
forEach(properties, function(prop) {
if (element[prop]) {
delete element[prop];
if (!isArray(properties)) {
properties = [ properties ];
}
forEach(properties, function(property) {
if (element[property]) {
delete element[property];
}
});
}
export default function BpmnCopyPaste(
bpmnFactory, eventBus, copyPaste,
clipboard, canvas, bpmnRules) {
var LOW_PRIORITY = 750;
var helper = new ModelCloneHelper(eventBus, bpmnFactory);
copyPaste.registerDescriptor(function(element, descriptor) {
export default function BpmnCopyPaste(bpmnFactory, eventBus, moddleCopy) {
eventBus.on('copyPaste.copyElement', LOW_PRIORITY, function(context) {
var descriptor = context.descriptor,
element = context.element;
var businessObject = descriptor.oldBusinessObject = getBusinessObject(element);
var colors = {};
descriptor.type = element.type;
setProperties(descriptor, businessObject.di, [ 'isExpanded' ]);
descriptor.di = {};
setProperties(colors, businessObject.di, [ 'fill', 'stroke' ]);
// fill and stroke will be set to DI
copyProperties(businessObject.di, descriptor.di, [
'fill',
'stroke'
]);
descriptor.colors = colors;
copyProperties(businessObject.di, descriptor, 'isExpanded');
if (element.type === 'label') {
if (isLabel(descriptor)) {
return descriptor;
}
setProperties(descriptor, businessObject, [
'processRef',
'triggeredByEvent'
]);
// default sequence flow
if (businessObject.default) {
descriptor.default = businessObject.default.id;
}
return descriptor;
});
eventBus.on('element.paste', function(context) {
var descriptor = context.descriptor,
createdElements = context.createdElements,
parent = descriptor.parent,
rootElement = canvas.getRootElement(),
eventBus.on('moddleCopy.canCopyProperty', function(context) {
var parent = context.parent,
property = context.property,
propertyName = context.propertyName;
if (is(parent, 'bpmn:Participant') &&
is(property, 'bpmn:Process') &&
propertyName === 'processRef') {
return bpmnFactory.create('bpmn:Process');
}
});
var references;
function resolveReferences(descriptor) {
var businessObject = getBusinessObject(descriptor);
// default sequence flows
if (descriptor.default) {
references[ descriptor.default ] = {
element: businessObject,
property: 'default'
};
}
references = omit(references, reduce(references, function(array, reference, key) {
var element = reference.element,
property = reference.property;
if (key === descriptor.id) {
element[ property ] = businessObject;
array.push(descriptor.id);
}
return array;
}, []));
}
eventBus.on('copyPaste.pasteElements', function() {
references = {};
});
eventBus.on('copyPaste.pasteElement', function(context) {
var cache = context.cache,
descriptor = context.descriptor,
oldBusinessObject = descriptor.oldBusinessObject,
newBusinessObject,
source,
target,
canConnect;
newBusinessObject;
newBusinessObject = bpmnFactory.create(oldBusinessObject.$type);
// do NOT copy business object if external label
if (isLabel(descriptor)) {
descriptor.businessObject = getBusinessObject(cache[ descriptor.labelTarget ]);
var properties = getProperties(oldBusinessObject.$descriptor);
properties = filter(properties, function(property) {
return IGNORED_PROPERTIES.indexOf(property.replace(/bpmn:/, '')) === -1;
});
descriptor.businessObject = helper.clone(oldBusinessObject, newBusinessObject, properties);
if (descriptor.type === 'label') {
return;
}
if (is(parent, 'bpmn:Process')) {
descriptor.parent = is(rootElement, 'bpmn:Collaboration') ? rootElement : parent;
}
newBusinessObject = bpmnFactory.create(oldBusinessObject.$type);
if (descriptor.type === 'bpmn:DataOutputAssociation' ||
descriptor.type === 'bpmn:DataInputAssociation' ||
descriptor.type === 'bpmn:MessageFlow') {
descriptor.parent = rootElement;
}
descriptor.businessObject = moddleCopy.copyElement(
oldBusinessObject,
newBusinessObject
);
if (is(parent, 'bpmn:Lane')) {
descriptor.parent = parent.parent;
}
// resolve references e.g. default sequence flow
resolveReferences(descriptor);
// make sure that the correct type of connection is created
if (descriptor.waypoints) {
source = createdElements[descriptor.source];
target = createdElements[descriptor.target];
copyProperties(descriptor, newBusinessObject, 'isExpanded');
if (source && target) {
source = source.element;
target = target.element;
}
canConnect = bpmnRules.canConnect(source, target);
if (canConnect) {
descriptor.type = canConnect.type;
}
}
// remove the id or else we cannot paste multiple times
delete newBusinessObject.id;
// assign an ID
bpmnFactory._ensureId(newBusinessObject);
if (descriptor.type === 'bpmn:Participant' && descriptor.processRef) {
descriptor.processRef = newBusinessObject.processRef = bpmnFactory.create('bpmn:Process');
}
setProperties(newBusinessObject, descriptor, [
'isExpanded',
'triggeredByEvent'
]);
removeProperties(descriptor, [
'triggeredByEvent'
]);
removeProperties(descriptor, 'oldBusinessObject');
});
}
@ -148,8 +145,11 @@ export default function BpmnCopyPaste(
BpmnCopyPaste.$inject = [
'bpmnFactory',
'eventBus',
'copyPaste',
'clipboard',
'canvas',
'bpmnRules'
];
'moddleCopy'
];
// helpers //////////
function isLabel(element) {
return !!element.labelTarget;
}

View File

@ -0,0 +1,271 @@
import {
find,
forEach,
isArray,
isDefined,
isObject,
matchPattern,
reduce,
sortBy
} from 'min-dash';
var DISALLOWED_PROPERTIES = [
'artifacts',
'dataInputAssociations',
'dataOutputAssociations',
'default',
'flowElements',
'lanes',
'incoming',
'outgoing'
];
/**
* @typedef {Function} <moddleCopy.canCopyProperties> listener
*
* @param {Object} context
* @param {Array<string>} context.propertyNames
* @param {ModdleElement} context.sourceElement
* @param {ModdleElement} context.targetElement
*
* @returns {Array<string>|boolean} - Return properties to be copied or false to disallow
* copying.
*/
/**
* @typedef {Function} <moddleCopy.canCopyProperty> listener
*
* @param {Object} context
* @param {ModdleElement} context.parent
* @param {*} context.property
* @param {string} context.propertyName
*
* @returns {*|boolean} - Return copied property or false to disallow
* copying.
*/
/**
* @typedef {Function} <moddleCopy.canSetCopiedProperty> listener
*
* @param {Object} context
* @param {ModdleElement} context.parent
* @param {*} context.property
* @param {string} context.propertyName
*
* @returns {boolean} - Return false to disallow
* setting copied property.
*/
/**
* Utility for copying model properties from source element to target element.
*
* @param {EventBus} eventBus
* @param {BpmnFactory} bpmnFactory
* @param {BpmnModdle} moddle
*/
export default function ModdleCopy(eventBus, bpmnFactory, moddle) {
this._bpmnFactory = bpmnFactory;
this._eventBus = eventBus;
this._moddle = moddle;
// copy extension elements last
eventBus.on('moddleCopy.canCopyProperties', function(context) {
var propertyNames = context.propertyNames;
if (!propertyNames || !propertyNames.length) {
return;
}
return sortBy(propertyNames, function(propertyName) {
return propertyName === 'extensionElements';
});
});
// default check wether property can be copied
eventBus.on('moddleCopy.canCopyProperty', function(context) {
var parent = context.parent,
parentDescriptor = isObject(parent) && parent.$descriptor,
propertyName = context.propertyName;
if (propertyName && DISALLOWED_PROPERTIES.indexOf(propertyName) !== -1) {
// disallow copying property
return false;
}
if (propertyName &&
parentDescriptor &&
!find(parentDescriptor.properties, matchPattern({ name: propertyName }))) {
// disallow copying property
return false;
}
});
// do NOT allow to copy empty extension elements
eventBus.on('moddleCopy.canSetCopiedProperty', function(context) {
var property = context.property;
if (is(property, 'bpmn:ExtensionElements') && (!property.values || !property.values.length)) {
// disallow setting copied property
return false;
}
});
}
ModdleCopy.$inject = [
'eventBus',
'bpmnFactory',
'moddle'
];
/**
* Copy model properties of source element to target element.
*
* @param {ModdleElement} sourceElement
* @param {ModdleElement} targetElement
* @param {Array<string>} [propertyNames]
*
* @param {ModdleElement}
*/
ModdleCopy.prototype.copyElement = function(sourceElement, targetElement, propertyNames) {
var self = this;
if (propertyNames && !isArray(propertyNames)) {
propertyNames = [ propertyNames ];
}
propertyNames = propertyNames || getPropertyNames(sourceElement.$descriptor);
var canCopyProperties = this._eventBus.fire('moddleCopy.canCopyProperties', {
propertyNames: propertyNames,
sourceElement: sourceElement,
targetElement: targetElement
});
if (canCopyProperties === false) {
return targetElement;
}
if (isArray(canCopyProperties)) {
propertyNames = canCopyProperties;
}
// copy properties
forEach(propertyNames, function(propertyName) {
var sourceProperty;
if (sourceElement.hasOwnProperty(propertyName)) {
sourceProperty = sourceElement.get(propertyName);
}
var copiedProperty = self.copyProperty(sourceProperty, targetElement, propertyName);
var canSetProperty = self._eventBus.fire('moddleCopy.canSetCopiedProperty', {
parent: parent,
property: copiedProperty,
propertyName: propertyName
});
if (canSetProperty === false) {
return;
}
if (isDefined(copiedProperty)) {
targetElement.set(propertyName, copiedProperty);
}
});
return targetElement;
};
/**
* Copy model property.
*
* @param {*} property
* @param {ModdleElement} parent
* @param {string} propertyName
*
* @returns {*}
*/
ModdleCopy.prototype.copyProperty = function(property, parent, propertyName) {
var self = this;
// allow others to copy property
var copiedProperty = this._eventBus.fire('moddleCopy.canCopyProperty', {
parent: parent,
property: property,
propertyName: propertyName
});
// return if copying is NOT allowed
if (copiedProperty === false) {
return;
}
if (copiedProperty) {
if (isObject(copiedProperty) && copiedProperty.$type && !copiedProperty.$parent) {
copiedProperty.$parent = parent;
}
return copiedProperty;
}
var propertyDescriptor = this._moddle.getPropertyDescriptor(parent, propertyName);
// do NOT copy Ids and references
if (propertyDescriptor.isId || propertyDescriptor.isReference) {
return;
}
// copy arrays
if (isArray(property)) {
return reduce(property, function(childProperties, childProperty) {
// recursion
copiedProperty = self.copyProperty(childProperty, parent, propertyName);
// copying might NOT be allowed
if (copiedProperty) {
copiedProperty.$parent = parent;
return childProperties.concat(copiedProperty);
}
return childProperties;
}, []);
}
// copy model elements
if (isObject(property) && property.$type) {
copiedProperty = self._bpmnFactory.create(property.$type);
copiedProperty.$parent = parent;
// recursion
copiedProperty = self.copyElement(property, copiedProperty);
return copiedProperty;
}
// copy primitive properties
return property;
};
// helpers //////////
export function getPropertyNames(descriptor, keepDefaultProperties) {
return reduce(descriptor.properties, function(properties, property) {
if (keepDefaultProperties && property.default) {
return properties;
}
return properties.concat(property.name);
}, []);
}
function is(element, type) {
return element && (typeof element.$instanceOf === 'function') && element.$instanceOf(type);
}

View File

@ -1,11 +1,13 @@
import CopyPasteModule from 'diagram-js/lib/features/copy-paste';
import BpmnCopyPaste from './BpmnCopyPaste';
import ModdleCopy from './ModdleCopy';
export default {
__depends__: [
CopyPasteModule
],
__init__: [ 'bpmnCopyPaste' ],
bpmnCopyPaste: [ 'type', BpmnCopyPaste ]
__init__: [ 'bpmnCopyPaste', 'moddleCopy' ],
bpmnCopyPaste: [ 'type', BpmnCopyPaste ],
moddleCopy: [ 'type', ModdleCopy ]
};

View File

@ -90,10 +90,10 @@ ElementFactory.prototype.createBpmnElement = function(elementType, attrs) {
}, attrs);
}
if (attrs.colors) {
assign(businessObject.di, attrs.colors);
if (attrs.di) {
assign(businessObject.di, attrs.di);
delete attrs.colors;
delete attrs.di;
}
applyAttributes(businessObject, attrs, [

View File

@ -1,71 +0,0 @@
import inherits from 'inherits';
import {
forEach
} from 'min-dash';
import { is } from '../../../util/ModelUtil';
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
export default function CopyPasteBehavior(eventBus, modeling, canvas) {
CommandInterceptor.call(this, eventBus);
this.preExecute('elements.paste', 1500, function(context) {
var topParent = context.topParent;
// always grab the latest root
if (!topParent.parent) {
context.topParent = canvas.getRootElement();
}
if (is(topParent, 'bpmn:Lane')) {
do {
// unwrap Lane -> LaneSet -> (Lane | FlowElementsContainer)
topParent = context.topParent = topParent.parent;
} while (is(topParent, 'bpmn:Lane') || !is(topParent, 'bpmn:Participant'));
}
}, true);
this.postExecute('elements.paste', function(context) {
var tree = context.tree,
createdElements = tree.createdElements;
forEach(createdElements, function(data) {
var element = data.element,
businessObject = element.businessObject,
descriptor = data.descriptor,
defaultFlow;
if ((is(businessObject, 'bpmn:ExclusiveGateway') || is(businessObject, 'bpmn:InclusiveGateway') ||
is(businessObject, 'bpmn:Activity')) && descriptor.default) {
defaultFlow = createdElements[descriptor.default];
// if the default flow wasn't created, means that it wasn't copied
if (defaultFlow) {
defaultFlow = defaultFlow.element;
} else {
defaultFlow = undefined;
}
delete element.default;
modeling.updateProperties(element, { default: defaultFlow });
}
});
}, true);
}
CopyPasteBehavior.$inject = [
'eventBus',
'modeling',
'canvas'
];
inherits(CopyPasteBehavior, CommandInterceptor);

View File

@ -0,0 +1,27 @@
import inherits from 'inherits';
import { is } from '../../../util/ModelUtil';
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
import { getParent } from '../util/ModelingUtil';
export default function CreateBehavior(injector) {
injector.invoke(CommandInterceptor, this);
this.preExecute('shape.create', 1500, function(event) {
var context = event.context,
parent = context.parent;
if (is(parent, 'bpmn:Lane')) {
context.parent = getParent(parent, 'bpmn:Participant');
}
});
}
CreateBehavior.$inject = [ 'injector' ];
inherits(CreateBehavior, CommandInterceptor);

View File

@ -16,12 +16,21 @@ import {
createCategoryValue
} from './util/CategoryUtil';
var HIGH_PRIORITY = 2000;
/**
* BPMN specific Group behavior
*/
export default function GroupBehavior(eventBus, bpmnFactory, canvas, elementRegistry) {
CommandInterceptor.call(this, eventBus);
export default function GroupBehavior(
bpmnFactory,
canvas,
elementRegistry,
eventBus,
injector,
moddleCopy
) {
injector.invoke(CommandInterceptor, this);
/**
* Gets process definitions
@ -43,8 +52,13 @@ export default function GroupBehavior(eventBus, bpmnFactory, canvas, elementRegi
function removeReferencedCategoryValue(shape) {
var businessObject = getBusinessObject(shape),
categoryValue = businessObject.categoryValueRef,
category = categoryValue.$parent;
categoryValue = businessObject.categoryValueRef;
if (!categoryValue) {
return;
}
var category = categoryValue.$parent;
if (!categoryValue) {
return;
@ -142,27 +156,18 @@ export default function GroupBehavior(eventBus, bpmnFactory, canvas, elementRegi
* create new category + value when group was created
*/
this.execute('shape.create', function(event) {
var context = event.context,
shape = context.shape,
businessObject = getBusinessObject(shape),
oldBusinessObject = shape.oldBusinessObject;
businessObject = getBusinessObject(shape);
if (is(businessObject, 'bpmn:Group') && !businessObject.categoryValueRef) {
var definitions = getDefinitions(),
categoryValue = createCategoryValue(definitions, bpmnFactory);
// set name from copied group if existing
if (oldBusinessObject && oldBusinessObject.categoryValueRef) {
categoryValue.value = oldBusinessObject.categoryValueRef.value;
}
// link the reference to the Group
businessObject.categoryValueRef = categoryValue;
}
});
@ -172,7 +177,6 @@ export default function GroupBehavior(eventBus, bpmnFactory, canvas, elementRegi
shape = context.shape;
if (is(shape, 'bpmn:Group')) {
removeReferencedCategoryValue(shape);
delete getBusinessObject(shape).categoryValueRef;
@ -180,13 +184,28 @@ export default function GroupBehavior(eventBus, bpmnFactory, canvas, elementRegi
}
});
// copy bpmn:CategoryValue when copying element
eventBus.on('moddleCopy.canCopyProperty', HIGH_PRIORITY, function(context) {
var property = context.property,
categoryValue;
if (is(property, 'bpmn:CategoryValue')) {
categoryValue = createCategoryValue(getDefinitions(), bpmnFactory);
// return copy of category
return moddleCopy.copyElement(property, categoryValue);
}
});
}
GroupBehavior.$inject = [
'eventBus',
'bpmnFactory',
'canvas',
'elementRegistry'
'elementRegistry',
'eventBus',
'injector',
'moddleCopy'
];
inherits(GroupBehavior, CommandInterceptor);

View File

@ -100,7 +100,12 @@ export default function LabelBehavior(
// create label shape after shape/connection was created
this.postExecute([ 'shape.create', 'connection.create' ], function(e) {
var context = e.context;
var context = e.context,
hints = context.hints || {};
if (hints.createElementsBehavior === false) {
return;
}
var element = context.shape || context.connection,
businessObject = element.businessObject;

View File

@ -2,7 +2,7 @@ import AdaptiveLabelPositioningBehavior from './AdaptiveLabelPositioningBehavior
import AppendBehavior from './AppendBehavior';
import AttachEventBehavior from './AttachEventBehavior';
import BoundaryEventBehavior from './BoundaryEventBehavior';
import CopyPasteBehavior from './CopyPasteBehavior';
import CreateBehavior from './CreateBehavior';
import FixHoverBehavior from './FixHoverBehavior';
import CreateBoundaryEventBehavior from './CreateBoundaryEventBehavior';
import CreateDataObjectBehavior from './CreateDataObjectBehavior';
@ -36,7 +36,7 @@ export default {
'appendBehavior',
'attachEventBehavior',
'boundaryEventBehavior',
'copyPasteBehavior',
'createBehavior',
'fixHoverBehavior',
'createBoundaryEventBehavior',
'createDataObjectBehavior',
@ -68,7 +68,7 @@ export default {
appendBehavior: [ 'type', AppendBehavior ],
attachEventBehavior: [ 'type', AttachEventBehavior ],
boundaryEventBehavior: [ 'type', BoundaryEventBehavior ],
copyPasteBehavior: [ 'type', CopyPasteBehavior ],
createBehavior: [ 'type', CreateBehavior ],
fixHoverBehavior: [ 'type', FixHoverBehavior ],
createBoundaryEventBehavior: [ 'type', CreateBoundaryEventBehavior ],
createDataObjectBehavior: [ 'type', CreateDataObjectBehavior ],

View File

@ -2,6 +2,9 @@ import {
pick,
assign,
filter,
forEach,
isArray,
isUndefined,
has
} from 'min-dash';
@ -19,12 +22,19 @@ import {
isEventSubProcess
} from '../../util/DiUtil';
import {
getProperties,
IGNORED_PROPERTIES
} from '../../util/model/ModelCloneUtils';
import { getPropertyNames } from '../copy-paste/ModdleCopy';
import ModelCloneHelper from '../../util/model/ModelCloneHelper';
function copyProperties(source, target, properties) {
if (!isArray(properties)) {
properties = [ properties ];
}
forEach(properties, function(property) {
if (!isUndefined(source[property])) {
target[property] = source[property];
}
});
}
var CUSTOM_PROPERTIES = [
'cancelActivity',
@ -67,12 +77,14 @@ function toggeling(element, target) {
* This module takes care of replacing BPMN elements
*/
export default function BpmnReplace(
bpmnFactory, elementFactory, replace,
selection, modeling, eventBus
bpmnFactory,
elementFactory,
moddleCopy,
modeling,
replace,
selection
) {
var helper = new ModelCloneHelper(eventBus, bpmnFactory);
/**
* Prepares a new business object for the replacement element
* and triggers the replace operation.
@ -108,51 +120,54 @@ export default function BpmnReplace(
businessObject: newBusinessObject
};
var elementProps = getProperties(oldBusinessObject.$descriptor),
newElementProps = getProperties(newBusinessObject.$descriptor, true),
var elementProps = getPropertyNames(oldBusinessObject.$descriptor),
newElementProps = getPropertyNames(newBusinessObject.$descriptor, true),
copyProps = intersection(elementProps, newElementProps);
// initialize special properties defined in target definition
assign(newBusinessObject, pick(target, CUSTOM_PROPERTIES));
var properties = filter(copyProps, function(property) {
var propName = property.replace(/bpmn:/, '');
var properties = filter(copyProps, function(propertyName) {
// copying event definitions, unless we replace
if (propName === 'eventDefinitions') {
if (propertyName === 'eventDefinitions') {
return hasEventDefinition(element, target.eventDefinitionType);
}
// retain loop characteristics if the target element
// is not an event sub process
if (propName === 'loopCharacteristics') {
if (propertyName === 'loopCharacteristics') {
return !isEventSubProcess(newBusinessObject);
}
// so the applied properties from 'target' don't get lost
if (property in newBusinessObject) {
if (newBusinessObject.hasOwnProperty(propertyName)) {
return false;
}
if (propName === 'processRef' && target.isExpanded === false) {
if (propertyName === 'processRef' && target.isExpanded === false) {
return false;
}
if (propName === 'triggeredByEvent') {
if (propertyName === 'triggeredByEvent') {
return false;
}
return IGNORED_PROPERTIES.indexOf(propName) === -1;
return true;
});
newBusinessObject = helper.clone(oldBusinessObject, newBusinessObject, properties);
newBusinessObject = moddleCopy.copyElement(
oldBusinessObject,
newBusinessObject,
properties
);
// initialize custom BPMN extensions
if (target.eventDefinitionType) {
// only initialize with new eventDefinition
// if we did not set an event definition yet,
// i.e. because we cloned it
// i.e. because we copied it
if (!hasEventDefinition(newBusinessObject, target.eventDefinitionType)) {
newElement.eventDefinitionType = target.eventDefinitionType;
}
@ -225,9 +240,13 @@ export default function BpmnReplace(
newElement.host = target.host;
}
if ('fill' in oldBusinessObject.di || 'stroke' in oldBusinessObject.di) {
assign(newElement, { colors: pick(oldBusinessObject.di, [ 'fill', 'stroke' ]) });
}
newElement.di = {};
// fill and stroke will be set to DI
copyProperties(oldBusinessObject.di, newElement.di, [
'fill',
'stroke'
]);
newElement = replace.replaceElement(element, newElement, hints);
@ -244,10 +263,10 @@ export default function BpmnReplace(
BpmnReplace.$inject = [
'bpmnFactory',
'elementFactory',
'replace',
'selection',
'moddleCopy',
'modeling',
'eventBus'
'replace',
'selection'
];

View File

@ -1,12 +1,14 @@
import SelectionModule from 'diagram-js/lib/features/selection';
import CopyPasteModule from '../copy-paste';
import ReplaceModule from 'diagram-js/lib/features/replace';
import SelectionModule from 'diagram-js/lib/features/selection';
import BpmnReplace from './BpmnReplace';
export default {
__depends__: [
SelectionModule,
ReplaceModule
CopyPasteModule,
ReplaceModule,
SelectionModule
],
bpmnReplace: [ 'type', BpmnReplace ]
};

View File

@ -1,8 +1,8 @@
import {
find,
some,
every,
forEach
find,
forEach,
some
} from 'min-dash';
import inherits from 'inherits';
@ -164,31 +164,10 @@ BpmnRules.prototype.init = function() {
});
this.addRule('element.copy', function(context) {
var collection = context.collection,
element = context.element;
var element = context.element,
elements = context.elements;
return canCopy(collection, element);
});
this.addRule('element.paste', function(context) {
var parent = context.parent,
element = context.element,
position = context.position,
source = context.source,
target = context.target;
if (source || target) {
return canConnect(source, target);
}
return canAttach([ element ], parent, null, position) || canCreate(element, parent, null, position);
});
this.addRule('elements.paste', function(context) {
var tree = context.tree,
target = context.target;
return canPaste(tree, target);
return canCopy(elements, element);
});
};
@ -537,41 +516,6 @@ function isDroppableBoundaryEvent(event) {
);
}
function canPaste(tree, target) {
var topLevel = tree[0],
participants;
if (is(target, 'bpmn:Collaboration')) {
return every(topLevel, function(e) {
return e.type === 'bpmn:Participant';
});
}
if (is(target, 'bpmn:Process')) {
participants = some(topLevel, function(e) {
return e.type === 'bpmn:Participant';
});
return !(participants && target.children.length > 0);
}
// disallow to create elements on collapsed pools
if (is(target, 'bpmn:Participant') && !isExpanded(target)) {
return false;
}
if (is(target, 'bpmn:FlowElementsContainer')) {
return isExpanded(target);
}
return isAny(target, [
'bpmn:Collaboration',
'bpmn:Lane',
'bpmn:Participant',
'bpmn:Process',
'bpmn:SubProcess' ]);
}
function isBoundaryEvent(element) {
return !isLabel(element) && is(element, 'bpmn:BoundaryEvent');
}
@ -946,16 +890,16 @@ function canInsert(shape, flow, position) {
canDrop(shape, flow.parent, position));
}
function contains(collection, element) {
return (collection && element) && collection.indexOf(element) !== -1;
function includes(elements, element) {
return (elements && element) && elements.indexOf(element) !== -1;
}
function canCopy(collection, element) {
if (is(element, 'bpmn:Lane') && !contains(collection, element.parent)) {
function canCopy(elements, element) {
if (is(element, 'bpmn:Lane') && !includes(elements, element.parent)) {
return false;
}
if (is(element, 'bpmn:BoundaryEvent') && !contains(collection, element.host)) {
if (is(element, 'bpmn:BoundaryEvent') && !includes(elements, element.host)) {
return false;
}

View File

@ -1,214 +0,0 @@
import {
forEach,
filter,
some,
sortBy,
isArray
} from 'min-dash';
import {
IGNORED_PROPERTIES
} from './ModelCloneUtils';
function isAllowedIn(extProp, type) {
var allowedIn = extProp.meta.allowedIn;
// '*' is a wildcard, which means any element is allowed to use this property
if (allowedIn.length === 1 && allowedIn[0] === '*') {
return true;
}
return allowedIn.indexOf(type) !== -1;
}
function isType(element, types) {
return some(types, function(type) {
return typeof element === type;
});
}
/**
* A bpmn properties cloning interface
*
*/
export default function ModelCloneHelper(eventBus, bpmnFactory) {
this._eventBus = eventBus;
this._bpmnFactory = bpmnFactory;
}
ModelCloneHelper.prototype.clone = function(refElement, newElement, properties) {
var self = this;
// hasNestedProperty: property allows us to avoid ending up with empty (xml) tags
// f.ex: if extensionElements.values is empty, don't set it
var context = {
newElement: newElement,
hasNestedProperty: false
};
// we want the extensionElements to be cloned last
// so that they can check certain properties
properties = sortBy(properties, function(prop) {
return prop === 'bpmn:extensionElements';
});
forEach(properties, function(propName) {
var refElementProp = refElement.get(propName),
newElementProp = newElement.get(propName),
propDescriptor = newElement.$model.getPropertyDescriptor(newElement, propName),
newProperty, name;
// we're not interested in cloning:
// - same values from simple types
// - cloning id's
// - cloning reference elements
if (newElementProp === refElementProp) {
return;
}
if (propDescriptor && (propDescriptor.isId || propDescriptor.isReference)) {
return;
}
// if the property is of type 'boolean', 'string', 'number' or 'null', just set it
if (isType(refElementProp, [ 'boolean', 'string', 'number' ]) || refElementProp === null) {
newElement.set(propName, refElementProp);
return;
}
if (isArray(refElementProp)) {
forEach(refElementProp, function(extElement) {
var newProp;
context.refTopLevelProperty = extElement;
newProp = self._deepClone(extElement, context);
if (context.hasNestedProperty) {
newProp.$parent = newElement;
newElementProp.push(newProp);
}
context.hasNestedProperty = false;
});
} else {
name = propName.replace(/bpmn:/, '');
context.refTopLevelProperty = refElementProp;
newProperty = self._deepClone(refElementProp, context);
if (context.hasNestedProperty) {
newProperty.$parent = newElement;
newElement.set(name, newProperty);
}
context.hasNestedProperty = false;
}
});
return newElement;
};
ModelCloneHelper.prototype._deepClone = function _deepClone(propertyElement, context) {
var self = this;
var eventBus = this._eventBus;
var bpmnFactory = this._bpmnFactory;
var newProp = bpmnFactory.create(propertyElement.$type);
var properties = filter(Object.keys(propertyElement), function(prop) {
var descriptor = newProp.$model.getPropertyDescriptor(newProp, prop);
if (descriptor && (descriptor.isId || descriptor.isReference)) {
return false;
}
// we need to make sure we don't clone certain properties
// which we cannot easily know if they hold references or not
if (IGNORED_PROPERTIES.indexOf(prop) !== -1) {
return false;
}
// make sure we don't copy the type
return prop !== '$type';
});
if (!properties.length) {
context.hasNestedProperty = true;
}
forEach(properties, function(propName) {
// check if the propertyElement has this property defined
if (propertyElement[propName] !== undefined &&
(propertyElement[propName].$type || isArray(propertyElement[propName]))) {
if (isArray(propertyElement[propName])) {
newProp[propName] = [];
forEach(propertyElement[propName], function(property) {
var extProp = propertyElement.$model.getTypeDescriptor(property.$type),
newDeepProp;
// we're not going to copy undefined types
if (!extProp) {
return;
}
var canClone = eventBus.fire('property.clone', {
newElement: context.newElement,
refTopLevelProperty: context.refTopLevelProperty,
propertyDescriptor: extProp
});
if (!canClone) {
// if can clone is 'undefined' or 'false'
// check for the meta information if it is allowed
if (propertyElement.$type === 'bpmn:ExtensionElements' &&
extProp.meta && extProp.meta.allowedIn &&
!isAllowedIn(extProp, context.newElement.$type)) {
return false;
}
}
newDeepProp = self._deepClone(property, context);
newDeepProp.$parent = newProp;
if (!newProp[propName]) {
newProp[propName] = [];
}
context.hasNestedProperty = true;
newProp[propName].push(newDeepProp);
});
} else if (propertyElement[propName].$type) {
newProp[propName] = self._deepClone(propertyElement[propName], context);
if (newProp[propName]) {
context.hasNestedProperty = true;
newProp[propName].$parent = newProp;
}
}
} else {
context.hasNestedProperty = true;
// just assign directly if it's a value
newProp[propName] = propertyElement[propName];
}
});
return newProp;
};

View File

@ -1,36 +0,0 @@
import {
forEach
} from 'min-dash';
/**
* These are the properties that should be ignored when cloning elements.
*
* @type {Array}
*/
export var IGNORED_PROPERTIES = [
'lanes',
'incoming',
'outgoing',
'artifacts',
'default',
'flowElements',
'dataInputAssociations',
'dataOutputAssociations'
];
export function getProperties(descriptor, keepDefault) {
var properties = [];
forEach(descriptor.properties, function(property) {
if (keepDefault && property.default) {
return;
}
properties.push(property.ns.name);
});
return properties;
}

3420
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,7 @@
"*.css"
],
"devDependencies": {
"camunda-bpmn-moddle": "^4.0.1",
"chai": "^4.1.2",
"chai-match": "^1.1.1",
"cpx": "^1.5.0",

View File

@ -1,102 +0,0 @@
<?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:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:collaboration id="Collaboration_0xsgb8u">
<bpmn:participant id="Participant_0pgdgt4" processRef="Process_1" />
<bpmn:participant id="Participant_1id96b4" processRef="Process_08nr0a7" />
<bpmn:messageFlow id="MessageFlow_150lriv" sourceRef="IntermediateThrowEvent_0audt6r" targetRef="Task_0n0k2nj" />
</bpmn:collaboration>
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:laneSet>
<bpmn:lane id="Lane_1gzt96j">
<bpmn:flowNodeRef>Task_1pamrp2</bpmn:flowNodeRef>
<bpmn:childLaneSet xsi:type="bpmn:tLaneSet">
<bpmn:lane id="Lane_1yo0kyz">
<bpmn:flowNodeRef>Task_1pamrp2</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_022an7b" />
</bpmn:childLaneSet>
</bpmn:lane>
<bpmn:lane id="Lane_1kulv9k">
<bpmn:flowNodeRef>Task_0n0k2nj</bpmn:flowNodeRef>
</bpmn:lane>
</bpmn:laneSet>
<bpmn:task id="Task_0n0k2nj" />
<bpmn:task id="Task_1pamrp2" />
</bpmn:process>
<bpmn:process id="Process_08nr0a7" isExecutable="false">
<bpmn:laneSet>
<bpmn:lane id="Lane_0aws6ii">
<bpmn:flowNodeRef>StartEvent_07r1iyh</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_1sd1zl3">
<bpmn:flowNodeRef>IntermediateThrowEvent_0audt6r</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_16ah5rn" />
</bpmn:laneSet>
<bpmn:intermediateThrowEvent id="IntermediateThrowEvent_0audt6r" />
<bpmn:startEvent id="StartEvent_07r1iyh" />
<bpmn:endEvent id="EndEvent_1u50ypf" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_0xsgb8u">
<bpmndi:BPMNShape id="Participant_0pgdgt4_di" bpmnElement="Participant_0pgdgt4">
<dc:Bounds x="93" y="21" width="600" height="323" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_1id96b4_di" bpmnElement="Participant_1id96b4">
<dc:Bounds x="93" y="432" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1gzt96j_di" bpmnElement="Lane_1gzt96j">
<dc:Bounds x="123" y="21" width="570" height="198" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1kulv9k_di" bpmnElement="Lane_1kulv9k">
<dc:Bounds x="123" y="219" width="570" height="125" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_0aws6ii_di" bpmnElement="Lane_0aws6ii">
<dc:Bounds x="123" y="432" width="570" height="83" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1sd1zl3_di" bpmnElement="Lane_1sd1zl3">
<dc:Bounds x="123" y="515" width="570" height="83" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_16ah5rn_di" bpmnElement="Lane_16ah5rn">
<dc:Bounds x="123" y="598" width="570" height="84" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="StartEvent_07r1iyh_di" bpmnElement="StartEvent_07r1iyh">
<dc:Bounds x="181" y="455" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="154" y="491" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="IntermediateThrowEvent_0audt6r_di" bpmnElement="IntermediateThrowEvent_0audt6r">
<dc:Bounds x="365" y="542" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="338" y="578" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="EndEvent_1u50ypf_di" bpmnElement="EndEvent_1u50ypf">
<dc:Bounds x="541" y="636" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="514" y="672" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_1pamrp2_di" bpmnElement="Task_1pamrp2">
<dc:Bounds x="341" y="56" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_0n0k2nj_di" bpmnElement="Task_0n0k2nj">
<dc:Bounds x="341" y="242" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="MessageFlow_150lriv_di" bpmnElement="MessageFlow_150lriv">
<di:waypoint xsi:type="dc:Point" x="383" y="542" />
<di:waypoint xsi:type="dc:Point" x="383" y="322" />
<bpmndi:BPMNLabel>
<dc:Bounds x="338" y="453.5" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Lane_1yo0kyz_di" bpmnElement="Lane_1yo0kyz">
<dc:Bounds x="153" y="21" width="540" height="136" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_022an7b_di" bpmnElement="Lane_022an7b">
<dc:Bounds x="153" y="157" width="540" height="62" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

File diff suppressed because it is too large Load Diff

View File

@ -1,56 +0,0 @@
var forEach = require('min-dash').forEach;
export default function DescriptorTree(tree) {
var self = this;
this._tree = {};
this._length = 0;
forEach(tree, function(branch, depth) {
if (branch.length) {
self._length += 1;
}
forEach(branch, function(element) {
element.depth = parseInt(depth, 10);
self._tree[element.id] = element;
});
});
}
DescriptorTree.prototype.getLength = function() {
return this._length;
};
DescriptorTree.prototype.getElement = function(id) {
return this._tree[id];
};
DescriptorTree.prototype.getDepth = function(depth) {
var newTree = {};
forEach(this._tree, function(element) {
if (element.depth === depth) {
newTree[element.id] = element;
}
});
return newTree;
};
DescriptorTree.prototype.getDepthLength = function(depth) {
var length = 0;
forEach(this._tree, function(element) {
if (element.depth === depth) {
length += 1;
}
});
return length;
};

View File

@ -0,0 +1,738 @@
import {
bootstrapModeler,
inject
} from 'test/TestHelper';
import copyPasteModule from 'lib/features/copy-paste';
import coreModule from 'lib/core';
import modelingModule from 'lib/features/modeling';
import camundaModdleModule from 'camunda-bpmn-moddle/lib';
import camundaPackage from 'camunda-bpmn-moddle/resources/camunda.json';
import {
getBusinessObject,
is
} from 'lib/util/ModelUtil';
var HIGH_PRIORITY = 3000;
describe('features/copy-paste/ModdleCopy', function() {
var testModules = [
camundaModdleModule,
copyPasteModule,
coreModule,
modelingModule
];
var basicXML = require('../../../fixtures/bpmn/basic.bpmn');
beforeEach(bootstrapModeler(basicXML, {
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
describe('simple', function() {
it('should copy primitive properties', inject(function(moddleCopy, moddle) {
// given
var userTask = moddle.create('bpmn:UserTask', {
asyncBefore: true
});
// when
var serviceTask = moddleCopy.copyElement(userTask, moddle.create('bpmn:ServiceTask'));
// then
expect(serviceTask.asyncBefore).to.be.true;
expectNoAttrs(serviceTask);
}));
it('should copy arrays of properties', inject(function(moddleCopy, moddle) {
// given
var messageEventDefinition = moddle.create('bpmn:MessageEventDefinition'),
signalEventDefinition = moddle.create('bpmn:SignalEventDefinition'),
startEvent = moddle.create('bpmn:StartEvent');
startEvent.eventDefinitions = [ messageEventDefinition, signalEventDefinition ];
// when
var endEvent = moddleCopy.copyElement(startEvent, moddle.create('bpmn:EndEvent'));
// then
var eventDefinitions = endEvent.eventDefinitions;
expect(eventDefinitions).to.have.length(2);
expect(eventDefinitions[0].$type).to.equal('bpmn:MessageEventDefinition');
expect(eventDefinitions[1].$type).to.equal('bpmn:SignalEventDefinition');
expectNoAttrs(endEvent);
}));
it('should NOT copy properties that are not allowed in target element', inject(
function(moddleCopy, moddle) {
// given
var userTask = moddle.create('bpmn:UserTask', {
assignee: 'foobar'
});
// when
var serviceTask = moddleCopy.copyElement(userTask, moddle.create('bpmn:ServiceTask'));
// then
expect(serviceTask.assignee).not.to.exist;
expectNoAttrs(serviceTask);
}
));
it('should NOT copy IDs', inject(function(moddleCopy, moddle) {
// given
var task = moddle.create('bpmn:Task', {
id: 'foo'
});
// when
var userTask = moddleCopy.copyElement(task, moddle.create('bpmn:UserTask'));
// then
expect(userTask.id).not.to.equal('foo');
expectNoAttrs(userTask);
}));
it('should NOT copy references', inject(function(moddleCopy, moddle) {
// given
var processRef = moddle.create('bpmn:Process'),
participant = moddle.create('bpmn:Participant');
participant.processRef = processRef;
// when
participant = moddleCopy.copyElement(participant, moddle.create('bpmn:Participant'));
// then
expect(participant.processRef).not.to.equal(processRef);
}));
it('should copy extension elements last', inject(function(moddleCopy, eventBus, moddle) {
// given
var connector = moddle.create('camunda:Connector'),
extensionElements = moddle.create('bpmn:ExtensionElements'),
messageEventDefinition = moddle.create('bpmn:MessageEventDefinition'),
messageEndEvent = moddle.create('bpmn:EndEvent');
connector.$parent = extensionElements;
extensionElements.$parent = messageEventDefinition;
extensionElements.values = [ connector ];
messageEventDefinition.$parent = messageEndEvent;
messageEventDefinition.extensionElements = extensionElements;
messageEndEvent.eventDefinitions = [ messageEventDefinition ];
var propertyNames = [];
eventBus.on('moddleCopy.canCopyProperty', function(context) {
var propertyName = context.propertyName;
propertyNames.push(propertyName);
});
moddleCopy.copyElement(messageEndEvent, moddle.create('bpmn:EndEvent'), [
'extensionElements',
'name'
]);
expect(propertyNames).to.eql([
'name',
'extensionElements'
]);
}));
it('should NOT copy empty extension elements', inject(function(moddleCopy, moddle) {
// given
var connector = moddle.create('camunda:Connector'),
extensionElements = moddle.create('bpmn:ExtensionElements'),
messageEventDefinition = moddle.create('bpmn:MessageEventDefinition'),
messageEndEvent = moddle.create('bpmn:EndEvent');
connector.$parent = extensionElements;
extensionElements.$parent = messageEventDefinition;
extensionElements.values = [ connector ];
messageEventDefinition.$parent = messageEndEvent;
messageEventDefinition.extensionElements = extensionElements;
messageEndEvent.eventDefinitions = [ messageEventDefinition ];
var startEvent = moddleCopy.copyElement(messageEndEvent, moddle.create('bpmn:StartEvent'));
// connector not allowed in start event
expect(startEvent.eventDefinitions[0].extensionElements).not.to.exist;
}));
it('should only copy specified properties', inject(function(moddleCopy, moddle) {
// given
var userTask = moddle.create('bpmn:UserTask', {
asyncBefore: true,
name: 'foo'
});
// when
var serviceTask = moddleCopy.copyElement(
userTask,
moddle.create('bpmn:ServiceTask'),
'asyncBefore'
);
// then
expect(serviceTask.asyncBefore).to.be.true;
expect(serviceTask.name).not.to.exist;
expectNoAttrs(serviceTask);
}));
});
describe('nested', function() {
it('should copy documentation', inject(function(moddleCopy, moddle) {
// given
var documentation = [
moddle.create('bpmn:Documentation', { text: 'FOO\nBAR', textFormat: 'xyz' }),
moddle.create('bpmn:Documentation', { text: '<html></html>' })
];
var userTask = moddle.create('bpmn:UserTask');
userTask.documentation = documentation;
// when
var serviceTask = moddleCopy.copyElement(userTask, moddle.create('bpmn:ServiceTask'));
expect(serviceTask.documentation[0].$parent).to.equal(serviceTask);
expect(serviceTask.documentation[0].text).to.equal('FOO\nBAR');
expect(serviceTask.documentation[0].textFormat).to.equal('xyz');
expect(serviceTask.documentation[1].$parent).to.equal(serviceTask);
expect(serviceTask.documentation[1].text).to.equal('<html></html>');
}));
it('should copy execution listener', inject(function(moddleCopy, moddle) {
// given
var script = moddle.create('camunda:Script', {
scriptFormat: 'groovy',
value: 'foo = bar;'
});
var executionListener = moddle.create('camunda:ExecutionListener', {
event: 'start',
script: script
});
var extensionElements = moddle.create('bpmn:ExtensionElements'),
userTask = moddle.create('bpmn:UserTask');
executionListener.$parent = extensionElements;
extensionElements.$parent = userTask;
extensionElements.values = [ executionListener ];
userTask.extensionElements = extensionElements;
// when
var serviceTask = moddleCopy.copyElement(userTask, moddle.create('bpmn:ServiceTask'));
// then
executionListener = serviceTask.extensionElements.values[0];
expect(executionListener).to.exist;
expect(executionListener.$type).to.equal('camunda:ExecutionListener');
expect(executionListener.$parent).to.equal(serviceTask.extensionElements);
expect(executionListener.event).to.equal('start');
script = executionListener.script;
expect(script).to.exist;
expect(script.$type).to.equal('camunda:Script');
expect(script.$parent).to.equal(executionListener);
expect(script.scriptFormat).to.equal('groovy');
expect(script.value).to.equal('foo = bar;');
}));
it('should copy output parameter', inject(function(moddleCopy, moddle) {
// given
var outputParameter = moddle.create('camunda:OutputParameter', {
name: 'foo',
definition: moddle.create('camunda:List', {
items: [
moddle.create('camunda:Value', { value: '${1+1}' }),
moddle.create('camunda:Value', { value: '${1+2}' }),
moddle.create('camunda:Value', { value: '${1+3}' })
]
})
});
var inputOutput = moddle.create('camunda:InputOutput', {
outputParameters: [ outputParameter ]
});
var extensionElements = moddle.create('bpmn:ExtensionElements'),
userTask = moddle.create('bpmn:UserTask');
extensionElements.$parent = userTask;
extensionElements.values = [ inputOutput ];
userTask.extensionElements = extensionElements;
// when
var subProcess = moddleCopy.copyElement(userTask, moddle.create('bpmn:SubProcess'));
// then
extensionElements = subProcess.extensionElements;
inputOutput = extensionElements.values[0];
expect(inputOutput.$type).to.equal('camunda:InputOutput');
expect(inputOutput.$parent).to.equal(extensionElements);
outputParameter = inputOutput.outputParameters[0];
expect(outputParameter.$type).to.equal('camunda:OutputParameter');
expect(outputParameter.$parent).to.equal(inputOutput);
expect(outputParameter.name).to.equal('foo');
var definition = outputParameter.definition;
expect(definition.$type).to.equal('camunda:List');
expect(definition.$parent).to.equal(outputParameter);
var items = definition.items;
expect(items[0].$type).to.equal('camunda:Value');
expect(items[0].$parent).to.equal(definition);
expect(items[0].value).to.equal('${1+1}');
expect(items[1].$type).to.equal('camunda:Value');
expect(items[1].$parent).to.equal(definition);
expect(items[1].value).to.equal('${1+2}');
expect(items[2].$type).to.equal('camunda:Value');
expect(items[2].$parent).to.equal(definition);
expect(items[2].value).to.equal('${1+3}');
}));
});
describe('integration', function() {
describe('camunda:Connector', function() {
it('should copy if parent is message event definition and is child of end event', inject(
function(moddleCopy, moddle) {
// given
var connector = moddle.create('camunda:Connector', {
connectorId: 'foo'
});
var extensionElements = moddle.create('bpmn:ExtensionElements'),
messageEventDefinition = moddle.create('bpmn:MessageEventDefinition'),
messageIntermediateThrowEvent = moddle.create('bpmn:IntermediateThrowEvent');
connector.$parent = extensionElements;
extensionElements.$parent = messageEventDefinition;
extensionElements.values = [ connector ];
messageEventDefinition.$parent = messageIntermediateThrowEvent;
messageEventDefinition.extensionElements = extensionElements;
messageIntermediateThrowEvent.eventDefinitions = [ messageEventDefinition ];
// when
var endEvent =
moddleCopy.copyElement(messageIntermediateThrowEvent, moddle.create('bpmn:EndEvent'));
// then
extensionElements = endEvent.eventDefinitions[0].extensionElements;
expect(extensionElements.values[0].$type).to.equal('camunda:Connector');
expect(extensionElements.values[0].connectorId).to.equal('foo');
}
));
});
describe('camunda:Field', function() {
it('should copy if parent is message event definition and is child of end event', inject(
function(moddleCopy, moddle) {
// given
var field = moddle.create('camunda:Field', {
name: 'foo'
});
var extensionElements = moddle.create('bpmn:ExtensionElements'),
messageEventDefinition = moddle.create('bpmn:MessageEventDefinition'),
messageIntermediateThrowEvent = moddle.create('bpmn:IntermediateThrowEvent');
field.$parent = extensionElements;
extensionElements.$parent = messageEventDefinition;
extensionElements.values = [ field ];
messageEventDefinition.$parent = messageIntermediateThrowEvent;
messageEventDefinition.extensionElements = extensionElements;
messageIntermediateThrowEvent.eventDefinitions = [ messageEventDefinition ];
// when
var endEvent =
moddleCopy.copyElement(messageIntermediateThrowEvent, moddle.create('bpmn:EndEvent'));
// then
extensionElements = endEvent.eventDefinitions[0].extensionElements;
expect(extensionElements.values[0].$type).to.equal('camunda:Field');
expect(extensionElements.values[0].name).to.equal('foo');
}
));
});
describe('camunda:FailedJobRetryTimeCycle', function() {
it('should copy if parent is SignalEventDefinition and is intermediate throwing', inject(
function(moddleCopy, moddle) {
// given
var retryCycle = moddle.create('camunda:FailedJobRetryTimeCycle', {
body: 'foo'
});
var extensionElements = moddle.create('bpmn:ExtensionElements'),
signalEventDefinition = moddle.create('bpmn:SignalEventDefinition'),
signalIntermediateThrowEvent = moddle.create('bpmn:IntermediateThrowEvent');
retryCycle.$parent = extensionElements;
extensionElements.$parent = signalEventDefinition;
extensionElements.values = [ retryCycle ];
signalEventDefinition.$parent = signalIntermediateThrowEvent;
signalEventDefinition.extensionElements = extensionElements;
signalIntermediateThrowEvent.eventDefinitions = [ signalEventDefinition ];
// when
var intermediateThrowEvent = moddleCopy.copyElement(
signalIntermediateThrowEvent,
moddle.create('bpmn:IntermediateThrowEvent')
);
// then
extensionElements = intermediateThrowEvent.eventDefinitions[0].extensionElements;
expect(extensionElements.values[0].$type).to.equal('camunda:FailedJobRetryTimeCycle');
expect(extensionElements.values[0].body).to.equal('foo');
}
));
it('should copy if parent is TimerEventDefinition and is catching', inject(
function(moddleCopy, moddle) {
// given
var retryCycle = moddle.create('camunda:FailedJobRetryTimeCycle', {
body: 'foo'
});
var extensionElements = moddle.create('bpmn:ExtensionElements'),
timerEventDefinition = moddle.create('bpmn:TimerEventDefinition'),
timerStartEvent = moddle.create('bpmn:StartEvent');
retryCycle.$parent = extensionElements;
extensionElements.$parent = timerEventDefinition;
extensionElements.values = [ retryCycle ];
timerEventDefinition.$parent = timerStartEvent;
timerEventDefinition.extensionElements = extensionElements;
timerStartEvent.eventDefinitions = [ timerEventDefinition ];
// when
var intermediateCatchEvent =
moddleCopy.copyElement(timerStartEvent, moddle.create('bpmn:IntermediateCatchEvent'));
// then
extensionElements = intermediateCatchEvent.eventDefinitions[0].extensionElements;
expect(extensionElements.values[0].$type).to.equal('camunda:FailedJobRetryTimeCycle');
expect(extensionElements.values[0].body).to.equal('foo');
}
));
it('should copy if parent is call activity', inject(function(moddleCopy, moddle) {
// given
var retryCycle = moddle.create('camunda:FailedJobRetryTimeCycle', {
body: 'foo'
});
var extensionElements = moddle.create('bpmn:ExtensionElements'),
loopCharacteristics = moddle.create('bpmn:MultiInstanceLoopCharacteristics'),
subProcess = moddle.create('bpmn:SubProcess');
retryCycle.$parent = extensionElements;
extensionElements.$parent = loopCharacteristics;
extensionElements.values = [ retryCycle ];
loopCharacteristics.$parent = subProcess;
loopCharacteristics.extensionElements = extensionElements;
subProcess.loopCharacteristics = loopCharacteristics;
// when
var callActivity = moddleCopy.copyElement(subProcess, moddle.create('bpmn:CallActivity'));
// then
extensionElements = callActivity.loopCharacteristics.extensionElements;
expect(extensionElements.values[0].$type).to.equal('camunda:FailedJobRetryTimeCycle');
expect(extensionElements.values[0].body).to.equal('foo');
}));
});
});
describe('events', function() {
it('should disallow copying properties', inject(function(moddleCopy, eventBus, moddle) {
// given
var task = moddle.create('bpmn:Task', {
name: 'foo'
});
eventBus.on('moddleCopy.canCopyProperties', HIGH_PRIORITY, function(context) {
var sourceElement = context.sourceElement;
if (is(sourceElement, 'bpmn:Task')) {
return false;
}
});
// when
var userTask = moddleCopy.copyElement(task, moddle.create('bpmn:UserTask'));
// then
expect(userTask.name).not.to.exist;
}));
it('should disallow copying property', inject(function(moddleCopy, eventBus, moddle) {
// given
var task = moddle.create('bpmn:Task', {
name: 'foo'
});
eventBus.on('moddleCopy.canCopyProperty', HIGH_PRIORITY, function(context) {
var propertyName = context.propertyName;
if (propertyName === 'name') {
return false;
}
});
// when
var userTask = moddleCopy.copyElement(task, moddle.create('bpmn:UserTask'));
// then
expect(userTask.name).not.to.exist;
}));
it('should disallow setting copied property', inject(function(moddleCopy, eventBus, moddle) {
// given
var task = moddle.create('bpmn:Task', {
name: 'foo'
});
eventBus.on('moddleCopy.canSetCopiedProperty', HIGH_PRIORITY, function(context) {
var property = context.property;
if (property === 'foo') {
return false;
}
});
// when
var userTask = moddleCopy.copyElement(task, moddle.create('bpmn:UserTask'));
// then
expect(userTask.name).not.to.exist;
}));
it('should copy primitive property', inject(function(moddleCopy, eventBus, moddle) {
// given
var task = moddle.create('bpmn:Task', {
name: 'foo'
});
eventBus.on('moddleCopy.canCopyProperty', HIGH_PRIORITY, function(context) {
var propertyName = context.propertyName;
if (propertyName === 'name') {
return 'bar';
}
});
// when
var userTask = moddleCopy.copyElement(task, moddle.create('bpmn:UserTask'));
// then
expect(userTask.name).to.equal('bar');
}));
describe('copy model element property', function() {
it('should copy and set parent', inject(function(moddleCopy, eventBus, moddle) {
// given
var startEvent = moddle.create('bpmn:StartEvent'),
messageEventDefinition = moddle.create('bpmn:MessageEventDefinition');
messageEventDefinition.$parent = startEvent;
startEvent.eventDefinitions = [ messageEventDefinition ];
eventBus.on('moddleCopy.canCopyProperty', HIGH_PRIORITY, function(context) {
var property = context.property;
if (is(property, 'bpmn:MessageEventDefinition')) {
return moddle.create('bpmn:MessageEventDefinition');
}
});
// when
var endEvent = moddleCopy.copyElement(startEvent, moddle.create('bpmn:EndEvent'));
// then
expect(endEvent.eventDefinitions).to.have.length(1);
expect(endEvent.eventDefinitions[0]).not.to.equal(messageEventDefinition);
expect(endEvent.eventDefinitions[0].$type).to.equal('bpmn:MessageEventDefinition');
}));
});
it('should copy and NOT set parent', inject(function(canvas, moddleCopy, eventBus, moddle) {
// given
var definitions = getDefinitions(canvas.getRootElement()),
categoryValue = moddle.create('bpmn:CategoryValue'),
category = moddle.create('bpmn:Category'),
group = moddle.create('bpmn:Group'),
newCategoryValue,
newCategory,
newGroup;
categoryValue.$parent = category;
category.$parent = definitions;
category.categoryValue = [ categoryValue ];
definitions.rootElements.push(category);
group.categoryValueRef = categoryValue;
eventBus.on('moddleCopy.canCopyProperty', HIGH_PRIORITY, function(context) {
var propertyName = context.propertyName;
if (propertyName !== 'categoryValueRef') {
return;
}
newCategoryValue = moddle.create('bpmn:CategoryValue');
newCategory = moddle.create('bpmn:Category');
newCategoryValue.$parent = newCategory;
newCategory.$parent = definitions;
newCategory.categoryValue = [ newCategoryValue ];
definitions.rootElements.push(newCategory);
return newCategoryValue;
});
// when
newGroup = moddleCopy.copyElement(group, moddle.create('bpmn:Group'));
// then
expect(newGroup.categoryValueRef).to.exist;
expect(newGroup.categoryValueRef).not.to.equal(categoryValue);
expect(newGroup.categoryValueRef.$parent).to.equal(newCategory);
}));
});
});
// helpers //////////
function expectNoAttrs(element) {
expect(element.$attrs).to.be.empty;
}
function getDefinitions(rootElement) {
var businessObject = getBusinessObject(rootElement);
return businessObject.$parent;
}

View File

@ -1,107 +1,108 @@
<?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:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.2.1">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:laneSet />
<bpmn:subProcess id="SubProcess_1kd6ist">
<bpmn:subProcess id="SubProcess_0gev7mx">
<bpmn:subProcess id="SubProcess_1">
<bpmn:subProcess id="SubProcess_2">
<bpmn:multiInstanceLoopCharacteristics isSequential="true" />
<bpmn:startEvent id="StartEvent_1" name="hello">
<bpmn:outgoing>SequenceFlow_1rtr33r</bpmn:outgoing>
<bpmn:outgoing>SequenceFlow_1</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:endEvent id="EndEvent_0yejuvr" name="world!">
<bpmn:incoming>SequenceFlow_0y69l8f</bpmn:incoming>
<bpmn:endEvent id="EndEvent_1" name="world!">
<bpmn:incoming>SequenceFlow_2</bpmn:incoming>
</bpmn:endEvent>
<bpmn:task id="Task_1fo63a7" name="wait for it.." default="SequenceFlow_0y69l8f">
<bpmn:incoming>SequenceFlow_1rtr33r</bpmn:incoming>
<bpmn:outgoing>SequenceFlow_0y69l8f</bpmn:outgoing>
<bpmn:outgoing>SequenceFlow_07vo2r8</bpmn:outgoing>
<bpmn:task id="Task_1" name="wait for it.." default="SequenceFlow_2">
<bpmn:incoming>SequenceFlow_1</bpmn:incoming>
<bpmn:outgoing>SequenceFlow_2</bpmn:outgoing>
<bpmn:outgoing>SequenceFlow_3</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="SequenceFlow_0y69l8f" name="" sourceRef="Task_1fo63a7" targetRef="EndEvent_0yejuvr" />
<bpmn:sequenceFlow id="SequenceFlow_1rtr33r" name="blah" sourceRef="StartEvent_1" targetRef="Task_1fo63a7" />
<bpmn:boundaryEvent id="BoundaryEvent_1c94bi9" attachedToRef="Task_1fo63a7">
<bpmn:sequenceFlow id="SequenceFlow_2" name="" sourceRef="Task_1" targetRef="EndEvent_1" />
<bpmn:sequenceFlow id="SequenceFlow_1" name="blah" sourceRef="StartEvent_1" targetRef="Task_1" />
<bpmn:boundaryEvent id="BoundaryEvent_2" attachedToRef="Task_1">
<bpmn:timerEventDefinition />
</bpmn:boundaryEvent>
<bpmn:boundaryEvent id="BoundaryEvent_1404oxd" attachedToRef="Task_1fo63a7">
<bpmn:boundaryEvent id="BoundaryEvent_1" attachedToRef="Task_1">
<bpmn:messageEventDefinition />
</bpmn:boundaryEvent>
<bpmn:intermediateThrowEvent id="IntermediateThrowEvent_09kpyzx">
<bpmn:incoming>SequenceFlow_07vo2r8</bpmn:incoming>
<bpmn:intermediateThrowEvent id="IntermediateThrowEvent_1">
<bpmn:incoming>SequenceFlow_3</bpmn:incoming>
</bpmn:intermediateThrowEvent>
<bpmn:sequenceFlow id="SequenceFlow_07vo2r8" sourceRef="Task_1fo63a7" targetRef="IntermediateThrowEvent_09kpyzx">
<bpmn:sequenceFlow id="SequenceFlow_3" sourceRef="Task_1" targetRef="IntermediateThrowEvent_1">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">foo</bpmn:conditionExpression>
</bpmn:sequenceFlow>
</bpmn:subProcess>
<bpmn:textAnnotation id="TextAnnotation_0h1hhgg"> <bpmn:text>foo</bpmn:text>
</bpmn:textAnnotation>
<bpmn:association id="Association_1f53xbo" sourceRef="SubProcess_0gev7mx" targetRef="TextAnnotation_0h1hhgg" />
<bpmn:textAnnotation id="TextAnnotation_1">
<bpmn:text>foo</bpmn:text>
</bpmn:textAnnotation>
<bpmn:association id="Association_1f53xbo" sourceRef="SubProcess_2" targetRef="TextAnnotation_1" />
</bpmn:subProcess>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="SubProcess_1kd6ist_di" bpmnElement="SubProcess_1kd6ist" isExpanded="true">
<dc:Bounds x="88" y="34" width="613" height="372" />
<bpmndi:BPMNShape id="SubProcess_1kd6ist_di" bpmnElement="SubProcess_1" isExpanded="true">
<dc:Bounds x="156" y="34" width="613" height="372" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="SubProcess_0gev7mx_di" bpmnElement="SubProcess_0gev7mx" isExpanded="true">
<dc:Bounds x="147" y="118" width="461" height="259" />
<bpmndi:BPMNShape id="SubProcess_0gev7mx_di" bpmnElement="SubProcess_2" isExpanded="true">
<dc:Bounds x="215" y="118" width="461" height="259" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="167" y="198" width="36" height="36" />
<dc:Bounds x="235" y="198" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="140" y="149" width="90" height="20" />
<dc:Bounds x="241" y="149" width="24" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="EndEvent_0yejuvr_di" bpmnElement="EndEvent_0yejuvr">
<dc:Bounds x="543" y="198" width="36" height="36" />
<bpmndi:BPMNShape id="EndEvent_0yejuvr_di" bpmnElement="EndEvent_1">
<dc:Bounds x="611" y="198" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="516" y="272" width="90" height="20" />
<dc:Bounds x="615" y="272" width="29" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_1fo63a7_di" bpmnElement="Task_1fo63a7">
<dc:Bounds x="293" y="176" width="100" height="80" />
<bpmndi:BPMNShape id="Task_1fo63a7_di" bpmnElement="Task_1">
<dc:Bounds x="361" y="176" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_0y69l8f_di" bpmnElement="SequenceFlow_0y69l8f">
<di:waypoint xsi:type="dc:Point" x="393" y="216" />
<di:waypoint xsi:type="dc:Point" x="543" y="216" />
<bpmndi:BPMNEdge id="SequenceFlow_0y69l8f_di" bpmnElement="SequenceFlow_2">
<di:waypoint x="461" y="216" />
<di:waypoint x="611" y="216" />
<bpmndi:BPMNLabel>
<dc:Bounds x="421" y="166" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="SequenceFlow_1rtr33r_di" bpmnElement="SequenceFlow_1rtr33r">
<di:waypoint xsi:type="dc:Point" x="203" y="216" />
<di:waypoint xsi:type="dc:Point" x="293" y="216" />
<bpmndi:BPMNEdge id="SequenceFlow_1rtr33r_di" bpmnElement="SequenceFlow_1">
<di:waypoint x="271" y="216" />
<di:waypoint x="361" y="216" />
<bpmndi:BPMNLabel>
<dc:Bounds x="202" y="321" width="90" height="20" />
<dc:Bounds x="305" y="321" width="21" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="BoundaryEvent_1c94bi9_di" bpmnElement="BoundaryEvent_1c94bi9">
<dc:Bounds x="375" y="238" width="36" height="36" />
<bpmndi:BPMNShape id="BoundaryEvent_1c94bi9_di" bpmnElement="BoundaryEvent_2">
<dc:Bounds x="443" y="238" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="348" y="274" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="TextAnnotation_0h1hhgg_di" bpmnElement="TextAnnotation_0h1hhgg">
<dc:Bounds x="564" y="58" width="100" height="30" />
<bpmndi:BPMNShape id="TextAnnotation_0h1hhgg_di" bpmnElement="TextAnnotation_1">
<dc:Bounds x="632" y="58" width="100" height="30" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Association_1f53xbo_di" bpmnElement="Association_1f53xbo">
<di:waypoint xsi:type="dc:Point" x="595" y="118" />
<di:waypoint xsi:type="dc:Point" x="581" y="88" />
<di:waypoint x="663" y="118" />
<di:waypoint x="649" y="88" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="BoundaryEvent_1404oxd_di" bpmnElement="BoundaryEvent_1404oxd">
<dc:Bounds x="275" y="238" width="36" height="36" />
<bpmndi:BPMNShape id="BoundaryEvent_1404oxd_di" bpmnElement="BoundaryEvent_1">
<dc:Bounds x="343" y="238" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="248" y="274" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="IntermediateThrowEvent_09kpyzx_di" bpmnElement="IntermediateThrowEvent_09kpyzx">
<dc:Bounds x="458" y="287" width="36" height="36" />
<bpmndi:BPMNShape id="IntermediateThrowEvent_09kpyzx_di" bpmnElement="IntermediateThrowEvent_1">
<dc:Bounds x="526" y="287" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="431" y="323" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_07vo2r8_di" bpmnElement="SequenceFlow_07vo2r8">
<di:waypoint xsi:type="dc:Point" x="343" y="256" />
<di:waypoint xsi:type="dc:Point" x="343" y="305" />
<di:waypoint xsi:type="dc:Point" x="458" y="305" />
<bpmndi:BPMNEdge id="SequenceFlow_07vo2r8_di" bpmnElement="SequenceFlow_3">
<di:waypoint x="411" y="256" />
<di:waypoint x="411" y="305" />
<di:waypoint x="526" y="305" />
<bpmndi:BPMNLabel>
<dc:Bounds x="381" y="250.5" width="90" height="20" />
</bpmndi:BPMNLabel>

View File

@ -0,0 +1,104 @@
<?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:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.2.1">
<bpmn:collaboration id="Collaboration_1">
<bpmn:participant id="Participant_1" processRef="Process_1" />
<bpmn:participant id="Participant_2" processRef="Process_08nr0a7" />
<bpmn:messageFlow id="MessageFlow_1" sourceRef="IntermediateThrowEvent_1" targetRef="Task_2" />
</bpmn:collaboration>
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:laneSet>
<bpmn:lane id="Lane_2">
<bpmn:flowNodeRef>Task_2</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_1">
<bpmn:flowNodeRef>Task_1</bpmn:flowNodeRef>
<bpmn:childLaneSet>
<bpmn:lane id="Lane_4" />
<bpmn:lane id="Lane_3">
<bpmn:flowNodeRef>Task_1</bpmn:flowNodeRef>
</bpmn:lane>
</bpmn:childLaneSet>
</bpmn:lane>
</bpmn:laneSet>
<bpmn:task id="Task_1" />
<bpmn:task id="Task_2" />
</bpmn:process>
<bpmn:process id="Process_08nr0a7" isExecutable="false">
<bpmn:laneSet>
<bpmn:lane id="Lane_7">
<bpmn:flowNodeRef>EndEvent_1</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_6">
<bpmn:flowNodeRef>IntermediateThrowEvent_1</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_5">
<bpmn:flowNodeRef>StartEvent_1</bpmn:flowNodeRef>
</bpmn:lane>
</bpmn:laneSet>
<bpmn:intermediateThrowEvent id="IntermediateThrowEvent_1" />
<bpmn:endEvent id="EndEvent_1" />
<bpmn:startEvent id="StartEvent_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
<bpmndi:BPMNShape id="Participant_0pgdgt4_di" bpmnElement="Participant_1" isHorizontal="true">
<dc:Bounds x="156" y="96" width="360" height="308" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_1id96b4_di" bpmnElement="Participant_2" isHorizontal="true">
<dc:Bounds x="156" y="440" width="360" height="246" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1gzt96j_di" bpmnElement="Lane_1" isHorizontal="true">
<dc:Bounds x="186" y="96" width="330" height="183" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1kulv9k_di" bpmnElement="Lane_2" isHorizontal="true">
<dc:Bounds x="186" y="279" width="330" height="125" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_0aws6ii_di" bpmnElement="Lane_5" isHorizontal="true">
<dc:Bounds x="186" y="440" width="330" height="83" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1sd1zl3_di" bpmnElement="Lane_6" isHorizontal="true">
<dc:Bounds x="186" y="523" width="330" height="83" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_16ah5rn_di" bpmnElement="Lane_7" isHorizontal="true">
<dc:Bounds x="186" y="606" width="330" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="StartEvent_07r1iyh_di" bpmnElement="StartEvent_1">
<dc:Bounds x="204" y="462" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="154" y="491" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="IntermediateThrowEvent_0audt6r_di" bpmnElement="IntermediateThrowEvent_1">
<dc:Bounds x="274" y="550" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="338" y="578" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="EndEvent_1u50ypf_di" bpmnElement="EndEvent_1">
<dc:Bounds x="454" y="630" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="514" y="672" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_1pamrp2_di" bpmnElement="Task_1">
<dc:Bounds x="242" y="116" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_0n0k2nj_di" bpmnElement="Task_2">
<dc:Bounds x="242" y="302" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="MessageFlow_150lriv_di" bpmnElement="MessageFlow_1">
<di:waypoint x="292" y="550" />
<di:waypoint x="292" y="382" />
<bpmndi:BPMNLabel>
<dc:Bounds x="338" y="453.5" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Lane_1yo0kyz_di" bpmnElement="Lane_3" isHorizontal="true">
<dc:Bounds x="216" y="96" width="300" height="121" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_022an7b_di" bpmnElement="Lane_4" isHorizontal="true">
<dc:Bounds x="216" y="217" width="300" height="62" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -1,73 +1,73 @@
<?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:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:collaboration id="Collaboration_0whmvae">
<bpmn:participant id="Participant_0uu1rvj" processRef="Process_1" />
<bpmn:participant id="Participant_145muai" name="colloopsed" />
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.2.1">
<bpmn:collaboration id="Collaboration_1">
<bpmn:participant id="Participant_1" processRef="Process_1" />
<bpmn:participant id="Participant_2" name="collapsed" />
</bpmn:collaboration>
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:laneSet>
<bpmn:lane id="Lane_1gl63sa">
<bpmn:flowNodeRef>StartEvent_0o6vk5g</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Task_13xbgyg</bpmn:flowNodeRef>
<bpmn:flowNodeRef>EndEvent_1nef447</bpmn:flowNodeRef>
<bpmn:lane id="Lane_2" />
<bpmn:lane id="Lane_1">
<bpmn:flowNodeRef>StartEvent_1</bpmn:flowNodeRef>
<bpmn:flowNodeRef>EndEvent_1</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Task_1</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_13h648l" />
</bpmn:laneSet>
<bpmn:startEvent id="StartEvent_0o6vk5g">
<bpmn:outgoing>SequenceFlow_0v3q8mo</bpmn:outgoing>
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>SequenceFlow_1</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="Task_13xbgyg">
<bpmn:incoming>SequenceFlow_0v3q8mo</bpmn:incoming>
<bpmn:outgoing>SequenceFlow_1yvonen</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="SequenceFlow_0v3q8mo" sourceRef="StartEvent_0o6vk5g" targetRef="Task_13xbgyg" />
<bpmn:endEvent id="EndEvent_1nef447">
<bpmn:incoming>SequenceFlow_1yvonen</bpmn:incoming>
<bpmn:endEvent id="EndEvent_1">
<bpmn:incoming>SequenceFlow_2</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="SequenceFlow_1yvonen" sourceRef="Task_13xbgyg" targetRef="EndEvent_1nef447" />
<bpmn:task id="Task_1">
<bpmn:incoming>SequenceFlow_1</bpmn:incoming>
<bpmn:outgoing>SequenceFlow_2</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="SequenceFlow_2" sourceRef="Task_1" targetRef="EndEvent_1" />
<bpmn:sequenceFlow id="SequenceFlow_1" sourceRef="StartEvent_1" targetRef="Task_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_0whmvae">
<bpmndi:BPMNShape id="Participant_0uu1rvj_di" bpmnElement="Participant_0uu1rvj">
<dc:Bounds x="78" y="28" width="600" height="250" />
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
<bpmndi:BPMNShape id="Participant_0uu1rvj_di" bpmnElement="Participant_1" isHorizontal="true">
<dc:Bounds x="169" y="86" width="433" height="245" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1gl63sa_di" bpmnElement="Lane_1gl63sa">
<dc:Bounds x="108" y="28" width="570" height="125" />
<bpmndi:BPMNShape id="Lane_1gl63sa_di" bpmnElement="Lane_1" isHorizontal="true">
<dc:Bounds x="199" y="86" width="403" height="120" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_13h648l_di" bpmnElement="Lane_13h648l">
<dc:Bounds x="108" y="153" width="570" height="125" />
<bpmndi:BPMNShape id="Lane_13h648l_di" bpmnElement="Lane_2" isHorizontal="true">
<dc:Bounds x="199" y="206" width="403" height="125" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="StartEvent_0o6vk5g_di" bpmnElement="StartEvent_0o6vk5g">
<dc:Bounds x="141" y="75" width="36" height="36" />
<bpmndi:BPMNShape id="StartEvent_0o6vk5g_di" bpmnElement="StartEvent_1">
<dc:Bounds x="219" y="128" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="114" y="111" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_13xbgyg_di" bpmnElement="Task_13xbgyg">
<dc:Bounds x="285" y="53" width="100" height="80" />
<bpmndi:BPMNShape id="Task_13xbgyg_di" bpmnElement="Task_1">
<dc:Bounds x="351" y="106" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_0v3q8mo_di" bpmnElement="SequenceFlow_0v3q8mo">
<di:waypoint xsi:type="dc:Point" x="177" y="93" />
<di:waypoint xsi:type="dc:Point" x="285" y="93" />
<bpmndi:BPMNEdge id="SequenceFlow_0v3q8mo_di" bpmnElement="SequenceFlow_1">
<di:waypoint x="255" y="146" />
<di:waypoint x="351" y="146" />
<bpmndi:BPMNLabel>
<dc:Bounds x="186" y="83" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="EndEvent_1nef447_di" bpmnElement="EndEvent_1nef447">
<dc:Bounds x="468" y="75" width="36" height="36" />
<bpmndi:BPMNShape id="EndEvent_1nef447_di" bpmnElement="EndEvent_1">
<dc:Bounds x="546" y="128" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="441" y="111" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_1yvonen_di" bpmnElement="SequenceFlow_1yvonen">
<di:waypoint xsi:type="dc:Point" x="385" y="93" />
<di:waypoint xsi:type="dc:Point" x="468" y="93" />
<bpmndi:BPMNEdge id="SequenceFlow_1yvonen_di" bpmnElement="SequenceFlow_2">
<di:waypoint x="451" y="146" />
<di:waypoint x="546" y="146" />
<bpmndi:BPMNLabel>
<dc:Bounds x="381.5" y="83" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Participant_145muai_di" bpmnElement="Participant_145muai">
<dc:Bounds x="78" y="330" width="600" height="250" />
<bpmndi:BPMNShape id="Participant_145muai_di" bpmnElement="Participant_2" isHorizontal="true">
<dc:Bounds x="169" y="350" width="433" height="60" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>

View File

@ -0,0 +1,141 @@
<?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:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.1.2">
<bpmn:collaboration id="Collaboration_1">
<bpmn:participant id="Participant_1" name="Participant" processRef="Process_1" />
</bpmn:collaboration>
<bpmn:process id="Process_1" name="Process" isExecutable="false" camunda:versionTag="1.0">
<bpmn:dataStoreReference id="DataStoreReference_1" />
<bpmn:dataStoreReference id="DataStoreReference_2" />
<bpmn:dataObjectReference id="DataObjectReference_2" dataObjectRef="DataObject_1l0h55k" />
<bpmn:dataObject id="DataObject_1l0h55k" />
<bpmn:dataObjectReference id="DataObjectReference_1" dataObjectRef="DataObject_1iu55n1" />
<bpmn:dataObject id="DataObject_1iu55n1" />
<bpmn:subProcess id="SubProcess_1">
<bpmn:userTask id="Task_1" camunda:asyncBefore="true" camunda:jobPriority="100">
<bpmn:documentation>hello world</bpmn:documentation>
<bpmn:extensionElements>
<camunda:inputOutput>
<camunda:inputParameter name="Input_1">foo</camunda:inputParameter>
<camunda:outputParameter name="Output_1">bar</camunda:outputParameter>
</camunda:inputOutput>
<camunda:properties>
<camunda:property name="bar" value="foo" />
</camunda:properties>
<camunda:executionListener class="reallyClassy" event="start" />
<camunda:failedJobRetryTimeCycle>10</camunda:failedJobRetryTimeCycle>
<camunda:taskListener class="foobar" event="create" />
</bpmn:extensionElements>
<bpmn:incoming>SequenceFlow_1</bpmn:incoming>
<bpmn:outgoing>SequenceFlow_2</bpmn:outgoing>
<bpmn:property id="Property_0j0o7pl" name="__targetRef_placeholder" />
<bpmn:dataInputAssociation id="DataInputAssociation_4">
<bpmn:sourceRef>DataStoreReference_1</bpmn:sourceRef>
<bpmn:targetRef>Property_0j0o7pl</bpmn:targetRef>
</bpmn:dataInputAssociation>
<bpmn:dataInputAssociation id="DataInputAssociation_2">
<bpmn:sourceRef>DataObjectReference_1</bpmn:sourceRef>
<bpmn:targetRef>Property_0j0o7pl</bpmn:targetRef>
</bpmn:dataInputAssociation>
<bpmn:dataOutputAssociation id="DataOutputAssociation_5">
<bpmn:targetRef>DataStoreReference_2</bpmn:targetRef>
</bpmn:dataOutputAssociation>
<bpmn:dataOutputAssociation id="DataOutputAssociation_3">
<bpmn:targetRef>DataObjectReference_2</bpmn:targetRef>
</bpmn:dataOutputAssociation>
</bpmn:userTask>
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>SequenceFlow_1</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="SequenceFlow_1" sourceRef="StartEvent_1" targetRef="Task_1" />
<bpmn:task id="Task_2">
<bpmn:incoming>SequenceFlow_2</bpmn:incoming>
</bpmn:task>
<bpmn:sequenceFlow id="SequenceFlow_2" sourceRef="Task_1" targetRef="Task_2" />
</bpmn:subProcess>
<bpmn:textAnnotation id="TextAnnotation_1" />
<bpmn:association id="Association_1" sourceRef="Task_1" targetRef="TextAnnotation_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
<bpmndi:BPMNShape id="UserTask_033cl9l_di" bpmnElement="Task_1">
<dc:Bounds x="261" y="159.5" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="StartEvent_1a4dsh8_di" bpmnElement="StartEvent_1">
<dc:Bounds x="168" y="181.5" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="186" y="217.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_1e74z8m_di" bpmnElement="SequenceFlow_1">
<di:waypoint x="204" y="199.5" />
<di:waypoint x="261" y="199.5" />
<bpmndi:BPMNLabel>
<dc:Bounds x="233" y="174.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Task_042z61e_di" bpmnElement="Task_2">
<dc:Bounds x="441" y="159.5" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_1tdxph9_di" bpmnElement="SequenceFlow_2">
<di:waypoint x="361" y="199.5" />
<di:waypoint x="441" y="199.5" />
<bpmndi:BPMNLabel>
<dc:Bounds x="401" y="184.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Participant_0x9lnke_di" bpmnElement="Participant_1">
<dc:Bounds x="0" y="0" width="632" height="417" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="TextAnnotation_1cghzwc_di" bpmnElement="TextAnnotation_1">
<dc:Bounds x="50" y="30.5" width="100" height="30" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_1elrt45_di" bpmnElement="DataStoreReference_1">
<dc:Bounds x="211" y="347.5" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="236" y="397.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_1j8ymac_di" bpmnElement="DataStoreReference_2">
<dc:Bounds x="345" y="347.5" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="370" y="397.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataObjectReference_1js94kb_di" bpmnElement="DataObjectReference_2">
<dc:Bounds x="352" y="20.5" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="370" y="70.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataObjectReference_0hkbt95_di" bpmnElement="DataObjectReference_1">
<dc:Bounds x="218" y="20.5" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="236" y="70.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="SubProcess_04tmqcs_di" bpmnElement="SubProcess_1" isExpanded="true">
<dc:Bounds x="153" y="104.5" width="459" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Association_0edc446_di" bpmnElement="Association_1">
<di:waypoint x="265" y="165.5" />
<di:waypoint x="121" y="60.5" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DataInputAssociation_0xdwl7n_di" bpmnElement="DataInputAssociation_4">
<di:waypoint x="244" y="347.5" />
<di:waypoint x="276" y="239.5" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DataOutputAssociation_1wf2bxo_di" bpmnElement="DataOutputAssociation_5">
<di:waypoint x="323" y="239.5" />
<di:waypoint x="354" y="347.5" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DataOutputAssociation_0hr21ne_di" bpmnElement="DataOutputAssociation_3">
<di:waypoint x="329" y="159.5" />
<di:waypoint x="368" y="70.5" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DataInputAssociation_188je0k_di" bpmnElement="DataInputAssociation_2">
<di:waypoint x="245" y="70.5" />
<di:waypoint x="275" y="159.5" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -1,60 +1,60 @@
<?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:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="0.7.0-dev">
<bpmn:collaboration id="Collaboration_09rf7ug">
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.1.2">
<bpmn:collaboration id="Collaboration_1">
<bpmn:participant id="Participant_Output" processRef="Process_Output" />
<bpmn:participant id="Participant_Input" processRef="Process_Input" />
</bpmn:collaboration>
<bpmn:process id="Process_Output" isExecutable="false">
<bpmn:task id="Task_17elucr">
<bpmn:dataOutputAssociation id="DataOutputAssociation_0bncpb8">
<bpmn:targetRef>DataStoreReference_1muhdww</bpmn:targetRef>
<bpmn:task id="Task_1">
<bpmn:dataOutputAssociation id="DataOutputAssociation_1">
<bpmn:targetRef>DataStoreReference_1</bpmn:targetRef>
</bpmn:dataOutputAssociation>
</bpmn:task>
<bpmn:dataStoreReference id="DataStoreReference_1muhdww" />
<bpmn:dataStoreReference id="DataStoreReference_1" />
</bpmn:process>
<bpmn:process id="Process_Input" isExecutable="false">
<bpmn:dataStoreReference id="DataStoreReference_0q26vzn" />
<bpmn:task id="Task_10pzi8y">
<bpmn:dataStoreReference id="DataStoreReference_2" />
<bpmn:task id="Task_2">
<bpmn:property id="Property_0l7g57i" name="__targetRef_placeholder" />
<bpmn:dataInputAssociation id="DataInputAssociation_1sf5ecg">
<bpmn:sourceRef>DataStoreReference_0q26vzn</bpmn:sourceRef>
<bpmn:dataInputAssociation id="DataInputAssociation_1">
<bpmn:sourceRef>DataStoreReference_2</bpmn:sourceRef>
<bpmn:targetRef>Property_0l7g57i</bpmn:targetRef>
</bpmn:dataInputAssociation>
</bpmn:task>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_09rf7ug">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
<bpmndi:BPMNShape id="Participant_166hvof_di" bpmnElement="Participant_Output">
<dc:Bounds x="302" y="60" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_17elucr_di" bpmnElement="Task_17elucr">
<bpmndi:BPMNShape id="Task_17elucr_di" bpmnElement="Task_1">
<dc:Bounds x="416" y="100" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_1muhdww_di" bpmnElement="DataStoreReference_1muhdww">
<bpmndi:BPMNShape id="DataStoreReference_1muhdww_di" bpmnElement="DataStoreReference_1">
<dc:Bounds x="746" y="216" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="726" y="266" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="DataOutputAssociation_0bncpb8_di" bpmnElement="DataOutputAssociation_0bncpb8">
<di:waypoint xsi:type="dc:Point" x="516" y="157" />
<di:waypoint xsi:type="dc:Point" x="746" y="233" />
<bpmndi:BPMNEdge id="DataOutputAssociation_0bncpb8_di" bpmnElement="DataOutputAssociation_1">
<di:waypoint x="516" y="157" />
<di:waypoint x="746" y="233" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Participant_1duzt5k_di" bpmnElement="Participant_Input">
<dc:Bounds x="302" y="354" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_0q26vzn_di" bpmnElement="DataStoreReference_0q26vzn">
<bpmndi:BPMNShape id="DataStoreReference_0q26vzn_di" bpmnElement="DataStoreReference_2">
<dc:Bounds x="758" y="491" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="738" y="541" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_10pzi8y_di" bpmnElement="Task_10pzi8y">
<bpmndi:BPMNShape id="Task_10pzi8y_di" bpmnElement="Task_2">
<dc:Bounds x="426" y="375" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="DataInputAssociation_1sf5ecg_di" bpmnElement="DataInputAssociation_1sf5ecg">
<di:waypoint xsi:type="dc:Point" x="758" y="508" />
<di:waypoint xsi:type="dc:Point" x="526" y="431" />
<bpmndi:BPMNEdge id="DataInputAssociation_1sf5ecg_di" bpmnElement="DataInputAssociation_1">
<di:waypoint x="758" y="508" />
<di:waypoint x="526" y="431" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>

View File

@ -1,49 +1,49 @@
<?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:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.2.0-dev">
<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" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.1.2">
<bpmn:category id="Category">
<bpmn:categoryValue id="CategoryValue" value="Group" />
</bpmn:category>
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:subProcess id="Sub_non_interrupt" />
<bpmn:subProcess id="Sub_event_subprocess" triggeredByEvent="true" />
<bpmn:boundaryEvent id="BoundaryEvent_1ttq5yj" cancelActivity="false" attachedToRef="Sub_non_interrupt">
<bpmn:subProcess id="SubProcess_NonInterrupting" />
<bpmn:subProcess id="SubProcess_Event" triggeredByEvent="true" />
<bpmn:boundaryEvent id="BoundaryEvent_1" cancelActivity="false" attachedToRef="SubProcess_NonInterrupting">
<bpmn:messageEventDefinition />
</bpmn:boundaryEvent>
<bpmn:subProcess id="Sub_interrupt" />
<bpmn:boundaryEvent id="BoundaryEvent_0w2tz4k" attachedToRef="Sub_interrupt">
<bpmn:subProcess id="SubProcess_Interrupting" />
<bpmn:boundaryEvent id="BoundaryEvent_2" attachedToRef="SubProcess_Interrupting">
<bpmn:timerEventDefinition />
</bpmn:boundaryEvent>
<bpmn:transaction id="Sub_transaction" />
<bpmn:transaction id="SubProcess_Transaction" />
<bpmn:group id="Group" categoryValueRef="CategoryValue" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="SubProcess_1pvi3qq_di" bpmnElement="Sub_non_interrupt" isExpanded="true">
<dc:Bounds x="111" y="40" width="140" height="120" />
<bpmndi:BPMNShape id="SubProcess_1pvi3qq_di" bpmnElement="SubProcess_NonInterrupting" isExpanded="true">
<dc:Bounds x="100" y="100" width="140" height="120" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="SubProcess_0k446tj_di" bpmnElement="Sub_event_subprocess" isExpanded="true">
<dc:Bounds x="329" y="40" width="140" height="120" />
<bpmndi:BPMNShape id="SubProcess_0k446tj_di" bpmnElement="SubProcess_Event" isExpanded="true">
<dc:Bounds x="300" y="100" width="140" height="120" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BoundaryEvent_1a6busd_di" bpmnElement="BoundaryEvent_1ttq5yj">
<dc:Bounds x="119" y="142" width="36" height="36" />
<bpmndi:BPMNShape id="BoundaryEvent_1a6busd_di" bpmnElement="BoundaryEvent_1">
<dc:Bounds x="152" y="202" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="92" y="178" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="SubProcess_0pj87vw_di" bpmnElement="Sub_interrupt" isExpanded="true">
<dc:Bounds x="111" y="207" width="140" height="120" />
<bpmndi:BPMNShape id="SubProcess_0pj87vw_di" bpmnElement="SubProcess_Interrupting" isExpanded="true">
<dc:Bounds x="100" y="300" width="140" height="120" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BoundaryEvent_1aqt6gt_di" bpmnElement="BoundaryEvent_0w2tz4k">
<dc:Bounds x="124" y="309" width="36" height="36" />
<bpmndi:BPMNShape id="BoundaryEvent_1aqt6gt_di" bpmnElement="BoundaryEvent_2">
<dc:Bounds x="152" y="402" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="97" y="345" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Transaction_1so7kki_di" bpmnElement="Sub_transaction" isExpanded="true">
<dc:Bounds x="329" y="207" width="140" height="120" />
<bpmndi:BPMNShape id="Transaction_1so7kki_di" bpmnElement="SubProcess_Transaction" isExpanded="true">
<dc:Bounds x="300" y="300" width="140" height="120" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Group_di" bpmnElement="Group">
<dc:Bounds x="529" y="40" width="140" height="120" />
<dc:Bounds x="500" y="100" width="140" height="120" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>

View File

@ -7,16 +7,17 @@ import {
import { forEach } from 'min-dash';
import copyPasteModule from 'lib/features/copy-paste';
import coreModule from 'lib/core';
import editorActionsModule from 'lib/features/editor-actions';
import searchModule from 'lib/features/search';
import globalConnectModule from 'diagram-js/lib/features/global-connect';
import spaceToolModule from 'diagram-js/lib/features/space-tool';
import lassoToolModule from 'diagram-js/lib/features/lasso-tool';
import handToolModule from 'diagram-js/lib/features/hand-tool';
import keyboardModule from 'lib/features/keyboard';
import modelingModule from 'lib/features/modeling';
import labelEditingModule from 'lib/features/label-editing';
import lassoToolModule from 'diagram-js/lib/features/lasso-tool';
import modelingModule from 'lib/features/modeling';
import searchModule from 'lib/features/search';
import spaceToolModule from 'diagram-js/lib/features/space-tool';
import {
createKeyEvent
@ -28,16 +29,17 @@ describe('features/keyboard', function() {
var diagramXML = require('../../../fixtures/bpmn/simple.bpmn');
var testModules = [
copyPasteModule,
coreModule,
editorActionsModule,
keyboardModule,
modelingModule,
globalConnectModule,
spaceToolModule,
lassoToolModule,
handToolModule,
keyboardModule,
labelEditingModule,
lassoToolModule,
modelingModule,
searchModule,
labelEditingModule
spaceToolModule
];
beforeEach(bootstrapViewer(diagramXML, { modules: testModules }));
@ -46,10 +48,13 @@ describe('features/keyboard', function() {
describe('bpmn keyboard bindings', function() {
it('should include triggers inside editorActions', inject(function(editorActions) {
// given
var expectedActions = [
'undo',
'redo',
'copy',
'paste',
'zoom',
'removeSelection',
'selectElements',

View File

@ -0,0 +1,25 @@
<?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" id="Definitions_1bizrl3" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.1.2">
<bpmn:collaboration id="Collaboration_1">
<bpmn:participant id="Participant_1" processRef="Process_1" />
</bpmn:collaboration>
<bpmn:process id="Process_1" isExecutable="true">
<bpmn:laneSet id="LaneSet_04h5t15">
<bpmn:lane id="Lane_2" />
<bpmn:lane id="Lane_1" />
</bpmn:laneSet>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
<bpmndi:BPMNShape id="Participant_1amm1zc_di" bpmnElement="Participant_1" isHorizontal="true">
<dc:Bounds x="100" y="100" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_0govxlt_di" bpmnElement="Lane_1" isHorizontal="true">
<dc:Bounds x="130" y="100" width="570" height="125" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_0f7d1ts_di" bpmnElement="Lane_2" isHorizontal="true">
<dc:Bounds x="130" y="225" width="570" height="125" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,42 @@
import {
bootstrapModeler,
inject
} from 'test/TestHelper';
import coreModule from 'lib/core';
import modelingModule from 'lib/features/modeling';
import { getMid } from 'diagram-js/lib/layout/LayoutUtil';
describe('features/modeling - CreateBehavior', function() {
var processDiagramXML = require('./CreateBehavior.bpmn');
beforeEach(bootstrapModeler(processDiagramXML, {
modules: [
coreModule,
modelingModule
]
}));
it('should ensure parent is participant', inject(
function(elementFactory, elementRegistry, modeling) {
// given
var lane = elementRegistry.get('Lane_1'),
participant = elementRegistry.get('Participant_1');
var task = elementFactory.createShape({
type: 'bpmn:Task'
});
// when
modeling.createShape(task, getMid(lane), lane);
// then
expect(task.parent).to.equal(participant);
}
));
});

View File

@ -1,11 +1,11 @@
/* global sinon */
import {
bootstrapModeler,
inject
} from 'test/TestHelper';
import {
getBusinessObject
getBusinessObject,
is
} from 'lib/util/ModelUtil';
import {
@ -17,6 +17,8 @@ import copyPasteModule from 'diagram-js/lib/features/copy-paste';
import modelingModule from 'lib/features/modeling';
import coreModule from 'lib/core';
import { find } from 'min-dash';
describe('features/modeling/behavior - groups', function() {
@ -154,43 +156,68 @@ describe('features/modeling/behavior - groups', function() {
});
describe('should set copied name for pasted group', function() {
describe('integration', function() {
it('execute', inject(function(canvas, elementRegistry, copyPaste, eventBus) {
var groupBo, rootElements;
beforeEach(inject(function(canvas, copyPaste, elementRegistry) {
// given
var groupShape = elementRegistry.get('Group_1'),
categoryValue = getBusinessObject(groupShape).categoryValueRef,
root = canvas.getRootElement(),
listener = sinon.spy(function(event) {
var group = elementRegistry.get('Group_1'),
rootElement = canvas.getRootElement();
var context = event.context,
createdElement = context.shape,
businessObject = createdElement.businessObject,
categoryValueRef = businessObject.categoryValueRef;
expect(categoryValueRef).to.exist;
expect(categoryValueRef).to.not.eql(categoryValue);
expect(categoryValueRef.value).to.equal(categoryValue.value);
});
eventBus.on('commandStack.shape.create.postExecute', listener);
copyPaste.copy(group);
// when
copyPaste.copy(groupShape);
copyPaste.paste({
element: root,
var elements = copyPaste.paste({
element: rootElement,
point: {
x: 50,
y: 50
x: 500,
y: 500
}
});
// then
expect(listener).to.have.been.called;
group = find(elements, function(element) {
return is(element, 'bpmn:Group');
});
groupBo = getBusinessObject(group);
rootElements = getBusinessObject(canvas.getRootElement()).$parent.rootElements;
}));
it('<do>', function() {
// then
expect(groupBo.categoryValueRef).to.exist;
expect(groupBo.categoryValueRef.$parent).to.exist;
expect(groupBo.categoryValueRef.value).to.equal('Value 1');
expect(rootElements).to.have.length(4);
});
it('<undo>', inject(function(commandStack) {
// when
commandStack.undo();
// then
expect(rootElements).to.have.length(3);
}));
it('<redo>', function() {
// then
expect(groupBo.categoryValueRef).to.exist;
expect(groupBo.categoryValueRef.$parent).to.exist;
expect(groupBo.categoryValueRef.value).to.equal('Value 1');
expect(rootElements).to.have.length(4);
});
});
});

View File

@ -272,6 +272,29 @@ describe('behavior - LabelBehavior', function() {
}
));
it('should NOT add label if hint createElementsBehavior=false', inject(
function(bpmnFactory, elementFactory, elementRegistry, modeling) {
// given
var parentShape = elementRegistry.get('Process_1'),
newShape = elementFactory.createShape({
type: 'bpmn:ExclusiveGateway',
businessObject: bpmnFactory.create('bpmn:ExclusiveGateway', {
name: 'foo'
})
});
// when
newShape = modeling.createShape(newShape, { x: 50, y: 50 }, parentShape, {
createElementsBehavior: false
});
// then
expect(newShape.label).not.to.exist;
}
));
});
@ -646,7 +669,7 @@ describe('behavior - LabelBehavior', function() {
});
// helper //////////
// helpers //////////
function getBounds(element) {
return pick(element, [ 'x', 'y', 'width', 'height' ]);

View File

@ -4,13 +4,10 @@ import {
} from 'test/TestHelper';
import coreModule from 'lib/core';
import createModule from 'diagram-js/lib/features/create';
import draggingModule from 'diagram-js/lib/features/create';
import modelingModule from 'lib/features/modeling';
import replaceModule from 'lib/features/replace';
import { is } from 'lib/util/ModelUtil';
import { createCanvasEvent as canvasEvent } from 'test/util/MockEvents';
describe('features/modeling/behavior - subprocess start event', function() {
@ -19,46 +16,12 @@ describe('features/modeling/behavior - subprocess start event', function() {
beforeEach(bootstrapModeler(diagramXML, {
modules: [
coreModule,
createModule,
draggingModule,
modelingModule,
replaceModule
]
}));
describe('create', function() {
it('should contain start event child', inject(
function(canvas, elementFactory, create, dragging) {
// given
var rootElement = canvas.getRootElement(),
subProcess = elementFactory.createShape({
type: 'bpmn:SubProcess',
isExpanded: true
}),
startEvents;
// when
create.start(canvasEvent({ x: 0, y: 0 }), subProcess);
dragging.hover({ element: rootElement });
dragging.move(canvasEvent({ x: 600, y: 150 }));
dragging.end();
// then
startEvents = getChildStartEvents(subProcess);
expect(startEvents).to.have.length(1);
}
));
});
describe('replace', function() {
describe('task -> expanded subprocess', function() {

View File

@ -200,7 +200,7 @@ describe('features/modeling - lanes - flowNodeRefs', function() {
parentLane = parentLaneShape.businessObject;
// when
taskShape = modeling.createShape({ type: 'bpmn:Task' }, { x: 200, y: 300 }, parentLaneShape);
taskShape = modeling.createShape({ type: 'bpmn:Task' }, { x: 500, y: 150 }, parentLaneShape);
task = taskShape.businessObject;
// then
@ -215,7 +215,7 @@ describe('features/modeling - lanes - flowNodeRefs', function() {
parentLaneShape = elementRegistry.get('Lane'),
parentLane = parentLaneShape.businessObject;
taskShape = modeling.createShape({ type: 'bpmn:Task' }, { x: 200, y: 300 }, parentLaneShape);
taskShape = modeling.createShape({ type: 'bpmn:Task' }, { x: 500, y: 150 }, parentLaneShape);
task = taskShape.businessObject;
// when
@ -233,7 +233,7 @@ describe('features/modeling - lanes - flowNodeRefs', function() {
parentLaneShape = elementRegistry.get('Lane'),
parentLane = parentLaneShape.businessObject;
taskShape = modeling.createShape({ type: 'bpmn:Task' }, { x: 200, y: 300 }, parentLaneShape);
taskShape = modeling.createShape({ type: 'bpmn:Task' }, { x: 500, y: 150 }, parentLaneShape);
task = taskShape.businessObject;
// when

View File

@ -13,6 +13,9 @@ import replaceModule from 'lib/features/replace';
import moveModule from 'diagram-js/lib/features/move';
import coreModule from 'lib/core';
import camundaModdleModule from 'camunda-bpmn-moddle/lib';
import camundaPackage from 'camunda-bpmn-moddle/resources/camunda.json';
import {
is
} from 'lib/util/ModelUtil';
@ -28,10 +31,11 @@ import {
describe('features/replace - bpmn replace', function() {
var testModules = [
camundaModdleModule,
coreModule,
modelingModule,
replaceModule,
moveModule
moveModule,
replaceModule
];
@ -39,7 +43,12 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn');
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
it('task', inject(function(elementRegistry, bpmnReplace) {
@ -288,7 +297,10 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('./BpmnReplace.collaboration.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
@ -341,7 +353,10 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('./BpmnReplace.poolMessageFlows.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
@ -372,7 +387,10 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('./BpmnReplace.dataObjects.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
@ -413,7 +431,12 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn');
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
it('should keep position', inject(function(elementRegistry, bpmnReplace) {
@ -458,7 +481,12 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn');
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
it('should select after replace',
@ -485,7 +513,12 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn');
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
it('should keep internal labels',
inject(function(elementRegistry, bpmnReplace) {
@ -533,7 +566,10 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
@ -595,7 +631,10 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
@ -830,7 +869,12 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn');
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
it('should update bpmn containment properly', inject(function(elementRegistry, modeling, bpmnReplace) {
@ -871,7 +915,12 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn');
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
it('should allow morphing expanded into expanded ad hoc',
@ -1010,7 +1059,10 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
@ -1063,7 +1115,10 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('./BpmnReplace.compensation.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
@ -1089,7 +1144,12 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('./BpmnReplace.eventSubProcesses.bpmn');
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
it('should remove connections',
@ -1371,7 +1431,10 @@ describe('features/replace - bpmn replace', function() {
var diagramXML = require('../../../fixtures/bpmn/basic.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: testModules
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
@ -1439,20 +1502,20 @@ describe('features/replace - bpmn replace', function() {
describe('properties', function() {
var clonePropertiesXML = require('../../../fixtures/bpmn/features/replace/clone-properties.bpmn');
var copyPropertiesXML = require('../../../fixtures/bpmn/features/replace/copy-properties.bpmn');
var camundaPackage = require('../../../fixtures/json/model/camunda');
beforeEach(bootstrapModeler(clonePropertiesXML, {
beforeEach(bootstrapModeler(copyPropertiesXML, {
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
it('should copy properties', inject(function(elementRegistry, bpmnReplace) {
it('should copy properties', inject(function(bpmnReplace, elementRegistry) {
// given
var task = elementRegistry.get('Task_1');
var newElementData = {
type: 'bpmn:ServiceTask'
};
@ -1465,39 +1528,46 @@ describe('features/replace - bpmn replace', function() {
expect(businessObject.asyncBefore).to.be.true;
expect(businessObject.jobPriority).to.equal('100');
expect(businessObject.documentation[0].text).to.equal('hello world');
var extensionElements = businessObject.extensionElements.values;
var documentation = businessObject.documentation;
expect(extensionElements).to.have.length(4);
expect(documentation).to.have.length(1);
expect(documentation[0]).to.exist;
expect(documentation[0].text).to.equal('hello world');
expect(is(extensionElements[0], 'camunda:InputOutput')).to.be.true;
var extensionElements = businessObject.extensionElements;
expect(is(extensionElements[0].inputParameters[0], 'camunda:InputParameter')).to.be.true;
expect(extensionElements.values).to.have.length(4);
expect(extensionElements[0].inputParameters[0].name).to.equal('Input_1');
expect(extensionElements[0].inputParameters[0].value).to.equal('foo');
var inputOutput = extensionElements.values[0],
properties = extensionElements.values[1],
executionListener = extensionElements.values[2],
retryCycle = extensionElements.values[3];
expect(is(extensionElements[0].outputParameters[0], 'camunda:OutputParameter')).to.be.true;
expect(is(inputOutput, 'camunda:InputOutput')).to.be.true;
expect(extensionElements[0].outputParameters[0].name).to.equal('Output_1');
expect(extensionElements[0].outputParameters[0].value).to.equal('bar');
expect(is(inputOutput.inputParameters[0], 'camunda:InputParameter')).to.be.true;
expect(inputOutput.inputParameters[0].name).to.equal('Input_1');
expect(inputOutput.inputParameters[0].value).to.equal('foo');
expect(is(extensionElements[1], 'camunda:Properties')).to.be.true;
expect(is(inputOutput.outputParameters[0], 'camunda:OutputParameter')).to.be.true;
expect(inputOutput.outputParameters[0].name).to.equal('Output_1');
expect(inputOutput.outputParameters[0].value).to.equal('bar');
expect(is(extensionElements[1].values[0], 'camunda:Property')).to.be.true;
expect(is(properties, 'camunda:Properties')).to.be.true;
expect(extensionElements[1].values[0].name).to.equal('bar');
expect(extensionElements[1].values[0].value).to.equal('foo');
expect(is(properties.values[0], 'camunda:Property')).to.be.true;
expect(properties.values[0].name).to.equal('bar');
expect(properties.values[0].value).to.equal('foo');
expect(is(extensionElements[2], 'camunda:ExecutionListener')).to.be.true;
expect(is(executionListener, 'camunda:ExecutionListener')).to.be.true;
expect(extensionElements[2].class).to.equal('reallyClassy');
expect(extensionElements[2].event).to.equal('start');
expect(executionListener.class).to.equal('reallyClassy');
expect(executionListener.event).to.equal('start');
expect(is(extensionElements[3], 'camunda:FailedJobRetryTimeCycle')).to.be.true;
expect(is(retryCycle, 'camunda:FailedJobRetryTimeCycle')).to.be.true;
expect(extensionElements[3].body).to.equal('10');
expect(retryCycle.body).to.equal('10');
}));
});
@ -1516,8 +1586,8 @@ describe('features/replace - bpmn replace', function() {
var newElementData = {
type: 'bpmn:UserTask'
},
fill = '#BBDEFB',
stroke = '#1E88E5';
fill = 'red',
stroke = 'green';
modeling.setColor(task, { fill: fill, stroke: stroke });
@ -1529,8 +1599,6 @@ describe('features/replace - bpmn replace', function() {
expect(businessObject.di.fill).to.equal(fill);
expect(businessObject.di.stroke).to.equal(stroke);
expect(newElement.colors).not.to.exist;
}));
});

View File

@ -1,390 +0,0 @@
import {
bootstrapModeler,
inject
} from 'test/TestHelper';
import coreModule from 'lib/core';
import modelingModule from 'lib/features/modeling';
import ModelCloneHelper from 'lib/util/model/ModelCloneHelper';
import camundaPackage from '../../fixtures/json/model/camunda';
import camundaModdleModule from './camunda-moddle';
describe('util/clone/ModelCloneHelper', function() {
var testModules = [
camundaModdleModule,
coreModule,
modelingModule
];
var basicXML = require('../../fixtures/bpmn/basic.bpmn');
beforeEach(bootstrapModeler(basicXML, {
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
var helper;
beforeEach(inject(function(eventBus, bpmnFactory) {
helper = new ModelCloneHelper(eventBus, bpmnFactory);
}));
describe('simple', function() {
it('should pass property', inject(function(moddle) {
// given
var userTask = moddle.create('bpmn:UserTask', {
asyncBefore: true
});
var serviceTask = helper.clone(userTask, moddle.create('bpmn:ServiceTask'), [ 'camunda:asyncBefore' ]);
expect(getProp(serviceTask, 'camunda:asyncBefore')).to.be.true;
}));
it('should not pass property', inject(function(moddle) {
// given
var userTask = moddle.create('bpmn:UserTask', {
assignee: 'foobar'
});
var serviceTask = helper.clone(userTask, moddle.create('bpmn:ServiceTask'), []);
expect(getProp(serviceTask, 'camunda:assignee')).not.to.exist;
}));
});
describe('nested', function() {
it('should pass nested property - documentation', inject(function(moddle) {
// given
var userTask = moddle.create('bpmn:UserTask');
var docs = userTask.get('documentation');
docs.push(moddle.create('bpmn:Documentation', { textFormat: 'xyz', text: 'FOO\nBAR' }));
docs.push(moddle.create('bpmn:Documentation', { text: '<some /><html></html>' }));
var serviceTask = helper.clone(userTask, moddle.create('bpmn:ServiceTask'), [ 'bpmn:documentation' ]);
var serviceTaskDocs = getProp(serviceTask, 'bpmn:documentation'),
userTaskDocs = getProp(userTask, 'bpmn:documentation');
expect(userTaskDocs[0]).not.to.equal(serviceTaskDocs[0]);
expect(serviceTaskDocs[0].$parent).to.equal(serviceTask);
expect(serviceTaskDocs[0].text).to.equal('FOO\nBAR');
expect(serviceTaskDocs[0].textFormat).to.equal('xyz');
expect(serviceTaskDocs[1].text).to.equal('<some /><html></html>');
}));
it('should pass deeply nested property - executionListener', inject(function(moddle) {
// given
var script = moddle.create('camunda:Script', {
scriptFormat: 'groovy',
value: 'foo = bar;'
});
var execListener = moddle.create('camunda:ExecutionListener', {
event: 'start',
script: script
});
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ execListener ] });
var userTask = moddle.create('bpmn:UserTask', {
extensionElements: extensionElements
});
var serviceTask = helper.clone(userTask, moddle.create('bpmn:ServiceTask'), [
'bpmn:extensionElements',
'camunda:executionListener'
]);
var executionListener = serviceTask.extensionElements.values[0];
// then
expect(executionListener).not.to.equal(userTask.extensionElements.values[0]);
expect(executionListener.$type).to.equal('camunda:ExecutionListener');
expect(executionListener.$type).to.equal('camunda:ExecutionListener');
expect(executionListener.$parent).to.equal(serviceTask.extensionElements);
expect(executionListener.event).to.equal('start');
expect(executionListener.script.$type).to.equal('camunda:Script');
expect(executionListener.script.$parent).to.equal(executionListener);
expect(executionListener.script.scriptFormat).to.equal('groovy');
expect(executionListener.script.value).to.equal('foo = bar;');
}));
it('should pass deeply nested property - inputOutput', inject(function(moddle) {
// given
var outputParameter = moddle.create('camunda:OutputParameter', {
name: 'var1',
definition: moddle.create('camunda:List', {
items: [
moddle.create('camunda:Value', { value: '${1+1}' }),
moddle.create('camunda:Value', { value: '${1+2}' }),
moddle.create('camunda:Value', { value: '${1+3}' })
]
})
});
var inputOutput = moddle.create('camunda:InputOutput', {
outputParameters: [ outputParameter ]
});
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ inputOutput ] });
var userTask = moddle.create('bpmn:UserTask', {
extensionElements: extensionElements
});
var subProcess = helper.clone(userTask, moddle.create('bpmn:SubProcess'), [
'bpmn:extensionElements'
]);
expect(subProcess.extensionElements.values[0].$type).to.equal('camunda:InputOutput');
var serviceTask = helper.clone(userTask, moddle.create('bpmn:ServiceTask'), [
'bpmn:extensionElements',
'camunda:inputOutput'
]);
var executionListener = serviceTask.extensionElements.values[0];
// then
expect(executionListener.$type).to.equal('camunda:InputOutput');
var newOutParam = executionListener.outputParameters[0];
var oldOutParam = userTask.extensionElements.values[0].outputParameters[0];
expect(newOutParam).not.to.equal(oldOutParam);
expect(newOutParam.$parent).to.equal(executionListener);
expect(newOutParam.definition).not.to.equal(oldOutParam.definition);
expect(newOutParam.definition.$parent).to.equal(newOutParam);
expect(newOutParam.definition.items[0]).not.to.equal(oldOutParam.definition.items[0]);
expect(newOutParam.definition.items[0].$parent).not.to.equal(newOutParam.definition.$parent);
expect(newOutParam.$type).to.equal('camunda:OutputParameter');
expect(newOutParam.definition.$type).to.equal('camunda:List');
expect(newOutParam.definition.items[0].value).to.equal('${1+1}');
}));
it('should not pass disallowed deeply nested property - connector', inject(function(moddle) {
// given
var connector = moddle.create('camunda:Connector', {
connectorId: 'hello_connector'
});
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ connector ] });
var serviceTask = moddle.create('bpmn:UserTask', {
extensionElements: extensionElements
});
var userTask = helper.clone(serviceTask, moddle.create('bpmn:UserTask'), [
'bpmn:extensionElements'
]);
var extElem = userTask.extensionElements;
// then
expect(extElem).not.to.exist;
}));
});
describe('special cases', function() {
it('failed job retry time cycle', inject(function(moddle) {
function createExtElems() {
var retryTimeCycle = moddle.create('camunda:FailedJobRetryTimeCycle', { body: 'foobar' });
return moddle.create('bpmn:ExtensionElements', { values: [ retryTimeCycle ] });
}
// given
var timerEvtDef = moddle.create('bpmn:TimerEventDefinition', {
timeDuration: 'foobar'
});
var signalEvtDef = moddle.create('bpmn:SignalEventDefinition', {
async: true
});
var multiInst = moddle.create('bpmn:MultiInstanceLoopCharacteristics', {
elementVariable: 'foobar'
});
var timerStartEvent = moddle.create('bpmn:StartEvent', {
extensionElements: createExtElems(),
eventDefinitions: [ timerEvtDef ]
});
var signalStartEvt = moddle.create('bpmn:StartEvent', {
extensionElements: createExtElems(),
eventDefinitions: [ signalEvtDef ]
});
var subProcess = moddle.create('bpmn:SubProcess', {
extensionElements: createExtElems(),
loopCharacteristics: multiInst
});
var intCatchEvt = helper.clone(timerStartEvent, moddle.create('bpmn:IntermediateCatchEvent'), [
'bpmn:extensionElements',
'bpmn:eventDefinitions'
]);
var startEvt = helper.clone(signalStartEvt, moddle.create('bpmn:StartEvent'), [
'bpmn:extensionElements',
'bpmn:eventDefinitions'
]);
var newSubProcess = helper.clone(subProcess, moddle.create('bpmn:SubProcess'), [
'bpmn:extensionElements',
'bpmn:loopCharacteristics'
]);
var intCatchEvtExtElems = intCatchEvt.extensionElements.values,
startEvtExtElems = startEvt.extensionElements.values,
newSubProcessExtElems = newSubProcess.extensionElements.values;
// then
expect(intCatchEvtExtElems[0].$type).to.equal('camunda:FailedJobRetryTimeCycle');
expect(intCatchEvtExtElems[0].body).to.equal('foobar');
expect(startEvtExtElems[0].$type).to.equal('camunda:FailedJobRetryTimeCycle');
expect(startEvtExtElems[0].body).to.equal('foobar');
expect(newSubProcessExtElems[0].$type).to.equal('camunda:FailedJobRetryTimeCycle');
expect(newSubProcessExtElems[0].body).to.equal('foobar');
}));
it('connector', inject(function(moddle) {
// given
var connector = moddle.create('camunda:Connector', {
connectorId: 'hello_connector'
});
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ connector ] });
var msgEvtDef = moddle.create('bpmn:MessageEventDefinition', {
extensionElements: extensionElements
});
var msgIntermThrowEvt = moddle.create('bpmn:IntermediateThrowEvent', {
eventDefinitions: [ msgEvtDef ]
});
var clonedElement = helper.clone(msgIntermThrowEvt, moddle.create('bpmn:EndEvent'), [
'bpmn:extensionElements',
'bpmn:eventDefinitions'
]);
var extElems = clonedElement.eventDefinitions[0].extensionElements.values;
// then
expect(extElems[0].$type).to.equal('camunda:Connector');
expect(extElems[0].connectorId).to.equal('hello_connector');
}));
it('field', inject(function(moddle) {
// given
var field = moddle.create('camunda:Field', {
name: 'hello_field'
});
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ field ] });
var msgEvtDef = moddle.create('bpmn:MessageEventDefinition', {
extensionElements: extensionElements
});
var msgIntermThrowEvt = moddle.create('bpmn:IntermediateThrowEvent', {
eventDefinitions: [ msgEvtDef ]
});
var clonedElement = helper.clone(msgIntermThrowEvt, moddle.create('bpmn:EndEvent'), [
'bpmn:extensionElements',
'bpmn:eventDefinitions'
]);
var extElems = clonedElement.eventDefinitions[0].extensionElements.values;
// then
expect(extElems[0].$type).to.equal('camunda:Field');
expect(extElems[0].name).to.equal('hello_field');
}));
it('not clone field', inject(function(moddle) {
// given
var field = moddle.create('camunda:Field', {
name: 'hello_field'
});
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ field ] });
var msgEvtDef = moddle.create('bpmn:MessageEventDefinition', {
extensionElements: extensionElements
});
var msgIntermThrowEvt = moddle.create('bpmn:IntermediateThrowEvent', {
eventDefinitions: [ msgEvtDef ]
});
var clonedElement = helper.clone(msgIntermThrowEvt, moddle.create('bpmn:IntermediateThrowEvent'), [
'bpmn:extensionElements'
]);
var extElems = clonedElement.extensionElements;
// then
expect(extElems).not.to.exist;
}));
});
});
// helpers ////////////
function getProp(element, property) {
return element && element.$model.properties.get(element, property);
}

View File

@ -1,77 +0,0 @@
import {
some
} from 'min-dash';
var ALLOWED_TYPES = {
FailedJobRetryTimeCycle: [
'bpmn:StartEvent',
'bpmn:BoundaryEvent',
'bpmn:IntermediateCatchEvent',
'bpmn:Activity'
],
Connector: [ 'bpmn:EndEvent', 'bpmn:IntermediateThrowEvent' ],
Field: [ 'bpmn:EndEvent', 'bpmn:IntermediateThrowEvent' ]
};
function is(element, type) {
return element && (typeof element.$instanceOf === 'function') && element.$instanceOf(type);
}
function exists(element) {
return element && element.length;
}
function includesType(collection, type) {
return exists(collection) && some(collection, function(element) {
return is(element, type);
});
}
function anyType(element, types) {
return some(types, function(type) {
return is(element, type);
});
}
function isAllowed(propName, propDescriptor, newElement) {
var name = propDescriptor.name,
types = ALLOWED_TYPES[ name.replace(/camunda:/, '') ];
return name === propName && anyType(newElement, types);
}
function CamundaModdleExtension(eventBus) {
eventBus.on('property.clone', function(context) {
var newElement = context.newElement,
refTopLevelProperty = context.refTopLevelProperty,
propDescriptor = context.propertyDescriptor;
return this.canCloneProperty(newElement, refTopLevelProperty, propDescriptor);
}, this);
}
CamundaModdleExtension.$inject = [ 'eventBus' ];
CamundaModdleExtension.prototype.canCloneProperty = function(
newElement, refTopLevelProperty, propDescriptor) {
if (isAllowed('camunda:FailedJobRetryTimeCycle', propDescriptor, newElement)) {
return includesType(newElement.eventDefinitions, 'bpmn:TimerEventDefinition') ||
includesType(newElement.eventDefinitions, 'bpmn:SignalEventDefinition') ||
is(newElement.loopCharacteristics, 'bpmn:MultiInstanceLoopCharacteristics');
}
if (isAllowed('camunda:Connector', propDescriptor, newElement) ||
isAllowed('camunda:Field', propDescriptor, newElement)) {
return is(refTopLevelProperty, 'bpmn:MessageEventDefinition');
}
};
export default {
__init__: [ 'camundaModdleExtension' ],
camundaModdleExtension: [ 'type', CamundaModdleExtension ]
};