feat(modeling): allow data store anywhere in collaboration

ensure valid BPMN 2.0 parent when

* creating/moving data store
* removing participant
* turning process into collaboration
* turning collaboration into process

Closes #483
This commit is contained in:
Philipp Fromme 2018-05-03 16:02:41 +02:00 committed by Nico Rehwaldt
parent 0f62183410
commit 690417b389
19 changed files with 863 additions and 13 deletions

View File

@ -321,6 +321,13 @@ BpmnUpdater.prototype.updateParent = function(element, oldParent) {
return;
}
// data stores in collaborations are handled seperately by DataStoreBehavior
if (is(element, 'bpmn:DataStoreReference') &&
element.parent &&
is(element.parent, 'bpmn:Collaboration')) {
return;
}
var parentShape = element.parent;
var businessObject = element.businessObject,

View File

@ -0,0 +1,206 @@
import inherits from 'inherits';
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
import { is } from '../../../util/ModelUtil';
import { isAny } from '../util/ModelingUtil';
import UpdateSemanticParentHandler from '../cmd/UpdateSemanticParentHandler';
/**
* BPMN specific data store behavior
*/
export default function DataStoreBehavior(
canvas, commandStack, elementRegistry,
eventBus) {
CommandInterceptor.call(this, eventBus);
commandStack.registerHandler('dataStore.updateContainment', UpdateSemanticParentHandler);
function getFirstParticipant() {
return elementRegistry.filter(function(element) {
return is(element, 'bpmn:Participant');
})[0];
}
function getDataStores(element) {
return element.children.filter(function(child) {
return is(child, 'bpmn:DataStoreReference') && !child.labelTarget;
});
}
function updateDataStoreParent(dataStore, newDataStoreParent) {
var dataStoreBo = dataStore.businessObject || dataStore;
newDataStoreParent = newDataStoreParent || getFirstParticipant();
if (newDataStoreParent) {
var newDataStoreParentBo = newDataStoreParent.businessObject || newDataStoreParent;
commandStack.execute('dataStore.updateContainment', {
dataStoreBo: dataStoreBo,
newSemanticParent: newDataStoreParentBo.processRef || newDataStoreParentBo,
newDiParent: newDataStoreParentBo.di
});
}
}
// disable auto-resize for data stores
this.preExecute('shape.create', function(event) {
var context = event.context,
shape = context.shape;
if (is(shape, 'bpmn:DataStoreReference') &&
shape.type !== 'label') {
if (!context.hints) {
context.hints = {};
}
// prevent auto resizing
context.hints.autoResize = false;
}
});
// disable auto-resize for data stores
this.preExecute('elements.move', function(event) {
var context = event.context,
shapes = context.shapes;
var dataStoreReferences = shapes.filter(function(shape) {
return is(shape, 'bpmn:DataStoreReference');
});
if (dataStoreReferences.length) {
if (!context.hints) {
context.hints = {};
}
// prevent auto resizing for data store references
context.hints.autoResize = shapes.filter(function(shape) {
return !is(shape, 'bpmn:DataStoreReference');
});
}
});
// update parent on data store created
this.postExecute('shape.create', function(event) {
var context = event.context,
shape = context.shape,
parent = shape.parent;
if (is(shape, 'bpmn:DataStoreReference') &&
shape.type !== 'label' &&
is(parent, 'bpmn:Collaboration')) {
updateDataStoreParent(shape);
}
});
// update parent on data store moved
this.postExecute('shape.move', function(event) {
var context = event.context,
shape = context.shape,
oldParent = context.oldParent,
parent = shape.parent;
if (is(oldParent, 'bpmn:Collaboration')) {
// do nothing if not necessary
return;
}
if (is(shape, 'bpmn:DataStoreReference') &&
shape.type !== 'label' &&
is(parent, 'bpmn:Collaboration')) {
var participant = is(oldParent, 'bpmn:Participant') ?
oldParent :
getAncestor(oldParent, 'bpmn:Participant');
updateDataStoreParent(shape, participant);
}
});
// update data store parents on participant deleted
this.postExecute('shape.delete', function(event) {
var context = event.context,
shape = context.shape,
rootElement;
if (isAny(shape, [ 'bpmn:Participant', 'bpmn:SubProcess' ])) {
rootElement = canvas.getRootElement();
getDataStores(rootElement)
.filter(function(dataStore) {
return isDescendant(dataStore, shape);
})
.forEach(updateDataStoreParent);
}
});
// update data store parents on collaboration -> process
this.postExecute('canvas.updateRoot', function(event) {
var context = event.context,
oldRoot = context.oldRoot,
newRoot = context.newRoot;
var dataStores = getDataStores(oldRoot);
dataStores.forEach(function(dataStore) {
if (is(newRoot, 'bpmn:Process')) {
updateDataStoreParent(dataStore, newRoot);
}
});
});
}
DataStoreBehavior.$inject = [
'canvas',
'commandStack',
'elementRegistry',
'eventBus',
];
inherits(DataStoreBehavior, CommandInterceptor);
// helpers //////////
function isDescendant(descendant, ancestor) {
var descendantBo = descendant.businessObject || descendant,
ancestorBo = ancestor.businessObject || ancestor;
while (descendantBo.$parent) {
if (descendantBo.$parent === ancestorBo.processRef || ancestorBo) {
return true;
}
descendantBo = descendantBo.$parent;
}
return false;
}
function getAncestor(element, type) {
while (element.parent) {
if (is(element.parent, type)) {
return element.parent;
}
element = element.parent;
}
}

View File

@ -5,6 +5,7 @@ import CreateBoundaryEventBehavior from './CreateBoundaryEventBehavior';
import CreateDataObjectBehavior from './CreateDataObjectBehavior';
import CreateParticipantBehavior from './CreateParticipantBehavior';
import DataInputAssociationBehavior from './DataInputAssociationBehavior';
import DataStoreBehavior from './DataStoreBehavior';
import DeleteLaneBehavior from './DeleteLaneBehavior';
import DropOnFlowBehavior from './DropOnFlowBehavior';
import ImportDockingFix from './ImportDockingFix';
@ -27,6 +28,7 @@ export default {
'copyPasteBehavior',
'createBoundaryEventBehavior',
'createDataObjectBehavior',
'dataStoreBehavior',
'createParticipantBehavior',
'dataInputAssociationBehavior',
'deleteLaneBehavior',
@ -51,6 +53,7 @@ export default {
createDataObjectBehavior: [ 'type', CreateDataObjectBehavior ],
createParticipantBehavior: [ 'type', CreateParticipantBehavior ],
dataInputAssociationBehavior: [ 'type', DataInputAssociationBehavior ],
dataStoreBehavior: [ 'type', DataStoreBehavior ],
deleteLaneBehavior: [ 'type', DeleteLaneBehavior ],
dropOnFlowBehavior: [ 'type', DropOnFlowBehavior ],
importDockingFix: [ 'type', ImportDockingFix ],

View File

@ -0,0 +1,34 @@
export default function UpdateSemanticParentHandler(bpmnUpdater) {
this._bpmnUpdater = bpmnUpdater;
}
UpdateSemanticParentHandler.$inject = [ 'bpmnUpdater' ];
UpdateSemanticParentHandler.prototype.execute = function(context) {
var dataStoreBo = context.dataStoreBo,
newSemanticParent = context.newSemanticParent,
newDiParent = context.newDiParent;
context.oldSemanticParent = dataStoreBo.$parent;
context.oldDiParent = dataStoreBo.di.$parent;
// update semantic parent
this._bpmnUpdater.updateSemanticParent(dataStoreBo, newSemanticParent);
// update DI parent
this._bpmnUpdater.updateDiParent(dataStoreBo.di, newDiParent);
};
UpdateSemanticParentHandler.prototype.revert = function(context) {
var dataStoreBo = context.dataStoreBo,
oldSemanticParent = context.oldSemanticParent,
oldDiParent = context.oldDiParent;
// update semantic parent
this._bpmnUpdater.updateSemanticParent(dataStoreBo, oldSemanticParent);
// update DI parent
this._bpmnUpdater.updateDiParent(dataStoreBo.di, oldDiParent);
};

View File

@ -464,7 +464,7 @@ function canDrop(element, target, position) {
// drop flow elements onto flow element containers
// and participants
if (is(element, 'bpmn:FlowElement')) {
if (is(element, 'bpmn:FlowElement') && !is(element, 'bpmn:DataStoreReference')) {
if (is(target, 'bpmn:FlowElementsContainer')) {
return isExpanded(target);
}
@ -476,7 +476,7 @@ function canDrop(element, target, position) {
// rendered and moved to top (Process or Collaboration level)
//
// artifacts may be placed wherever, too
if (isAny(element, [ 'bpmn:Artifact', 'bpmn:DataAssociation' ])) {
if (isAny(element, [ 'bpmn:Artifact', 'bpmn:DataAssociation', 'bpmn:DataStoreReference' ])) {
return isAny(target, [
'bpmn:Collaboration',
'bpmn:Lane',

View File

@ -12,6 +12,10 @@ import {
getExternalLabelBounds
} from '../util/LabelUtil';
import {
getMid
} from 'diagram-js/lib/layout/LayoutUtil';
import {
isExpanded
} from '../util/DiUtil';
@ -126,6 +130,14 @@ BpmnImporter.prototype.add = function(semantic, parentElement) {
parentIndex = 0;
}
if (is(semantic, 'bpmn:DataStoreReference')) {
// check wether data store is inside our outside of its semantic parent
if (!isPointInsideBBox(parentElement, getMid(bounds))) {
parentElement = this._canvas.getRootElement();
}
}
this._canvas.addShape(element, parentElement, parentIndex);
}
@ -326,4 +338,14 @@ function getLayoutedBounds(bounds, text, textUtil) {
width: Math.ceil(layoutedLabelDimensions.width),
height: Math.ceil(layoutedLabelDimensions.height)
};
}
function isPointInsideBBox(bbox, point) {
var x = point.x,
y = point.y;
return x >= bbox.x &&
x <= bbox.x + bbox.width &&
y >= bbox.y &&
y <= bbox.y + bbox.height;
}

View File

@ -0,0 +1,22 @@
<?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" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.15.0-dev" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
<bpmn:collaboration id="Collaboration">
<bpmn:participant id="Participant" processRef="Process" />
</bpmn:collaboration>
<bpmn:process id="Process" isExecutable="false">
<bpmn:dataStoreReference id="DataStoreReference" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration">
<bpmndi:BPMNShape id="Participant_di" bpmnElement="Participant" isHorizontal="false">
<dc:Bounds x="42" y="46" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_0acedkc_di" bpmnElement="DataStoreReference">
<dc:Bounds x="100" y="100" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="78" y="122" width="90" height="12" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,22 @@
<?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" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.15.0-dev" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
<bpmn:collaboration id="Collaboration">
<bpmn:participant id="Participant" processRef="Process" />
</bpmn:collaboration>
<bpmn:process id="Process" isExecutable="false">
<bpmn:dataStoreReference id="DataStoreReference" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration">
<bpmndi:BPMNShape id="Participant_di" bpmnElement="Participant" isHorizontal="false">
<dc:Bounds x="42" y="46" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_0acedkc_di" bpmnElement="DataStoreReference">
<dc:Bounds x="42" y="350" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="67" y="402" width="0" height="12" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,27 @@
<?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" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.15.0-dev" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
<bpmn:collaboration id="Collaboration">
<bpmn:participant id="Participant" processRef="Process" />
</bpmn:collaboration>
<bpmn:process id="Process" isExecutable="false">
<bpmn:subProcess id="SubProcess">
<bpmn:dataStoreReference id="DataStoreReference" />
</bpmn:subProcess>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration">
<bpmndi:BPMNShape id="Participant_di" bpmnElement="Participant" isHorizontal="false">
<dc:Bounds x="42" y="46" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_0acedkc_di" bpmnElement="DataStoreReference">
<dc:Bounds x="42" y="346" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="20" y="368" width="90" height="12" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="SubProcess_1x9ru5n_di" bpmnElement="SubProcess" isExpanded="true">
<dc:Bounds x="261" y="71" width="350" height="200" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,27 @@
<?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_0oawaw3" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.14.0">
<bpmn:collaboration id="Collaboration_1ymmlly">
<bpmn:participant id="Participant_1" processRef="Process_1" />
<bpmn:participant id="Participant_2" processRef="Process_2" />
</bpmn:collaboration>
<bpmn:process id="Process_1" isExecutable="true">
<bpmn:dataStoreReference id="DataStoreReference" />
</bpmn:process>
<bpmn:process id="Process_2" isExecutable="false" />
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1ymmlly">
<bpmndi:BPMNShape id="Participant_0xpjksb_di" bpmnElement="Participant_1">
<dc:Bounds x="0" y="0" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_18lkqyt_di" bpmnElement="Participant_2">
<dc:Bounds x="0" y="300" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_17mkq6m_di" bpmnElement="DataStoreReference">
<dc:Bounds x="200" y="100" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="240" y="120" width="0" height="12" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,71 @@
import {
bootstrapModeler,
inject
} from 'test/TestHelper';
import modelingModule from 'lib/features/modeling';
import coreModule from 'lib/core';
describe('features/modeling/behavior - update semantic parent', function() {
var diagramXML = require('./UpdateSemanticParent.bpmn');
var participant1Bo, participant2Bo, dataStoreBo;
beforeEach(bootstrapModeler(diagramXML, {
modules: [
coreModule,
modelingModule
]
}));
beforeEach(inject(function(commandStack, elementRegistry) {
var participant1 = elementRegistry.get('Participant_1'),
participant2 = elementRegistry.get('Participant_2'),
dataStore = elementRegistry.get('DataStoreReference');
participant1Bo = participant1.businessObject;
participant2Bo = participant2.businessObject;
dataStoreBo = dataStore.businessObject;
// when
commandStack.execute('dataStore.updateContainment', {
dataStoreBo: dataStoreBo,
newSemanticParent: participant2Bo.processRef,
newDiParent: participant2Bo.di
});
}));
it('should do', function() {
// then
expect(dataStoreBo.$parent).to.eql(participant2Bo.processRef);
expect(dataStoreBo.di.$parent).to.eql(participant2Bo.di.$parent);
});
it('should undo', inject(function(commandStack) {
// when
commandStack.undo();
// then
expect(dataStoreBo.$parent).to.eql(participant1Bo.processRef);
expect(dataStoreBo.di.$parent).to.eql(participant1Bo.di.$parent);
}));
it('should redo', inject(function(commandStack) {
// when
commandStack.undo();
commandStack.redo();
// then
expect(dataStoreBo.$parent).to.eql(participant2Bo.processRef);
expect(dataStoreBo.di.$parent).to.eql(participant2Bo.di.$parent);
}));
});

View File

@ -1,27 +1,47 @@
<?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" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" id="Definitions_1" exporter="camunda modeler" exporterVersion="2.6.0" targetNamespace="http://bpmn.io/schema/bpmn">
<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" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.15.0-dev" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
<bpmn:collaboration id="Collaboration">
<bpmn:participant id="Participant" processRef="Process"/>
<bpmn:participant id="Participant" processRef="Process" />
<bpmn:participant id="Participant_2" processRef="Process_2" />
</bpmn:collaboration>
<bpmn:process id="Process" isExecutable="false">
<bpmn:subProcess id="SubProcess">
<bpmn:dataStoreReference id="DataStoreReference"/>
<bpmn:dataStoreReference id="DataStoreReference" />
</bpmn:subProcess>
</bpmn:process>
<bpmn:process id="Process_2" isExecutable="false">
<bpmn:dataStoreReference id="DataStoreReference_2" />
<bpmn:dataStoreReference id="DataStoreReference_3" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration">
<bpmndi:BPMNShape id="Participant_di" bpmnElement="Participant" isHorizontal="false">
<dc:Bounds height="250.0" width="600.0" x="42.0" y="46.0"/>
<dc:Bounds x="42" y="46" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="SubProcess_di" bpmnElement="SubProcess" isExpanded="true">
<dc:Bounds height="200.0" width="350.0" x="260.0" y="73.0"/>
<dc:Bounds x="260" y="73" width="350" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_di" bpmnElement="DataStoreReference">
<dc:Bounds height="50.0" width="50.0" x="395.0" y="195.0"/>
<dc:Bounds x="400" y="200" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds height="20.0" width="90.0" x="375.0" y="245.0"/>
<dc:Bounds x="375" y="245" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_066vvzt_di" bpmnElement="Participant_2">
<dc:Bounds x="42" y="514" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_01wsbcu_di" bpmnElement="DataStoreReference_2">
<dc:Bounds x="150" y="600" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="180.5438596491228" y="685.7462887989204" width="0" height="12" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_135tyw7_di" bpmnElement="DataStoreReference_3">
<dc:Bounds x="500" y="400" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="617" y="478" width="0" height="12" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
</bpmn:definitions>

View File

@ -0,0 +1,22 @@
<?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" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.15.0-dev" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
<bpmn:collaboration id="Collaboration">
<bpmn:participant id="Participant" processRef="Process" />
</bpmn:collaboration>
<bpmn:process id="Process" isExecutable="false">
<bpmn:dataStoreReference id="DataStoreReference" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration">
<bpmndi:BPMNShape id="Participant_di" bpmnElement="Participant" isHorizontal="false">
<dc:Bounds x="42" y="46" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_0acedkc_di" bpmnElement="DataStoreReference">
<dc:Bounds x="42" y="350" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="67" y="402" width="0" height="12" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,16 @@
<?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_1pdhhel" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.15.0-dev">
<bpmn:process id="Process_1" isExecutable="true">
<bpmn:dataStoreReference id="DataStoreReference" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="DataStoreReference_0sw86lk_di" bpmnElement="DataStoreReference">
<dc:Bounds x="0" y="0" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="25" y="54" width="0" height="12" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,27 @@
<?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" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.15.0-dev" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
<bpmn:collaboration id="Collaboration">
<bpmn:participant id="Participant" processRef="Process" />
<bpmn:participant id="Participant_2" processRef="Process_2" />
</bpmn:collaboration>
<bpmn:process id="Process" isExecutable="false">
<bpmn:dataStoreReference id="DataStoreReference" />
</bpmn:process>
<bpmn:process id="Process_2" isExecutable="false" />
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration">
<bpmndi:BPMNShape id="Participant_di" bpmnElement="Participant" isHorizontal="false">
<dc:Bounds x="42" y="46" width="600" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_di" bpmnElement="DataStoreReference">
<dc:Bounds x="42" y="375" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="22" y="425" width="90" height="20" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_066vvzt_di" bpmnElement="Participant_2">
<dc:Bounds x="50" y="500" width="600" height="250" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -69,6 +69,32 @@ describe('features/modeling/behavior - data store', function() {
expect(dataStoreReference.dataStoreRef).not.to.exist;
}));
it('should create DataStoreReference on collaboration', inject(function(elementRegistry, modeling, bpmnjs) {
// give
var collaborationElement = elementRegistry.get('Collaboration'),
participantElement = elementRegistry.get('Participant'),
participantBo = participantElement.businessObject;
// when
var dataStoreShape = modeling.createShape(
{ type: 'bpmn:DataStoreReference' },
{ x: 420, y: 370 },
collaborationElement
);
var dataStoreReference = dataStoreShape.businessObject;
// then
// reference correctly wired
expect(dataStoreReference.$parent).to.eql(participantBo.processRef);
expect(participantBo.processRef.flowElements).to.contain(dataStoreReference);
// no actual data store created
expect(dataStoreReference.dataStoreRef).not.to.exist;
}));
});
@ -79,7 +105,7 @@ describe('features/modeling/behavior - data store', function() {
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
it('should move DataStoreReference', inject(function(elementRegistry, modeling, bpmnjs) {
it('should move DataStoreReference to Participant', inject(function(elementRegistry, modeling, bpmnjs) {
// give
var participantElement = elementRegistry.get('Participant'),
@ -91,11 +117,70 @@ describe('features/modeling/behavior - data store', function() {
modeling.moveElements([ dataStoreReference ], { x: -200, y: 0 }, participantElement);
// then
// reference correctly wired
expect(dataStoreReference.parent).to.eql(participantElement);
expect(dataStoreReferenceBo.$parent).to.eql(participantBo.processRef);
}));
it('should move DataStoreReference from partipant to Collaboration keeping parent particpant', inject(
function(elementRegistry, modeling, bpmnjs) {
// give
var collaborationElement = elementRegistry.get('Collaboration'),
participant2Element = elementRegistry.get('Participant_2'),
participant2Bo = participant2Element.businessObject,
dataStoreReference2 = elementRegistry.get('DataStoreReference_2'),
dataStoreReference2Bo = dataStoreReference2.businessObject;
// when
modeling.moveElements([ dataStoreReference2 ], { x: 0, y: 250 }, collaborationElement);
// then
expect(dataStoreReference2.parent).to.eql(collaborationElement);
expect(dataStoreReference2Bo.$parent).to.eql(participant2Bo.processRef);
})
);
it('should move DataStoreReference from subprocess to Collaboration keeping parent particpant', inject(
function(elementRegistry, modeling, bpmnjs) {
// give
var collaborationElement = elementRegistry.get('Collaboration'),
participantElement = elementRegistry.get('Participant'),
participantBo = participantElement.businessObject,
dataStoreReference = elementRegistry.get('DataStoreReference'),
dataStoreReferenceBo = dataStoreReference.businessObject;
// when
modeling.moveElements([ dataStoreReference ], { x: 0, y: 250 }, collaborationElement);
// then
expect(dataStoreReference.parent).to.eql(collaborationElement);
expect(dataStoreReferenceBo.$parent).to.eql(participantBo.processRef);
})
);
it('should move without changing parent', inject(
function(elementRegistry, modeling, bpmnjs) {
// give
var collaborationElement = elementRegistry.get('Collaboration'),
participant2Element = elementRegistry.get('Participant_2'),
participant2Bo = participant2Element.businessObject,
dataStoreReference3 = elementRegistry.get('DataStoreReference_3'),
dataStoreReference3Bo = dataStoreReference3.businessObject;
// when
modeling.moveElements([ dataStoreReference3 ], { x: 50, y: 0 }, collaborationElement);
// then
expect(dataStoreReference3.parent).to.eql(collaborationElement);
expect(dataStoreReference3Bo.$parent).to.eql(participant2Bo.processRef);
})
);
});
@ -226,4 +311,166 @@ describe('features/modeling/behavior - data store', function() {
});
describe('collaboration', function() {
describe('update parent on participant removed', function() {
var processDiagramXML = require('./DataStoreBehavior.remove-participant.bpmn');
var dataStoreReferenceBo,
participantBo,
participant2Bo;
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
beforeEach(inject(function(elementRegistry, modeling) {
// given
var participantElement = elementRegistry.get('Participant'),
participant2Element = elementRegistry.get('Participant_2'),
dataStoreReference = elementRegistry.get('DataStoreReference');
dataStoreReferenceBo = dataStoreReference.businessObject;
participantBo = participantElement.businessObject;
participant2Bo = participant2Element.businessObject;
// when
modeling.removeShape(participantElement);
}));
it('should do', function() {
// then
expect(dataStoreReferenceBo.$parent).to.eql(participant2Bo.processRef);
});
it('should undo', inject(function(commandStack) {
// when
commandStack.undo();
// then
expect(dataStoreReferenceBo.$parent).to.eql(participantBo.processRef);
}));
it('should redo', inject(function(commandStack) {
// when
commandStack.undo();
commandStack.redo();
// then
expect(dataStoreReferenceBo.$parent).to.eql(participant2Bo.processRef);
}));
});
describe('collaboration -> process', function() {
var processDiagramXML = require('./DataStoreBehavior.collaboration.bpmn');
var dataStoreShape,
participant;
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
beforeEach(inject(function(elementRegistry, modeling) {
dataStoreShape = elementRegistry.get('DataStoreReference');
participant = elementRegistry.get('Participant');
// when
modeling.removeShape(participant);
}));
it('should do', inject(function(canvas) {
var rootElement = canvas.getRootElement();
// then
expect(dataStoreShape.businessObject.$parent).to.eql(rootElement.businessObject);
}));
it('should undo', inject(function(canvas, commandStack) {
// when
commandStack.undo();
// then
expect(dataStoreShape.businessObject.$parent).to.eql(participant.businessObject.processRef);
}));
it('should redo', inject(function(canvas, commandStack) {
var rootElement = canvas.getRootElement();
// when
commandStack.undo();
commandStack.redo();
// then
expect(dataStoreShape.businessObject.$parent).to.eql(rootElement.businessObject);
}));
});
describe('process -> collaboration', function() {
var processDiagramXML = require('./DataStoreBehavior.process.bpmn');
var dataStoreShape,
participant,
process;
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
beforeEach(inject(function(canvas, elementRegistry, modeling) {
process = canvas.getRootElement();
dataStoreShape = elementRegistry.get('DataStoreReference');
// when
participant = modeling.createShape(
{ type: 'bpmn:Participant' },
{ x: 200, y: 200 },
process
);
}));
it('should do', function() {
// then
expect(dataStoreShape.businessObject.$parent).to.eql(participant.businessObject.processRef);
});
it('should undo', inject(function(commandStack) {
// when
commandStack.undo();
// then
expect(dataStoreShape.businessObject.$parent).to.eql(process.businessObject);
}));
it('should redo', inject(function(commandStack) {
// when
commandStack.undo();
commandStack.redo();
// then
expect(dataStoreShape.businessObject.$parent).to.eql(participant.businessObject.processRef);
}));
});
});
});

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:bpmn2="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="_biH3sOTeEeS2YerRfpjPrw" targetNamespace="http://activiti.org/bpmn" exporter="camunda modeler" exporterVersion="2.6.0" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
<bpmn2:definitions xmlns:bpmn2="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:xsi="http://www.w3.org/2001/XMLSchema-instance" id="_biH3sOTeEeS2YerRfpjPrw" targetNamespace="http://camunda.org/schema/1.0/bpmn" exporter="Camunda Modeler" exporterVersion="1.14.0" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
<bpmn2:collaboration id="Collaboration">
<bpmn2:participant id="Participant" name="Pool" processRef="Process" />
<bpmn2:participant id="OtherParticipant" name="Pool" processRef="OtherProcess" />
@ -38,6 +38,7 @@
</bpmn2:process>
<bpmn2:process id="OtherProcess" isExecutable="false">
<bpmn2:task id="Task_in_OtherParticipant" />
<bpmn2:dataStoreReference id="DataStoreReference" />
<bpmn2:textAnnotation id="TextAnnotation_OtherParticipant" />
</bpmn2:process>
<bpmn2:process id="Process_18q5tmq" isExecutable="false" />
@ -133,6 +134,12 @@
<bpmndi:BPMNShape id="Participant_09perow_di" bpmnElement="CollapsedParticipant">
<dc:Bounds x="125" y="704" width="594" height="117" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_09caypn_di" bpmnElement="DataStoreReference">
<dc:Bounds x="671.8233151183972" y="480" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="696.8233151183972" y="534" width="0" height="12" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

View File

@ -916,6 +916,12 @@ describe('features/modeling/rules - BpmnRules', function() {
expectCanDrop('TextAnnotation_Global', 'Participant', true);
}));
it('drop DataStoreReference -> Collaboration', function() {
expectCanDrop('DataStoreReference', 'Collaboration', true);
});
it('drop element -> collapsed Participant', inject(function(canvas) {
expectCanDrop('StartEvent_None', 'CollapsedParticipant', false);
expectCanDrop('SubProcess', 'CollapsedParticipant', false);
@ -1091,6 +1097,7 @@ describe('features/modeling/rules - BpmnRules', function() {
}));
});
describe('event move', function() {
var testXML = require('../../../fixtures/bpmn/boundary-events.bpmn');

View File

@ -316,6 +316,69 @@ describe('import - Importer', function() {
});
});
it('should import data store as child of participant', function(done) {
// given
var xml = require('../../fixtures/bpmn/import/data-store.inside-participant.bpmn');
var events = {};
// log events
diagram.get('eventBus').on('bpmnElement.added', function(e) {
events[e.element.id] = e.element;
});
runImport(diagram, xml, function(err, warnings) {
expect(events.DataStoreReference.parent).to.equal(events.Participant);
done(err);
});
});
it('should import data store in particpant as child of collaboration', function(done) {
// given
var xml = require('../../fixtures/bpmn/import/data-store.outside-participant.participant.bpmn');
var events = {};
// log events
diagram.get('eventBus').on('bpmnElement.added', function(e) {
events[e.element.id] = e.element;
});
runImport(diagram, xml, function(err, warnings) {
expect(events.DataStoreReference.parent).to.equal(events.Collaboration);
done(err);
});
});
it('should import data store in subprocess as child of collaboration', function(done) {
// given
var xml = require('../../fixtures/bpmn/import/data-store.outside-participant.subprocess.bpmn');
var events = {};
// log events
diagram.get('eventBus').on('bpmnElement.added', function(e) {
events[e.element.id] = e.element;
});
runImport(diagram, xml, function(err, warnings) {
expect(events.DataStoreReference.parent).to.equal(events.Collaboration);
done(err);
});
});
});