Skip to content

Commit

Permalink
fix: add isForCompensation on connect
Browse files Browse the repository at this point in the history
Closes #2038
  • Loading branch information
smbea authored and barmac committed Dec 19, 2023
1 parent ae9a25e commit e568807
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 14 deletions.
78 changes: 78 additions & 0 deletions lib/features/modeling/behavior/CompensateBoundaryEventBehaviour.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import inherits from 'inherits-browser';

import { is } from '../../../util/ModelUtil';

import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
import { hasEventDefinition } from '../../../util/DiUtil';

/**
* @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
* @typedef {import('diagram-js/lib/features/modeling/Modeling').default} Modeling
*/

export default function CompensateBoundaryEventBehaviour(eventBus, modeling) {

CommandInterceptor.call(this, eventBus);

function addIsForCompensationProperty(source, target) {
if (isCompensationBoundaryEvent(source)) {
if (is(target, 'bpmn:Activity') && !isForCompensation(target)) {
modeling.updateProperties(target, { isForCompensation: true });
}
}
}

function removeIsForCompensationProperty(source, target) {
if (isCompensationBoundaryEvent(source)) {
if (is(target, 'bpmn:Activity') && isForCompensation(target)) {
modeling.updateProperties(target, { isForCompensation: false });
}
}
}

this.preExecute('connection.create', function(context) {
var source = context.source,
target = context.target;

addIsForCompensationProperty(source, target);
}, true);

this.postExecute('connection.reconnect', function(context) {
var newSource = context.newSource,
newTarget = context.newTarget,
oldSource = context.oldSource,
oldTarget = context.oldTarget;

// add `isForCompensation` to new target
addIsForCompensationProperty(newSource, newTarget);

// remove `isForCompensation` from old target
removeIsForCompensationProperty(oldSource, oldTarget);
}, true);

this.postExecute('connection.delete', function(context) {
var source = context.source,
target = context.target;

removeIsForCompensationProperty(source, target);
}, true);

}

inherits(CompensateBoundaryEventBehaviour, CommandInterceptor);

CompensateBoundaryEventBehaviour.$inject = [
'eventBus',
'modeling'
];

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

function isForCompensation(element) {
return element && element.businessObject.isForCompensation;
}

function isCompensationBoundaryEvent(element) {
return element && is(element, 'bpmn:BoundaryEvent') &&
hasEventDefinition(element, 'bpmn:CompensateEventDefinition');
}
3 changes: 3 additions & 0 deletions lib/features/modeling/behavior/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import AppendBehavior from './AppendBehavior';
import AssociationBehavior from './AssociationBehavior';
import AttachEventBehavior from './AttachEventBehavior';
import BoundaryEventBehavior from './BoundaryEventBehavior';
import CompensateBoundaryEventBehaviour from './CompensateBoundaryEventBehaviour';
import CreateBehavior from './CreateBehavior';
import CreateDataObjectBehavior from './CreateDataObjectBehavior';
import CreateParticipantBehavior from './CreateParticipantBehavior';
Expand Down Expand Up @@ -47,6 +48,7 @@ export default {
'associationBehavior',
'attachEventBehavior',
'boundaryEventBehavior',
'compensateBoundaryEventBehaviour',
'createBehavior',
'createDataObjectBehavior',
'createParticipantBehavior',
Expand Down Expand Up @@ -86,6 +88,7 @@ export default {
associationBehavior: [ 'type', AssociationBehavior ],
attachEventBehavior: [ 'type', AttachEventBehavior ],
boundaryEventBehavior: [ 'type', BoundaryEventBehavior ],
compensateBoundaryEventBehaviour: [ 'type', CompensateBoundaryEventBehaviour ],
createBehavior: [ 'type', CreateBehavior ],
createDataObjectBehavior: [ 'type', CreateDataObjectBehavior ],
createParticipantBehavior: [ 'type', CreateParticipantBehavior ],
Expand Down
16 changes: 8 additions & 8 deletions lib/features/rules/BpmnRules.js
Original file line number Diff line number Diff line change
Expand Up @@ -550,15 +550,15 @@ function canConnect(source, target, connection) {
return connectDataAssociation;
}

if (isCompensationBoundary(source) && isForCompensation(target)) {
return {
type: 'bpmn:Association',
associationDirection: 'One'
};
}

if (canConnectAssociation(source, target)) {

if (isCompensationBoundary(source) && is(target, 'bpmn:Activity')) {
return {
type: 'bpmn:Association',
associationDirection: 'One'
};
}

return {
type: 'bpmn:Association'
};
Expand Down Expand Up @@ -1028,7 +1028,7 @@ function isOneTextAnnotation(source, target) {
function canConnectAssociation(source, target) {

// compensation boundary events are exception
if (isCompensationBoundary(source) && isForCompensation(target)) {
if (isCompensationBoundary(source) && is(target, 'bpmn:Activity') && !isEventSubProcess(target)) {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="sid-38422fae-e03e-43a3-bef4-bd33b32041b2" targetNamespace="http://bpmn.io/bpmn" exporter="Camunda Modeler" exporterVersion="5.17.0-rc.0">
<process id="Process_1" isExecutable="false">
<task id="Task_BoundaryEvent" />
<boundaryEvent id="Attached_Event" attachedToRef="Task_BoundaryEvent">
<compensateEventDefinition id="CompensateEventDefinition_1v5ffnt" />
</boundaryEvent>
<task id="Task" />
<task id="Task_BoundaryEvent2" />
<boundaryEvent id="Attached_Event2" attachedToRef="Task_BoundaryEvent2">
<compensateEventDefinition id="CompensateEventDefinition_0o69h2g" />
</boundaryEvent>
<task id="Task_Compensation" isForCompensation="true" />
<association id="Association" associationDirection="One" sourceRef="Attached_Event2" targetRef="Task_Compensation" />
</process>
<bpmndi:BPMNDiagram id="BpmnDiagram_1">
<bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="Activity_0ne36hy_di" bpmnElement="Task_BoundaryEvent">
<omgdc:Bounds x="200" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0l16eqc_di" bpmnElement="Task">
<omgdc:Bounds x="360" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_14r8htx" bpmnElement="Task_BoundaryEvent2">
<omgdc:Bounds x="210" y="270" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0asoxmo_di" bpmnElement="Task_Compensation">
<omgdc:Bounds x="320" y="390" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Association_di" bpmnElement="Association">
<di:waypoint x="250" y="368" />
<di:waypoint x="250" y="430" />
<di:waypoint x="320" y="430" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Event_12wgrmv_di" bpmnElement="Attached_Event">
<omgdc:Bounds x="222" y="142" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_0lrjsju" bpmnElement="Attached_Event2">
<omgdc:Bounds x="232" y="332" width="36" height="36" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import {
bootstrapModeler,
inject
} from 'test/TestHelper';

import modelingModule from 'lib/features/modeling';
import coreModule from 'lib/core';

import diagramXML from './CompensateBoundaryEventBehaviour.bpmn';


describe('features/modeling/behavior - compensation boundary event', function() {

var testModules = [ coreModule, modelingModule ];

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


describe('should add `isForCompensation`', function() {

it('on append', inject(function(elementFactory, modeling, elementRegistry) {

// given
var boundaryEventShape = elementRegistry.get('Attached_Event');
var taskShape = elementFactory.createShape({ type: 'bpmn:Task' });

// when
var task = modeling.appendShape(boundaryEventShape, taskShape, { x: 100, y: 100 });

// then
expect(task.businessObject.isForCompensation).to.be.true;
}));


it('on connect', inject(function(modeling, elementRegistry) {

// given
var boundaryEventShape = elementRegistry.get('Attached_Event');
var taskShape = elementRegistry.get('Task');

// when
modeling.connect(boundaryEventShape, taskShape);

// then
expect(taskShape.businessObject.isForCompensation).to.be.true;
}));


it('on reconnect', inject(function(modeling, elementRegistry) {

// given
var taskShape = elementRegistry.get('Task');
var connection = elementRegistry.get('Association');

// when
modeling.reconnectEnd(connection, taskShape, { x: 100, y: 100 });

// then
expect(taskShape.businessObject.isForCompensation).to.be.true;
}));
});


describe('should remove `isForCompensation`', function() {

it('on remove element', inject(function(elementRegistry, modeling) {

// given
var taskShape = elementRegistry.get('Task_Compensation');
var boundaryEventShape = elementRegistry.get('Attached_Event2');

// then
expect(taskShape.businessObject.isForCompensation).to.be.true;

// when
modeling.removeElements([ boundaryEventShape ]);

// then
expect(taskShape.businessObject.isForCompensation).to.be.false;
}));


it('on delete connection', inject(function(elementRegistry, modeling) {

// given
var taskShape = elementRegistry.get('Task_Compensation');
var connection = elementRegistry.get('Association');

// then
expect(taskShape.businessObject.isForCompensation).to.be.true;

// when
modeling.removeConnection(connection);

// then
expect(taskShape.businessObject.isForCompensation).to.be.false;
}));


it('on reconnect', inject(function(modeling, elementRegistry) {

// given
var oldShape = elementRegistry.get('Task_Compensation');
var taskShape = elementRegistry.get('Task');
var connection = elementRegistry.get('Association');

// when
modeling.reconnectEnd(connection, taskShape, { x: 100, y: 100 });

// then
expect(oldShape.businessObject.isForCompensation).to.be.false;
}));

});
});
21 changes: 15 additions & 6 deletions test/spec/features/rules/BpmnRules.compensation.bpmn
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@
<bpmn2:endEvent id="EndEvent_1">
<bpmn2:compensateEventDefinition id="_CompensateEventDefinition_5" waitForCompletion="false"/>
</bpmn2:endEvent>
<bpmn2:exclusiveGateway id="Gateway"/>
<bpmn2:intermediateThrowEvent id="IntermediateEvent"/>
<bpmn2:exclusiveGateway id="Gateway" />
<bpmn2:intermediateThrowEvent id="IntermediateEvent" />
<bpmn2:subProcess id="SubProcess_2">
<bpmn2:startEvent id="Event_0ih2uit" />
</bpmn2:subProcess>
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_TaskForCompensation" bpmnElement="Task">
<dc:Bounds height="80.0" width="100.0" x="43.0" y="99.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_BoundaryEvent_2" bpmnElement="CompensationBoundary">
<dc:Bounds height="36.0" width="36.0" x="87.0" y="161.0"/>
<dc:Bounds x="453" y="99" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_Task_3" bpmnElement="TaskForCompensation">
<dc:Bounds height="80.0" width="100.0" x="142.0" y="240.0"/>
Expand Down Expand Up @@ -61,6 +61,15 @@
<dc:Bounds height="0.0" width="0.0" x="450.0" y="303.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_11kmncl_di" bpmnElement="SubProcess_2" isExpanded="true">
<dc:Bounds x="160" y="344" width="350" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0ih2uit_di" bpmnElement="Event_0ih2uit">
<dc:Bounds x="200" y="426" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_BoundaryEvent_2" bpmnElement="CompensationBoundary">
<dc:Bounds x="497" y="161" width="36" height="36" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>
22 changes: 22 additions & 0 deletions test/spec/features/rules/BpmnRulesSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,28 @@ describe('features/modeling/rules - BpmnRules', function() {
it('connect CompensationBoundary -> Task', inject(function() {

expectCanConnect('CompensationBoundary', 'Task', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: false
});
}));


it('connect CompensationBoundary -> SubProcess', inject(function() {

expectCanConnect('CompensationBoundary', 'SubProcess_2', {
sequenceFlow: false,
messageFlow: false,
association: true,
dataAssociation: false
});
}));


it('connect CompensationBoundary -> Event SubProcess', inject(function() {

expectCanConnect('CompensationBoundary', 'SubProcess_1', {
sequenceFlow: false,
messageFlow: false,
association: false,
Expand Down

0 comments on commit e568807

Please sign in to comment.