fix(copy-paste): ignore data associations during cloning
* use bpmnFactory for cloning to ensure all relevant elements have actual IDs * don't copy dataAssociations, as they are visual elements that will be created during element re-connection NOTE: This fixes data input association not properly being wired during target replace, too. Closes #694, #693
This commit is contained in:
parent
25d5fb2967
commit
cd24b27768
|
@ -34,7 +34,7 @@ function BpmnCopyPaste(
|
|||
bpmnFactory, eventBus, copyPaste,
|
||||
clipboard, canvas, bpmnRules) {
|
||||
|
||||
var helper = new ModelCloneHelper(eventBus);
|
||||
var helper = new ModelCloneHelper(eventBus, bpmnFactory);
|
||||
|
||||
copyPaste.registerDescriptor(function(element, descriptor) {
|
||||
var businessObject = descriptor.oldBusinessObject = getBusinessObject(element);
|
||||
|
|
|
@ -56,7 +56,7 @@ function toggeling(element, target) {
|
|||
*/
|
||||
function BpmnReplace(bpmnFactory, replace, selection, modeling, eventBus) {
|
||||
|
||||
var helper = new ModelCloneHelper(eventBus);
|
||||
var helper = new ModelCloneHelper(eventBus, bpmnFactory);
|
||||
|
||||
/**
|
||||
* Prepares a new business object for the replacement element
|
||||
|
|
|
@ -29,8 +29,9 @@ function isType(element, types) {
|
|||
* A bpmn properties cloning interface
|
||||
*
|
||||
*/
|
||||
function ModelCloneHelper(eventBus) {
|
||||
function ModelCloneHelper(eventBus, bpmnFactory) {
|
||||
this._eventBus = eventBus;
|
||||
this._bpmnFactory = bpmnFactory;
|
||||
}
|
||||
|
||||
module.exports = ModelCloneHelper;
|
||||
|
@ -60,8 +61,11 @@ ModelCloneHelper.prototype.clone = function(refElement, newElement, properties)
|
|||
// - same values from simple types
|
||||
// - cloning id's
|
||||
// - cloning reference elements
|
||||
if (newElementProp === refElementProp ||
|
||||
(propDescriptor && (propDescriptor.isId || propDescriptor.isReference))) {
|
||||
if (newElementProp === refElementProp) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (propDescriptor && (propDescriptor.isId || propDescriptor.isReference)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -110,8 +114,9 @@ ModelCloneHelper.prototype.clone = function(refElement, newElement, properties)
|
|||
|
||||
ModelCloneHelper.prototype._deepClone = function _deepClone(propertyElement, context) {
|
||||
var eventBus = this._eventBus;
|
||||
var bpmnFactory = this._bpmnFactory;
|
||||
|
||||
var newProp = propertyElement.$model.create(propertyElement.$type);
|
||||
var newProp = bpmnFactory.create(propertyElement.$type);
|
||||
|
||||
var properties = filter(Object.keys(propertyElement), function(prop) {
|
||||
var descriptor = newProp.$model.getPropertyDescriptor(newProp, prop);
|
||||
|
|
|
@ -13,7 +13,9 @@ module.exports.IGNORED_PROPERTIES = [
|
|||
'outgoing',
|
||||
'artifacts',
|
||||
'default',
|
||||
'flowElements'
|
||||
'flowElements',
|
||||
'dataInputAssociations',
|
||||
'dataOutputAssociations'
|
||||
];
|
||||
|
||||
|
||||
|
|
|
@ -523,9 +523,15 @@ describe('features/copy-paste', function() {
|
|||
|
||||
describe('integration', function() {
|
||||
|
||||
it('multiple participants', inject(integrationTest([ 'Participant_0pgdgt4', 'Participant_1id96b4' ])));
|
||||
it('multiple participants', inject(integrationTest([
|
||||
'Participant_0pgdgt4',
|
||||
'Participant_1id96b4'
|
||||
])));
|
||||
|
||||
it('multiple participants', inject(integrationTest([ 'Participant_0pgdgt4', 'Participant_1id96b4' ])));
|
||||
it('multiple participants', inject(integrationTest([
|
||||
'Participant_0pgdgt4',
|
||||
'Participant_1id96b4'
|
||||
])));
|
||||
|
||||
});
|
||||
|
||||
|
@ -537,42 +543,44 @@ describe('features/copy-paste', function() {
|
|||
beforeEach(bootstrapModeler(collaborationAssociations, { modules: testModules }));
|
||||
|
||||
|
||||
it('copying participant should copy process as well', inject(function(elementRegistry, copyPaste, canvas) {
|
||||
it('copying participant should copy process as well', inject(
|
||||
function(elementRegistry, copyPaste, canvas) {
|
||||
|
||||
// given
|
||||
var participants = map([ 'Participant_Input', 'Participant_Output' ], function(e) {
|
||||
return elementRegistry.get(e);
|
||||
});
|
||||
var rootElement = canvas.getRootElement();
|
||||
// given
|
||||
var participants = map([ 'Participant_Input', 'Participant_Output' ], function(e) {
|
||||
return elementRegistry.get(e);
|
||||
});
|
||||
var rootElement = canvas.getRootElement();
|
||||
|
||||
// when
|
||||
copyPaste.copy(participants);
|
||||
// when
|
||||
copyPaste.copy(participants);
|
||||
|
||||
copyPaste.paste({
|
||||
element: rootElement,
|
||||
point: {
|
||||
x: 4000,
|
||||
y: 4500
|
||||
}
|
||||
});
|
||||
copyPaste.paste({
|
||||
element: rootElement,
|
||||
point: {
|
||||
x: 4000,
|
||||
y: 4500
|
||||
}
|
||||
});
|
||||
|
||||
// then
|
||||
var elements = elementRegistry.filter(function(element) {
|
||||
return element.type === 'bpmn:Participant';
|
||||
});
|
||||
// then
|
||||
var elements = elementRegistry.filter(function(element) {
|
||||
return element.type === 'bpmn:Participant';
|
||||
});
|
||||
|
||||
var processIds = map(elements, function(e) {
|
||||
return e.businessObject.processRef.id;
|
||||
});
|
||||
var processIds = map(elements, function(e) {
|
||||
return e.businessObject.processRef.id;
|
||||
});
|
||||
|
||||
expect(uniq(processIds)).to.have.length(4);
|
||||
}));
|
||||
expect(uniq(processIds)).to.have.length(4);
|
||||
}
|
||||
));
|
||||
|
||||
|
||||
it('participant with OutputDataAssociation', inject(integrationTest([ 'Participant_Output' ])));
|
||||
it('participant with DataOutputAssociation', inject(integrationTest([ 'Participant_Output' ])));
|
||||
|
||||
|
||||
it('participant with InputDataAssociation', inject(integrationTest([ 'Participant_Input' ])));
|
||||
it('participant with DataInputAssociation', inject(integrationTest([ 'Participant_Input' ])));
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
|
||||
<bpmn:process id="Process_1" isExecutable="false">
|
||||
<bpmn:task id="Task">
|
||||
<bpmn:property id="TaskPlaceholderProperty" name="__targetRef_placeholder" />
|
||||
<bpmn:dataInputAssociation id="DataInputAssociation">
|
||||
<bpmn:sourceRef>DataObjectReference_IN</bpmn:sourceRef>
|
||||
<bpmn:targetRef>TaskPlaceholderProperty</bpmn:targetRef>
|
||||
</bpmn:dataInputAssociation>
|
||||
<bpmn:dataOutputAssociation id="DataOutputAssociation_1by9zp9">
|
||||
<bpmn:targetRef>DataObjectReference_OUT</bpmn:targetRef>
|
||||
</bpmn:dataOutputAssociation>
|
||||
</bpmn:task>
|
||||
<bpmn:dataObjectReference id="DataObjectReference_IN" dataObjectRef="DataObject_1l9lukc" />
|
||||
<bpmn:dataObject id="DataObject_1l9lukc" />
|
||||
<bpmn:dataObjectReference id="DataObjectReference_OUT" dataObjectRef="DataObject_03twvyv" />
|
||||
<bpmn:dataObject id="DataObject_03twvyv" />
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
|
||||
<bpmndi:BPMNShape id="Task_di" bpmnElement="Task">
|
||||
<dc:Bounds x="132" y="150" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="DataObjectReference_IN_di" bpmnElement="DataObjectReference_IN">
|
||||
<dc:Bounds x="62" y="33" width="36" height="50" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="80" y="87" width="0" height="12" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="DataInputAssociation_di" bpmnElement="DataInputAssociation">
|
||||
<di:waypoint xsi:type="dc:Point" x="98" y="81" />
|
||||
<di:waypoint xsi:type="dc:Point" x="152" y="150" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="DataObjectReference_OUT_di" bpmnElement="DataObjectReference_OUT">
|
||||
<dc:Bounds x="232" y="33" width="36" height="50" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="250" y="87" width="0" height="12" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="DataOutputAssociation_1by9zp9_di" bpmnElement="DataOutputAssociation_1by9zp9">
|
||||
<di:waypoint xsi:type="dc:Point" x="207" y="150" />
|
||||
<di:waypoint xsi:type="dc:Point" x="248" y="83" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -236,6 +236,48 @@ describe('features/replace - bpmn replace', function() {
|
|||
});
|
||||
|
||||
|
||||
describe('should replace with data objects', function() {
|
||||
|
||||
var diagramXML = require('./BpmnReplace.dataObjects.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, {
|
||||
modules: testModules
|
||||
}));
|
||||
|
||||
|
||||
it('restoring dataAssociations', inject(function(elementRegistry, bpmnReplace) {
|
||||
|
||||
// given
|
||||
var task = elementRegistry.get('Task');
|
||||
|
||||
// when
|
||||
var serviceTask = bpmnReplace.replaceElement(task, { type: 'bpmn:ServiceTask' });
|
||||
var bo = serviceTask.businessObject;
|
||||
|
||||
// then
|
||||
// expect one incoming connection
|
||||
expect(serviceTask.incoming).to.have.length(1);
|
||||
|
||||
var inputAssociations = bo.dataInputAssociations;
|
||||
expect(inputAssociations).to.have.length(1);
|
||||
|
||||
var inputAssociation = inputAssociations[0];
|
||||
|
||||
// expect input association references __target_ref_placeholder property
|
||||
expect(inputAssociation.targetRef).to.equal(bo.properties[0]);
|
||||
|
||||
// ...and
|
||||
// expect one outgoing connection
|
||||
expect(serviceTask.outgoing).to.have.length(1);
|
||||
|
||||
var outputAssociations = bo.dataOutputAssociations;
|
||||
expect(outputAssociations).to.have.length(1);
|
||||
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('position and size', function() {
|
||||
|
||||
var diagramXML = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn');
|
||||
|
|
|
@ -5,6 +5,7 @@ require('../../TestHelper');
|
|||
/* global bootstrapModeler, inject */
|
||||
|
||||
var coreModule = require('../../../lib/core');
|
||||
var modelingModule = require('../../../lib/features/modeling');
|
||||
|
||||
var ModelCloneHelper = require('../../../lib/util/model/ModelCloneHelper');
|
||||
|
||||
|
@ -18,7 +19,11 @@ function getProp(element, property) {
|
|||
|
||||
describe('util/ModelCloneHelper', function() {
|
||||
|
||||
var testModules = [ camundaModdleModule, coreModule ];
|
||||
var testModules = [
|
||||
camundaModdleModule,
|
||||
coreModule,
|
||||
modelingModule
|
||||
];
|
||||
|
||||
var basicXML = require('../../fixtures/bpmn/basic.bpmn');
|
||||
|
||||
|
@ -31,8 +36,8 @@ describe('util/ModelCloneHelper', function() {
|
|||
|
||||
var helper;
|
||||
|
||||
beforeEach(inject(function(eventBus) {
|
||||
helper = new ModelCloneHelper(eventBus);
|
||||
beforeEach(inject(function(eventBus, bpmnFactory) {
|
||||
helper = new ModelCloneHelper(eventBus, bpmnFactory);
|
||||
}));
|
||||
|
||||
describe('simple', function() {
|
||||
|
@ -64,6 +69,7 @@ describe('util/ModelCloneHelper', function() {
|
|||
|
||||
});
|
||||
|
||||
|
||||
describe('nested', function() {
|
||||
|
||||
it('should pass nested property - documentation', inject(function(moddle) {
|
||||
|
|
Loading…
Reference in New Issue