Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: pasting compensation activity #2220

Merged
merged 2 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ All notable changes to [bpmn-js](https://github.com/bpmn-io/bpmn-js) are documen

___Note:__ Yet to be released changes appear here._

* `FIX`: pasting compensation activity without boundary event ([#2070](https://github.com/bpmn-io/bpmn-js/issues/2070))
* `FIX`: lane resize constraints for se and nw direction ([#2209](https://github.com/bpmn-io/bpmn-js/issues/2209))

## 17.9.2
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import inherits from 'inherits-browser';

import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';

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

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

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


/**
* A behavior that sets the property of Compensation Activity after paste operation
*
* @param {EventBus} eventBus
* @param {Modeling} modeling
*/
export default function SetCompensationActivityAfterPasteBehavior(eventBus, modeling) {

CommandInterceptor.call(this, eventBus);

this.postExecuted('elements.create', function(event) {
const context = event.context,
elements = context.elements;

// check if compensation activity is connected to compensation boundary event
for (const element of elements) {
if (isForCompensation(element) && !isConnectedToCompensationBoundaryEvent(element)) {
modeling.updateProperties(element, { isForCompensation: undefined });
}
}
});
}

inherits(SetCompensationActivityAfterPasteBehavior, CommandInterceptor);

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


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

function isForCompensation(element) {
const bo = getBusinessObject(element);
return bo && bo.isForCompensation;
}

function isCompensationBoundaryEvent(element) {
return element && is(element, 'bpmn:BoundaryEvent') &&
hasEventDefinition(element, 'bpmn:CompensateEventDefinition');
}

function isConnectedToCompensationBoundaryEvent(element) {
const compensationAssociations = element.incoming.filter(
connection => isCompensationBoundaryEvent(connection.source)
);
if (compensationAssociations.length > 0) {
return true;
}
return false;
}
7 changes: 5 additions & 2 deletions lib/features/modeling/behavior/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import ToggleElementCollapseBehaviour from './ToggleElementCollapseBehaviour';
import UnclaimIdBehavior from './UnclaimIdBehavior';
import UnsetDefaultFlowBehavior from './UnsetDefaultFlowBehavior';
import UpdateFlowNodeRefsBehavior from './UpdateFlowNodeRefsBehavior';
import SetCompensationActivityAfterPasteBehavior from './SetCompensationActivityAfterPasteBehavior';

/**
* @type { import('didi').ModuleDeclaration }
Expand Down Expand Up @@ -83,7 +84,8 @@ export default {
'toggleElementCollapseBehaviour',
'unclaimIdBehavior',
'updateFlowNodeRefsBehavior',
'unsetDefaultFlowBehavior'
'unsetDefaultFlowBehavior',
'setCompensationActivityAfterPasteBehavior'
],
adaptiveLabelPositioningBehavior: [ 'type', AdaptiveLabelPositioningBehavior ],
appendBehavior: [ 'type', AppendBehavior ],
Expand Down Expand Up @@ -124,5 +126,6 @@ export default {
toggleElementCollapseBehaviour : [ 'type', ToggleElementCollapseBehaviour ],
unclaimIdBehavior: [ 'type', UnclaimIdBehavior ],
unsetDefaultFlowBehavior: [ 'type', UnsetDefaultFlowBehavior ],
updateFlowNodeRefsBehavior: [ 'type', UpdateFlowNodeRefsBehavior ]
updateFlowNodeRefsBehavior: [ 'type', UpdateFlowNodeRefsBehavior ],
setCompensationActivityAfterPasteBehavior: [ 'type', SetCompensationActivityAfterPasteBehavior ]
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?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" exporter="Camunda Modeler" exporterVersion="5.25.0">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:startEvent id="Event_0wuaar2">
<bpmn:outgoing>Flow_1ank1yi</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="Compensation_Boundary_Task">
<bpmn:incoming>Flow_1ank1yi</bpmn:incoming>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_1ank1yi" sourceRef="Event_0wuaar2" targetRef="Compensation_Boundary_Task" />
<bpmn:boundaryEvent id="Compensation_Boundary_Event" attachedToRef="Compensation_Boundary_Task">
<bpmn:compensateEventDefinition id="CompensateEventDefinition_0ibh5ku" />
</bpmn:boundaryEvent>
<bpmn:task id="Compensation_Activity" isForCompensation="true" />
<bpmn:association id="Association_0x72gur" associationDirection="One" sourceRef="Compensation_Boundary_Event" targetRef="Compensation_Activity" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="Event_0wuaar2_di" bpmnElement="Event_0wuaar2">
<dc:Bounds x="152" y="112" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Compensation_Boundary_Task_di" bpmnElement="Compensation_Boundary_Task">
<dc:Bounds x="240" y="90" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Compensation_Activity_di" bpmnElement="Compensation_Activity">
<dc:Bounds x="370" y="210" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Association_0x72gur_di" bpmnElement="Association_0x72gur">
<di:waypoint x="300" y="188" />
<di:waypoint x="300" y="250" />
<di:waypoint x="370" y="250" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Event_0njauji_di" bpmnElement="Compensation_Boundary_Event">
<dc:Bounds x="282" y="152" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1ank1yi_di" bpmnElement="Flow_1ank1yi">
<di:waypoint x="188" y="130" />
<di:waypoint x="240" y="130" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {
bootstrapModeler,
inject
} from 'test/TestHelper';

import modelingModule from 'lib/features/modeling';
import coreModule from 'lib/core';
import { is } from 'lib/util/ModelUtil';
import copyPasteModule from 'lib/features/copy-paste';

import diagramXML from './SetCompensationActivityAfterPasteBehaviorSpec.bpmn';


describe('features/modeling/behavior - compensation activity after paste', function() {

const testModules = [
copyPasteModule,
coreModule,
modelingModule
];

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


describe('copy/paste compensation activity', function() {

it('without boundary event', inject(function(canvas, elementRegistry, copyPaste) {

// given
copyPaste.copy([ elementRegistry.get('Compensation_Activity') ]);

// when
var copiedElements = copyPaste.paste({
element: canvas.getRootElement(),
point: {
x: 100,
y: 100
}
});

// then
expect(copiedElements).to.have.lengthOf(1);
const taskElement = copiedElements.find(element => is(element, 'bpmn:Task'));
expect(taskElement.businessObject.isForCompensation).to.be.false;
}));


it('with boundary event', inject(function(canvas, elementRegistry, copyPaste) {

// given
copyPaste.copy([
elementRegistry.get('Compensation_Boundary_Task'),
elementRegistry.get('Compensation_Activity') ]);

// when
var copiedElements = copyPaste.paste({
element: canvas.getRootElement(),
point: {
x: 100,
y: 100
}
});

// then
expect(copiedElements).to.have.lengthOf(4);
expect(copiedElements.filter(element => is(element, 'bpmn:Association'))).to.have.length(1);
expect(copiedElements.filter(element => is(element, 'bpmn:BoundaryEvent'))).to.have.length(1);
expect(copiedElements.filter(element => is(element, 'bpmn:Task'))).to.have.length(2);

// verify that for every Task element, if businessObject.isForCompensation exists, it should be true
copiedElements.filter(element => is(element, 'bpmn:Task')).forEach(taskElement => {
if (Object.prototype.hasOwnProperty.call(taskElement.businessObject, 'isForCompensation')) {
expect(taskElement.businessObject.isForCompensation).to.be.true;
}
});
}));

});

});
3 changes: 2 additions & 1 deletion test/spec/features/snapping/BpmnCreateMoveSnappingSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ describe('features/snapping - BpmnCreateMoveSnapping', function() {
x: externalLabelMid.x - externalLabelBounds.width / 2,
y: externalLabelMid.y - externalLabelBounds.height / 2,
width: externalLabelBounds.width,
height: externalLabelBounds.height
height: externalLabelBounds.height,
businessObject: intermediateThrowEvent.businessObject
});

create.start(canvasEvent({ x: 0, y: 0 }), [ intermediateThrowEvent, label ]);
Expand Down