feat: reconnect message flows when collapsing participant
Related to camunda/camunda-modeler#1651
This commit is contained in:
parent
410beadae1
commit
4806507936
|
@ -0,0 +1,89 @@
|
||||||
|
import inherits from 'inherits';
|
||||||
|
|
||||||
|
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
|
||||||
|
|
||||||
|
import { is } from '../../../util/ModelUtil';
|
||||||
|
|
||||||
|
import { isExpanded } from '../../../util/DiUtil';
|
||||||
|
|
||||||
|
import { selfAndAllChildren } from 'diagram-js/lib/util/Elements';
|
||||||
|
|
||||||
|
import {
|
||||||
|
getResizedSourceAnchor,
|
||||||
|
getResizedTargetAnchor
|
||||||
|
} from 'diagram-js/lib/features/modeling/cmd/helper/AnchorsHelper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BPMN-specific message flow behavior.
|
||||||
|
*/
|
||||||
|
export default function MessageFlowBehavior(eventBus, modeling) {
|
||||||
|
|
||||||
|
CommandInterceptor.call(this, eventBus);
|
||||||
|
|
||||||
|
this.postExecute('shape.replace', function(context) {
|
||||||
|
var oldShape = context.oldShape,
|
||||||
|
newShape = context.newShape;
|
||||||
|
|
||||||
|
if (!isParticipantCollapse(oldShape, newShape)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var messageFlows = getMessageFlows(oldShape);
|
||||||
|
|
||||||
|
messageFlows.incoming.forEach(function(incoming) {
|
||||||
|
var anchor = getResizedTargetAnchor(incoming, newShape, oldShape);
|
||||||
|
|
||||||
|
modeling.reconnectEnd(incoming, newShape, anchor);
|
||||||
|
});
|
||||||
|
|
||||||
|
messageFlows.outgoing.forEach(function(outgoing) {
|
||||||
|
var anchor = getResizedSourceAnchor(outgoing, newShape, oldShape);
|
||||||
|
|
||||||
|
modeling.reconnectStart(outgoing, newShape, anchor);
|
||||||
|
});
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageFlowBehavior.$inject = [ 'eventBus', 'modeling' ];
|
||||||
|
|
||||||
|
inherits(MessageFlowBehavior, CommandInterceptor);
|
||||||
|
|
||||||
|
// helpers //////////
|
||||||
|
|
||||||
|
function isParticipantCollapse(oldShape, newShape) {
|
||||||
|
return is(oldShape, 'bpmn:Participant')
|
||||||
|
&& isExpanded(oldShape)
|
||||||
|
&& is(newShape, 'bpmn:Participant')
|
||||||
|
&& !isExpanded(newShape);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMessageFlows(parent) {
|
||||||
|
var elements = selfAndAllChildren([ parent ], false);
|
||||||
|
|
||||||
|
var incoming = [],
|
||||||
|
outgoing = [];
|
||||||
|
|
||||||
|
elements.forEach(function(element) {
|
||||||
|
if (element === parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
element.incoming.forEach(function(connection) {
|
||||||
|
if (is(connection, 'bpmn:MessageFlow')) {
|
||||||
|
incoming.push(connection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
element.outgoing.forEach(function(connection) {
|
||||||
|
if (is(connection, 'bpmn:MessageFlow')) {
|
||||||
|
outgoing.push(connection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
incoming: incoming,
|
||||||
|
outgoing: outgoing
|
||||||
|
};
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ import GroupBehavior from './GroupBehavior';
|
||||||
import ImportDockingFix from './ImportDockingFix';
|
import ImportDockingFix from './ImportDockingFix';
|
||||||
import IsHorizontalFix from './IsHorizontalFix';
|
import IsHorizontalFix from './IsHorizontalFix';
|
||||||
import LabelBehavior from './LabelBehavior';
|
import LabelBehavior from './LabelBehavior';
|
||||||
|
import MessageFlowBehavior from './MessageFlowBehavior';
|
||||||
import ModelingFeedback from './ModelingFeedback';
|
import ModelingFeedback from './ModelingFeedback';
|
||||||
import ReplaceConnectionBehavior from './ReplaceConnectionBehavior';
|
import ReplaceConnectionBehavior from './ReplaceConnectionBehavior';
|
||||||
import RemoveParticipantBehavior from './RemoveParticipantBehavior';
|
import RemoveParticipantBehavior from './RemoveParticipantBehavior';
|
||||||
|
@ -54,6 +55,7 @@ export default {
|
||||||
'importDockingFix',
|
'importDockingFix',
|
||||||
'isHorizontalFix',
|
'isHorizontalFix',
|
||||||
'labelBehavior',
|
'labelBehavior',
|
||||||
|
'messageFlowBehavior',
|
||||||
'modelingFeedback',
|
'modelingFeedback',
|
||||||
'removeElementBehavior',
|
'removeElementBehavior',
|
||||||
'removeParticipantBehavior',
|
'removeParticipantBehavior',
|
||||||
|
@ -88,6 +90,7 @@ export default {
|
||||||
importDockingFix: [ 'type', ImportDockingFix ],
|
importDockingFix: [ 'type', ImportDockingFix ],
|
||||||
isHorizontalFix: [ 'type', IsHorizontalFix ],
|
isHorizontalFix: [ 'type', IsHorizontalFix ],
|
||||||
labelBehavior: [ 'type', LabelBehavior ],
|
labelBehavior: [ 'type', LabelBehavior ],
|
||||||
|
messageFlowBehavior: [ 'type', MessageFlowBehavior ],
|
||||||
modelingFeedback: [ 'type', ModelingFeedback ],
|
modelingFeedback: [ 'type', ModelingFeedback ],
|
||||||
replaceConnectionBehavior: [ 'type', ReplaceConnectionBehavior ],
|
replaceConnectionBehavior: [ 'type', ReplaceConnectionBehavior ],
|
||||||
removeParticipantBehavior: [ 'type', RemoveParticipantBehavior ],
|
removeParticipantBehavior: [ 'type', RemoveParticipantBehavior ],
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:bioc="http://bpmn.io/schema/bpmn/biocolor/1.0" id="simple" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.7.0" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
|
||||||
|
<bpmn2:collaboration id="Collaboration_1">
|
||||||
|
<bpmn2:participant id="Participant_1" name="Participant_1" processRef="Process_1" />
|
||||||
|
<bpmn2:participant id="Participant_2" name="Participant_2" processRef="Process_2" />
|
||||||
|
<bpmn2:participant id="Participant_3" name="Participant_3" processRef="Process_3" />
|
||||||
|
<bpmn2:participant id="Participant_4" name="Participant_4" processRef="Process_4" />
|
||||||
|
<bpmn2:messageFlow id="Flow_2" name="Flow_2" sourceRef="Activity_3" targetRef="Activity_1" />
|
||||||
|
<bpmn2:messageFlow id="Flow_4" name="Flow_4" sourceRef="Activity_4" targetRef="Activity_3" />
|
||||||
|
<bpmn2:messageFlow id="Flow_3" name="Flow_3" sourceRef="Activity_4" targetRef="Activity_2" />
|
||||||
|
<bpmn2:messageFlow id="Flow_1" name="Flow_1" sourceRef="Activity_2" targetRef="Activity_1" />
|
||||||
|
</bpmn2:collaboration>
|
||||||
|
<bpmn2:process id="Process_1" isExecutable="false">
|
||||||
|
<bpmn2:task id="Activity_1" name="Activity_1" />
|
||||||
|
</bpmn2:process>
|
||||||
|
<bpmn2:process id="Process_2" isExecutable="false">
|
||||||
|
<bpmn2:task id="Activity_2" name="Activity_2" />
|
||||||
|
</bpmn2:process>
|
||||||
|
<bpmn2:process id="Process_3" isExecutable="false">
|
||||||
|
<bpmn2:task id="Activity_3" name="Activity_3" />
|
||||||
|
</bpmn2:process>
|
||||||
|
<bpmn2:process id="Process_4" isExecutable="false">
|
||||||
|
<bpmn2:task id="Activity_4" name="Activity_4" />
|
||||||
|
</bpmn2:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
|
||||||
|
<bpmndi:BPMNShape id="Participant_1xi2u59_di" bpmnElement="Participant_1" isHorizontal="true">
|
||||||
|
<dc:Bounds x="180" y="80" width="330" height="240" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_1ajk3x2_di" bpmnElement="Activity_1">
|
||||||
|
<dc:Bounds x="310" y="160" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Participant_1bs1k5p_di" bpmnElement="Participant_2" isHorizontal="true">
|
||||||
|
<dc:Bounds x="180" y="400" width="330" height="240" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_19rbcko_di" bpmnElement="Activity_2">
|
||||||
|
<dc:Bounds x="310" y="480" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Participant_1gev1ss_di" bpmnElement="Participant_3" isHorizontal="true">
|
||||||
|
<dc:Bounds x="610" y="400" width="330" height="240" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_0tq9cy6_di" bpmnElement="Activity_3">
|
||||||
|
<dc:Bounds x="740" y="480" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Participant_1r1lj0k_di" bpmnElement="Participant_4" isHorizontal="true">
|
||||||
|
<dc:Bounds x="610" y="720" width="330" height="240" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_18zqri6_di" bpmnElement="Activity_4">
|
||||||
|
<dc:Bounds x="740" y="800" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_10f8p6o_di" bpmnElement="Flow_2" bioc:stroke="#000" bioc:fill="#fff">
|
||||||
|
<di:waypoint x="790" y="480" />
|
||||||
|
<di:waypoint x="790" y="360" />
|
||||||
|
<di:waypoint x="370" y="360" />
|
||||||
|
<di:waypoint x="370" y="240" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="562" y="342" width="36" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_1hgc2dc_di" bpmnElement="Flow_4" bioc:stroke="#000" bioc:fill="#fff">
|
||||||
|
<di:waypoint x="800" y="800" />
|
||||||
|
<di:waypoint x="800" y="560" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="797" y="677" width="37" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0hj61b5_di" bpmnElement="Flow_3" bioc:stroke="#000" bioc:fill="#fff">
|
||||||
|
<di:waypoint x="780" y="800" />
|
||||||
|
<di:waypoint x="780" y="680" />
|
||||||
|
<di:waypoint x="360" y="680" />
|
||||||
|
<di:waypoint x="360" y="560" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="552" y="662" width="36" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_1oa1qkv_di" bpmnElement="Flow_1">
|
||||||
|
<di:waypoint x="350" y="480" />
|
||||||
|
<di:waypoint x="350" y="240" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="347" y="357" width="36" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn2:definitions>
|
|
@ -0,0 +1,151 @@
|
||||||
|
import {
|
||||||
|
bootstrapModeler,
|
||||||
|
inject
|
||||||
|
} from 'test/TestHelper';
|
||||||
|
|
||||||
|
import coreModule from 'lib/core';
|
||||||
|
import modelingModule from 'lib/features/modeling';
|
||||||
|
|
||||||
|
|
||||||
|
describe('features/modeling - message flow behavior', function() {
|
||||||
|
|
||||||
|
var testModules = [ coreModule, modelingModule ];
|
||||||
|
|
||||||
|
|
||||||
|
describe('when collapsing participant', function() {
|
||||||
|
|
||||||
|
var processDiagramXML = require('./MessageFlowBehavior.bpmn');
|
||||||
|
|
||||||
|
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
|
||||||
|
|
||||||
|
|
||||||
|
it('should reconnect message flows to collapsed participant (incoming)', inject(
|
||||||
|
function(bpmnReplace, elementRegistry) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var participant = elementRegistry.get('Participant_1');
|
||||||
|
|
||||||
|
// when
|
||||||
|
participant = bpmnReplace.replaceElement(participant, {
|
||||||
|
type: 'bpmn:Participant',
|
||||||
|
isExpanded: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(participant.incoming).to.have.length(2);
|
||||||
|
|
||||||
|
expect(elementRegistry.get('Flow_1').waypoints).to.eql([
|
||||||
|
{
|
||||||
|
original: {
|
||||||
|
x: 350,
|
||||||
|
y: 520
|
||||||
|
},
|
||||||
|
x: 350,
|
||||||
|
y: 480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
original: {
|
||||||
|
x: 350,
|
||||||
|
y: 110
|
||||||
|
},
|
||||||
|
x: 350,
|
||||||
|
y: 140
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(elementRegistry.get('Flow_2').waypoints).to.eql([
|
||||||
|
{
|
||||||
|
original: {
|
||||||
|
x: 790,
|
||||||
|
y: 520
|
||||||
|
},
|
||||||
|
x: 790,
|
||||||
|
y: 480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 790,
|
||||||
|
y: 360
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 370,
|
||||||
|
y: 360
|
||||||
|
},
|
||||||
|
{
|
||||||
|
original: {
|
||||||
|
x: 370,
|
||||||
|
y: 110
|
||||||
|
},
|
||||||
|
x: 370,
|
||||||
|
y: 140
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
it('should reconnect message flows to collapsed participant (outgoing)', inject(
|
||||||
|
function(bpmnReplace, elementRegistry) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var participant = elementRegistry.get('Participant_4');
|
||||||
|
|
||||||
|
// when
|
||||||
|
participant = bpmnReplace.replaceElement(participant, {
|
||||||
|
type: 'bpmn:Participant',
|
||||||
|
isExpanded: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(participant.outgoing).to.have.length(2);
|
||||||
|
|
||||||
|
expect(elementRegistry.get('Flow_3').waypoints).to.eql([
|
||||||
|
{
|
||||||
|
original: {
|
||||||
|
x: 780,
|
||||||
|
y: 750
|
||||||
|
},
|
||||||
|
x: 780,
|
||||||
|
y: 720
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 780,
|
||||||
|
y: 680
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 360,
|
||||||
|
y: 680
|
||||||
|
},
|
||||||
|
{
|
||||||
|
original: {
|
||||||
|
x: 360,
|
||||||
|
y: 520
|
||||||
|
},
|
||||||
|
x: 360,
|
||||||
|
y: 560
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(elementRegistry.get('Flow_4').waypoints).to.eql([
|
||||||
|
{
|
||||||
|
original: {
|
||||||
|
x: 800,
|
||||||
|
y: 750
|
||||||
|
},
|
||||||
|
x: 800,
|
||||||
|
y: 720
|
||||||
|
},
|
||||||
|
{
|
||||||
|
original: {
|
||||||
|
x: 800,
|
||||||
|
y: 520
|
||||||
|
},
|
||||||
|
x: 800,
|
||||||
|
y: 560
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -355,7 +355,7 @@ describe('features/replace - bpmn replace', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('should collapse pool, removing message flows', function() {
|
describe('should collapse pool, reconnecting message flows', function() {
|
||||||
|
|
||||||
var diagramXML = require('./BpmnReplace.poolMessageFlows.bpmn');
|
var diagramXML = require('./BpmnReplace.poolMessageFlows.bpmn');
|
||||||
|
|
||||||
|
@ -382,8 +382,8 @@ describe('features/replace - bpmn replace', function() {
|
||||||
expect(isExpanded(newShape)).to.be.false; // collapsed
|
expect(isExpanded(newShape)).to.be.false; // collapsed
|
||||||
expect(newShape.children).to.be.empty;
|
expect(newShape.children).to.be.empty;
|
||||||
|
|
||||||
expect(elementRegistry.get('MessageFlow_1')).not.to.exist;
|
expect(elementRegistry.get('MessageFlow_1')).to.exist;
|
||||||
expect(elementRegistry.get('MessageFlow_2')).not.to.exist;
|
expect(elementRegistry.get('MessageFlow_2')).to.exist;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue