Skip to content

Commit

Permalink
fix: correctly remove vertical lanes
Browse files Browse the repository at this point in the history
Closes #2082

---------

Co-authored-by: Maciej Barelkowski <[email protected]>
  • Loading branch information
sombrek and barmac authored Jan 22, 2024
1 parent 0a706be commit df2ae05
Show file tree
Hide file tree
Showing 3 changed files with 257 additions and 7 deletions.
59 changes: 52 additions & 7 deletions lib/features/modeling/behavior/DeleteLaneBehavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import {
getChildLanes
} from '../util/LaneUtil';

import {
isHorizontal
} from '../../../util/DiUtil';

import {
eachElement
} from 'diagram-js/lib/util/Elements';
Expand All @@ -32,18 +36,29 @@ export default function DeleteLaneBehavior(eventBus, spaceTool) {


function compensateLaneDelete(shape, oldParent) {
var isHorizontalLane = isHorizontal(shape);

var siblings = getChildLanes(oldParent);

var topAffected = [];
var bottomAffected = [];
var leftAffected = [];
var rightAffected = [];

eachElement(siblings, function(element) {

if (element.y > shape.y) {
bottomAffected.push(element);
if (isHorizontalLane) {
if (element.y > shape.y) {
bottomAffected.push(element);
} else {
topAffected.push(element);
}
} else {
topAffected.push(element);
if (element.x > shape.x) {
rightAffected.push(element);
} else {
leftAffected.push(element);
}
}

return element.children;
Expand All @@ -55,14 +70,24 @@ export default function DeleteLaneBehavior(eventBus, spaceTool) {

var offset;

if (bottomAffected.length && topAffected.length) {
offset = shape.height / 2;
if (isHorizontalLane) {
if (bottomAffected.length && topAffected.length) {
offset = shape.height / 2;
} else {
offset = shape.height;
}
} else {
offset = shape.height;
if (rightAffected.length && leftAffected.length) {
offset = shape.width / 2;
} else {
offset = shape.width;
}
}

var topAdjustments,
bottomAdjustments;
bottomAdjustments,
leftAdjustments,
rightAdjustments;

if (topAffected.length) {
topAdjustments = spaceTool.calculateAdjustments(
Expand All @@ -83,6 +108,26 @@ export default function DeleteLaneBehavior(eventBus, spaceTool) {
bottomAdjustments.resizingShapes,
{ x: 0, y: -offset }, 'n');
}

if (leftAffected.length) {
leftAdjustments = spaceTool.calculateAdjustments(
leftAffected, 'x', offset, shape.x - 10);

spaceTool.makeSpace(
leftAdjustments.movingShapes,
leftAdjustments.resizingShapes,
{ x: offset, y: 0 }, 'e');
}

if (rightAffected.length) {
rightAdjustments = spaceTool.calculateAdjustments(
rightAffected, 'x', -offset, shape.x + shape.width + 10);

spaceTool.makeSpace(
rightAdjustments.movingShapes,
rightAdjustments.resizingShapes,
{ x: -offset, y: 0 }, 'w');
}
}


Expand Down
112 changes: 112 additions & 0 deletions test/spec/features/modeling/lanes/DeleteLaneSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,118 @@ describe('features/modeling - delete lane', function() {
});


describe('features/modeling - delete vertical lane', function() {

var diagramXML = require('./lanes.vertical.bpmn');

var testModules = [ coreModule, modelingModule ];

beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));


it('should remove first Lane', inject(function(elementRegistry, modeling) {

// given
var laneShape = elementRegistry.get('Vertical_Lane_A'),
rightSideLaneShape = elementRegistry.get('Vertical_Lane_B'),
rightSideLaneBounds = getBounds(rightSideLaneShape);

// when
modeling.removeShape(laneShape);

// then
expect(rightSideLaneShape).to.have.bounds({
x: rightSideLaneBounds.x - laneShape.width,
y: rightSideLaneBounds.y,
width: rightSideLaneBounds.width + laneShape.width,
height: rightSideLaneBounds.height
});

}));


it('should remove last Lane', inject(function(elementRegistry, modeling) {

// given
var laneShape = elementRegistry.get('Vertical_Lane_B'),
leftSideLaneShape = elementRegistry.get('Vertical_Lane_A'),
leftSideLaneBounds = getBounds(leftSideLaneShape);

// when
modeling.removeShape(laneShape);

// then
expect(leftSideLaneShape).to.have.bounds({
x: leftSideLaneBounds.x,
y: leftSideLaneBounds.y,
width: leftSideLaneBounds.width + laneShape.width,
height: leftSideLaneBounds.height
});

}));


describe('three lanes', function() {

it('should remove middle Lane', inject(function(elementRegistry, modeling) {

// given
var laneShape = elementRegistry.get('Nested_Vertical_Lane_B'),
leftSideLaneShape = elementRegistry.get('Nested_Vertical_Lane_A'),
leftSideLaneBounds = getBounds(leftSideLaneShape),
rightSideLaneShape = elementRegistry.get('Nested_Vertical_Lane_C'),
rightSideLaneBounds = getBounds(rightSideLaneShape);

// when
modeling.removeShape(laneShape);

// then
expect(leftSideLaneShape).to.have.bounds({
x: leftSideLaneBounds.x,
y: leftSideLaneBounds.y,
width: leftSideLaneBounds.width + laneShape.width / 2,
height: leftSideLaneBounds.height
});

expect(rightSideLaneShape).to.have.bounds({
x: rightSideLaneBounds.x - laneShape.width / 2,
y: rightSideLaneBounds.y,
width: rightSideLaneBounds.width + laneShape.width / 2,
height: rightSideLaneBounds.height
});

}));


it('should remove first Lane', inject(function(elementRegistry, modeling) {

// given
var laneShape = elementRegistry.get('Nested_Vertical_Lane_A'),
rightSideLaneShape = elementRegistry.get('Nested_Vertical_Lane_B'),
rightSideLaneBounds = getBounds(rightSideLaneShape),
lastLaneShape = elementRegistry.get('Nested_Vertical_Lane_C'),
lastLaneBounds = getBounds(lastLaneShape);

// when
modeling.removeShape(laneShape);

// then
expect(rightSideLaneShape).to.have.bounds({
x: rightSideLaneBounds.x - laneShape.width,
y: rightSideLaneBounds.y,
width: rightSideLaneBounds.width + laneShape.width,
height: rightSideLaneBounds.height
});

expect(lastLaneShape).to.have.bounds(lastLaneBounds);

}));

});

});


// helpers ///////////////

function getBounds(element) {
Expand Down
93 changes: 93 additions & 0 deletions test/spec/features/modeling/lanes/lanes.vertical.bpmn
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?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" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" id="_4bAZoD9WEeWLcNBL4nCk1A" exporter="camunda modeler" exporterVersion="2.6.0" targetNamespace="http://camunda.org/schema/1.0/bpmn">
<bpmn2:collaboration id="_Collaboration_2">
<bpmn2:participant id="Vertical_Participant_Lane" name="Vertical_Participant_Lane" processRef="Process_Vertical_Lane" />
</bpmn2:collaboration>
<bpmn2:process id="Process_Vertical_Lane" isExecutable="false">
<bpmn2:laneSet id="LaneSet_1o2qvt0" name="Lane Set 1">
<bpmn2:lane id="Vertical_Lane_B" name="Vertical_Lane_B" />
<bpmn2:lane id="Vertical_Lane_A" name="Vertical_Lane_A">
<bpmn2:flowNodeRef>V_Task</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>V_Task_Boundary</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>V_Boundary</bpmn2:flowNodeRef>
<bpmn2:childLaneSet id="LaneSet_1nz9a4u">
<bpmn2:lane id="Nested_Vertical_Lane_C" name="Nested_Vertical_Lane_C" />
<bpmn2:lane id="Nested_Vertical_Lane_B" name="Nested_Vertical_Lane_B" />
<bpmn2:lane id="Nested_Vertical_Lane_A" name="Nested_Vertical_Lane_A">
<bpmn2:flowNodeRef>V_Task</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>V_Task_Boundary</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>V_Boundary</bpmn2:flowNodeRef>
</bpmn2:lane>
</bpmn2:childLaneSet>
</bpmn2:lane>
</bpmn2:laneSet>
<bpmn2:task id="V_Task" name="V_Task">
<bpmn2:incoming>Flow_V</bpmn2:incoming>
<bpmn2:incoming>Flow_From_V_Boundary</bpmn2:incoming>
</bpmn2:task>
<bpmn2:task id="V_Task_Boundary" name="V_Task_Boundary">
<bpmn2:outgoing>Flow_V</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:boundaryEvent id="V_Boundary" name="V_Boundary" attachedToRef="V_Task_Boundary">
<bpmn2:outgoing>Flow_From_V_Boundary</bpmn2:outgoing>
</bpmn2:boundaryEvent>
<bpmn2:sequenceFlow id="Flow_V" name="" sourceRef="V_Task_Boundary" targetRef="V_Task" />
<bpmn2:sequenceFlow id="Flow_From_V_Boundary" name="" sourceRef="V_Boundary" targetRef="V_Task" />
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="_Collaboration_2">
<bpmndi:BPMNShape id="BPMNShape_140jwaa" bpmnElement="Vertical_Participant_Lane" isHorizontal="false">
<dc:Bounds x="160" y="50" width="604" height="540" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_0n0ckvg" bpmnElement="Vertical_Lane_B" isHorizontal="false">
<dc:Bounds x="656" y="80" width="108" height="510" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_1xhgbhc" bpmnElement="Vertical_Lane_A" isHorizontal="false">
<dc:Bounds x="160" y="80" width="496" height="510" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_1vq767a" bpmnElement="Nested_Vertical_Lane_C" isHorizontal="false">
<dc:Bounds x="503" y="110" width="153" height="480" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_0zxz1a9" bpmnElement="Nested_Vertical_Lane_B" isHorizontal="false">
<dc:Bounds x="350" y="110" width="153" height="480" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_1dq00p8" bpmnElement="Nested_Vertical_Lane_A" isHorizontal="false">
<dc:Bounds x="160" y="110" width="190" height="480" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_0t1n94f" bpmnElement="V_Task">
<dc:Bounds x="190" y="330" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_0d8jcff" bpmnElement="V_Task_Boundary">
<dc:Bounds x="190" y="170" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_0ft8wdi" bpmnElement="V_Boundary">
<dc:Bounds x="272" y="212" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="259" y="253" width="62" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="BPMNEdge_0tb53a9" bpmnElement="Flow_V">
<di:waypoint x="240" y="250" />
<di:waypoint x="240" y="330" />
<bpmndi:BPMNLabel>
<dc:Bounds x="403" y="103" width="6" height="6" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_0yevmra" bpmnElement="Flow_From_V_Boundary">
<di:waypoint x="308" y="230" />
<di:waypoint x="320" y="230" />
<di:waypoint x="320" y="370" />
<di:waypoint x="290" y="370" />
<bpmndi:BPMNLabel>
<dc:Bounds x="377" y="188" width="6" height="6" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

0 comments on commit df2ae05

Please sign in to comment.