feat(modeling): allow to attach events with event definition
This feature is allowed only for events which have their boundary counteparts, i.e. intermediate throw, message catch, timer catch, signal catch and conditional catch events.
This commit is contained in:
parent
1e9aceecd7
commit
33f9e7be6e
|
@ -2,13 +2,14 @@ import inherits from 'inherits';
|
||||||
|
|
||||||
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
|
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
|
||||||
|
|
||||||
import { is } from '../../../util/ModelUtil';
|
import { isAny } from '../util/ModelingUtil';
|
||||||
|
import { getBusinessObject } from '../../../util/ModelUtil';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BPMN specific attach event behavior
|
* BPMN specific attach event behavior
|
||||||
*/
|
*/
|
||||||
export default function AttachEventBehavior(eventBus, bpmnFactory, bpmnReplace) {
|
export default function AttachEventBehavior(eventBus, bpmnReplace) {
|
||||||
|
|
||||||
CommandInterceptor.call(this, eventBus);
|
CommandInterceptor.call(this, eventBus);
|
||||||
|
|
||||||
|
@ -21,9 +22,9 @@ export default function AttachEventBehavior(eventBus, bpmnFactory, bpmnReplace)
|
||||||
var shapes = context.shapes,
|
var shapes = context.shapes,
|
||||||
host = context.newHost,
|
host = context.newHost,
|
||||||
shape,
|
shape,
|
||||||
newShape,
|
eventDefinition,
|
||||||
businessObject,
|
boundaryEvent,
|
||||||
boundaryEvent;
|
newShape;
|
||||||
|
|
||||||
if (shapes.length !== 1) {
|
if (shapes.length !== 1) {
|
||||||
return;
|
return;
|
||||||
|
@ -31,20 +32,18 @@ export default function AttachEventBehavior(eventBus, bpmnFactory, bpmnReplace)
|
||||||
|
|
||||||
shape = shapes[0];
|
shape = shapes[0];
|
||||||
|
|
||||||
var attrs = {
|
if (host && isAny(shape, [ 'bpmn:IntermediateThrowEvent', 'bpmn:IntermediateCatchEvent' ])) {
|
||||||
cancelActivity: true
|
|
||||||
};
|
|
||||||
|
|
||||||
if (host && is(shape, 'bpmn:IntermediateThrowEvent')) {
|
eventDefinition = getEventDefinition(shape);
|
||||||
attrs.attachedToRef = host.businessObject;
|
|
||||||
|
|
||||||
businessObject = bpmnFactory.create('bpmn:BoundaryEvent', attrs);
|
|
||||||
|
|
||||||
boundaryEvent = {
|
boundaryEvent = {
|
||||||
type: 'bpmn:BoundaryEvent',
|
type: 'bpmn:BoundaryEvent'
|
||||||
businessObject: businessObject
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (eventDefinition) {
|
||||||
|
boundaryEvent.eventDefinitionType = eventDefinition.$type;
|
||||||
|
}
|
||||||
|
|
||||||
newShape = bpmnReplace.replaceElement(shape, boundaryEvent);
|
newShape = bpmnReplace.replaceElement(shape, boundaryEvent);
|
||||||
|
|
||||||
context.shapes = [ newShape ];
|
context.shapes = [ newShape ];
|
||||||
|
@ -54,8 +53,16 @@ export default function AttachEventBehavior(eventBus, bpmnFactory, bpmnReplace)
|
||||||
|
|
||||||
AttachEventBehavior.$inject = [
|
AttachEventBehavior.$inject = [
|
||||||
'eventBus',
|
'eventBus',
|
||||||
'bpmnFactory',
|
|
||||||
'bpmnReplace'
|
'bpmnReplace'
|
||||||
];
|
];
|
||||||
|
|
||||||
inherits(AttachEventBehavior, CommandInterceptor);
|
inherits(AttachEventBehavior, CommandInterceptor);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// helper /////
|
||||||
|
function getEventDefinition(element) {
|
||||||
|
var bo = getBusinessObject(element);
|
||||||
|
|
||||||
|
return bo && bo.eventDefinitions && bo.eventDefinitions[0];
|
||||||
|
}
|
||||||
|
|
|
@ -564,7 +564,18 @@ function isLane(element) {
|
||||||
* this must be reflected in the rules.
|
* this must be reflected in the rules.
|
||||||
*/
|
*/
|
||||||
function isBoundaryCandidate(element) {
|
function isBoundaryCandidate(element) {
|
||||||
return isBoundaryEvent(element) || is(element, 'bpmn:IntermediateThrowEvent');
|
if (isBoundaryEvent(element)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is(element, 'bpmn:IntermediateThrowEvent') && hasNoEventDefinition(element)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
is(element, 'bpmn:IntermediateCatchEvent') &&
|
||||||
|
hasCommonBoundaryIntermediateEventDefinition(element)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasNoEventDefinition(element) {
|
function hasNoEventDefinition(element) {
|
||||||
|
|
|
@ -11,49 +11,100 @@ describe('features/modeling/behavior - attach events', function() {
|
||||||
|
|
||||||
var testModules = [ coreModule, modelingModule ];
|
var testModules = [ coreModule, modelingModule ];
|
||||||
|
|
||||||
var processDiagramXML = require('../../../../fixtures/bpmn/boundary-events.bpmn');
|
var processDiagramXML = require('test/spec/features/rules/BpmnRules.attaching.bpmn');
|
||||||
|
|
||||||
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
|
beforeEach(bootstrapModeler(processDiagramXML, { modules: testModules }));
|
||||||
|
|
||||||
|
|
||||||
it('should execute on attach', inject(function(elementRegistry, modeling) {
|
describe('basics', function() {
|
||||||
|
|
||||||
// given
|
it('should execute on attach', inject(function(elementRegistry, modeling) {
|
||||||
var eventId = 'IntermediateThrowEvent_1',
|
|
||||||
intermediateThrowEvent = elementRegistry.get(eventId),
|
|
||||||
subProcess = elementRegistry.get('SubProcess_1'),
|
|
||||||
boundaryEvent;
|
|
||||||
|
|
||||||
var elements = [ intermediateThrowEvent ];
|
// given
|
||||||
|
var eventId = 'IntermediateThrowEvent',
|
||||||
|
intermediateThrowEvent = elementRegistry.get(eventId),
|
||||||
|
subProcess = elementRegistry.get('SubProcess_1'),
|
||||||
|
boundaryEvent;
|
||||||
|
|
||||||
// when
|
var elements = [ intermediateThrowEvent ];
|
||||||
modeling.moveElements(elements, { x: 60, y: -131 }, subProcess, { attach: true });
|
|
||||||
|
|
||||||
// then
|
// when
|
||||||
boundaryEvent = elementRegistry.get(eventId);
|
modeling.moveElements(elements, { x: 0, y: -90 }, subProcess, { attach: true });
|
||||||
|
|
||||||
expect(intermediateThrowEvent.parent).to.not.exist;
|
// then
|
||||||
expect(boundaryEvent).to.exist;
|
boundaryEvent = elementRegistry.get(eventId);
|
||||||
expect(boundaryEvent.type).to.equal('bpmn:BoundaryEvent');
|
|
||||||
expect(boundaryEvent.businessObject.attachedToRef).to.equal(subProcess.businessObject);
|
expect(intermediateThrowEvent.parent).to.not.exist;
|
||||||
}));
|
expect(boundaryEvent).to.exist;
|
||||||
|
expect(boundaryEvent.type).to.equal('bpmn:BoundaryEvent');
|
||||||
|
expect(boundaryEvent.businessObject.attachedToRef).to.equal(subProcess.businessObject);
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should NOT execute on drop', inject(function(elementRegistry, modeling) {
|
it('should NOT execute on drop', inject(function(elementRegistry, modeling) {
|
||||||
|
|
||||||
// given
|
// given
|
||||||
var eventId = 'IntermediateThrowEvent_1',
|
var eventId = 'IntermediateThrowEvent',
|
||||||
intermediateThrowEvent = elementRegistry.get(eventId),
|
intermediateThrowEvent = elementRegistry.get(eventId),
|
||||||
subProcess = elementRegistry.get('SubProcess_1');
|
subProcess = elementRegistry.get('SubProcess_1');
|
||||||
|
|
||||||
var elements = [ intermediateThrowEvent ];
|
var elements = [ intermediateThrowEvent ];
|
||||||
|
|
||||||
// when
|
// when
|
||||||
modeling.moveElements(elements, { x: 60, y: -191 }, subProcess);
|
modeling.moveElements(elements, { x: 0, y: -150 }, subProcess);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(intermediateThrowEvent.parent).to.eql(subProcess);
|
expect(intermediateThrowEvent.parent).to.eql(subProcess);
|
||||||
expect(intermediateThrowEvent.type).to.equal('bpmn:IntermediateThrowEvent');
|
expect(intermediateThrowEvent.type).to.equal('bpmn:IntermediateThrowEvent');
|
||||||
}));
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('event definition', function() {
|
||||||
|
|
||||||
|
it('should copy event definitions', inject(function(elementRegistry, modeling) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var attachableEvents = [
|
||||||
|
'IntermediateThrowEvent',
|
||||||
|
'MessageCatchEvent',
|
||||||
|
'TimerCatchEvent',
|
||||||
|
'SignalCatchEvent',
|
||||||
|
'ConditionalCatchEvent'
|
||||||
|
];
|
||||||
|
|
||||||
|
attachableEvents.forEach(function(eventId) {
|
||||||
|
|
||||||
|
var event = elementRegistry.get(eventId),
|
||||||
|
subProcess = elementRegistry.get('SubProcess_1'),
|
||||||
|
eventDefinitions = event.businessObject.eventDefinitions,
|
||||||
|
boundaryEvent, bo;
|
||||||
|
|
||||||
|
var elements = [ event ];
|
||||||
|
|
||||||
|
// when
|
||||||
|
modeling.moveElements(elements, { x: 0, y: -90 }, subProcess, { attach: true });
|
||||||
|
|
||||||
|
// then
|
||||||
|
boundaryEvent = elementRegistry.get(eventId);
|
||||||
|
bo = boundaryEvent.businessObject;
|
||||||
|
|
||||||
|
expect(boundaryEvent.type).to.equal('bpmn:BoundaryEvent');
|
||||||
|
expect(bo.eventDefinitions).to.jsonEqual(eventDefinitions, skipId);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// helper //////
|
||||||
|
function skipId(key, value) {
|
||||||
|
|
||||||
|
if (key === 'id') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
<?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" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.1.0">
|
||||||
|
<bpmn:process id="Process_1" isExecutable="false">
|
||||||
|
<bpmn:subProcess id="SubProcess_1" name="SubProcess" />
|
||||||
|
<bpmn:intermediateCatchEvent id="MessageCatchEvent" name="2">
|
||||||
|
<bpmn:messageEventDefinition />
|
||||||
|
</bpmn:intermediateCatchEvent>
|
||||||
|
<bpmn:intermediateThrowEvent id="MessageThrowEvent" name="3">
|
||||||
|
<bpmn:messageEventDefinition />
|
||||||
|
</bpmn:intermediateThrowEvent>
|
||||||
|
<bpmn:intermediateThrowEvent id="IntermediateThrowEvent" name="1" />
|
||||||
|
<bpmn:intermediateCatchEvent id="TimerCatchEvent" name="4">
|
||||||
|
<bpmn:timerEventDefinition />
|
||||||
|
</bpmn:intermediateCatchEvent>
|
||||||
|
<bpmn:intermediateThrowEvent id="EscalationThrowEvent" name="5">
|
||||||
|
<bpmn:escalationEventDefinition />
|
||||||
|
</bpmn:intermediateThrowEvent>
|
||||||
|
<bpmn:intermediateCatchEvent id="ConditionalCatchEvent" name="6">
|
||||||
|
<bpmn:conditionalEventDefinition>
|
||||||
|
<bpmn:condition xsi:type="bpmn:tFormalExpression" />
|
||||||
|
</bpmn:conditionalEventDefinition>
|
||||||
|
</bpmn:intermediateCatchEvent>
|
||||||
|
<bpmn:intermediateCatchEvent id="LinkCatchEvent" name="7">
|
||||||
|
<bpmn:linkEventDefinition />
|
||||||
|
</bpmn:intermediateCatchEvent>
|
||||||
|
<bpmn:intermediateThrowEvent id="LinkThrowEvent" name="8">
|
||||||
|
<bpmn:linkEventDefinition />
|
||||||
|
</bpmn:intermediateThrowEvent>
|
||||||
|
<bpmn:intermediateThrowEvent id="CompensateThrowEvent" name="9">
|
||||||
|
<bpmn:compensateEventDefinition />
|
||||||
|
</bpmn:intermediateThrowEvent>
|
||||||
|
<bpmn:intermediateCatchEvent id="SignalCatchEvent" name="10">
|
||||||
|
<bpmn:signalEventDefinition />
|
||||||
|
</bpmn:intermediateCatchEvent>
|
||||||
|
<bpmn:intermediateThrowEvent id="SignalThrowEvent" name="11">
|
||||||
|
<bpmn:signalEventDefinition />
|
||||||
|
</bpmn:intermediateThrowEvent>
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
|
||||||
|
<bpmndi:BPMNShape id="SubProcess_1_di" bpmnElement="SubProcess_1" isExpanded="true">
|
||||||
|
<dc:Bounds x="156" y="30" width="660" height="200" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="IntermediateCatchEvent_0ckelak_di" bpmnElement="MessageCatchEvent">
|
||||||
|
<dc:Bounds x="234" y="300" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="249" y="340" width="7" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="IntermediateThrowEvent_0h76veu_di" bpmnElement="MessageThrowEvent">
|
||||||
|
<dc:Bounds x="281" y="300" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="296" y="340" width="7" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="IntermediateThrowEvent_di" bpmnElement="IntermediateThrowEvent">
|
||||||
|
<dc:Bounds x="188" y="300" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="203" y="340" width="7" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="IntermediateCatchEvent_1bkb8p2_di" bpmnElement="TimerCatchEvent">
|
||||||
|
<dc:Bounds x="343" y="300" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="358" y="340" width="7" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="IntermediateThrowEvent_0fxof2e_di" bpmnElement="EscalationThrowEvent">
|
||||||
|
<dc:Bounds x="402" y="300" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="417" y="340" width="7" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="IntermediateCatchEvent_0r6qqek_di" bpmnElement="ConditionalCatchEvent">
|
||||||
|
<dc:Bounds x="454" y="300" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="469" y="340" width="7" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="IntermediateCatchEvent_179y1zf_di" bpmnElement="LinkCatchEvent">
|
||||||
|
<dc:Bounds x="505" y="300" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="520" y="340" width="7" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="IntermediateThrowEvent_169wfo1_di" bpmnElement="LinkThrowEvent">
|
||||||
|
<dc:Bounds x="556" y="300" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="571" y="340" width="7" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="IntermediateThrowEvent_1o8dtmg_di" bpmnElement="CompensateThrowEvent">
|
||||||
|
<dc:Bounds x="605" y="300" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="620" y="340" width="7" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="IntermediateCatchEvent_0du6szv_di" bpmnElement="SignalCatchEvent">
|
||||||
|
<dc:Bounds x="654" y="300" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="666" y="340" width="13" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="IntermediateThrowEvent_0sqptpn_di" bpmnElement="SignalThrowEvent">
|
||||||
|
<dc:Bounds x="701" y="300" width="36" height="36" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="713" y="340" width="12" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn:definitions>
|
|
@ -1260,23 +1260,69 @@ describe('features/modeling/rules - BpmnRules', function() {
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
it('attach/move IntermediateThrowEvent -> SubProcess', inject(
|
|
||||||
function(elementRegistry) {
|
|
||||||
|
|
||||||
// given
|
describe('event attaching', function() {
|
||||||
var intermediateThrowEvent = elementRegistry.get('IntermediateThrowEvent_1');
|
|
||||||
|
|
||||||
var elements = [ intermediateThrowEvent ];
|
var testXML = require('./BpmnRules.attaching.bpmn');
|
||||||
|
|
||||||
// then
|
beforeEach(bootstrapModeler(testXML, { modules: testModules }));
|
||||||
expectCanMove(elements, 'SubProcess_1', {
|
|
||||||
|
|
||||||
|
it('should allow to attach attachable events to SubProcess', inject(function(elementRegistry) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var attachableEvents = [
|
||||||
|
'IntermediateThrowEvent',
|
||||||
|
'MessageCatchEvent',
|
||||||
|
'TimerCatchEvent',
|
||||||
|
'SignalCatchEvent',
|
||||||
|
'ConditionalCatchEvent'
|
||||||
|
];
|
||||||
|
|
||||||
|
var events = attachableEvents.map(function(eventId) {
|
||||||
|
return elementRegistry.get(eventId);
|
||||||
|
});
|
||||||
|
|
||||||
|
// then
|
||||||
|
events.forEach(function(event) {
|
||||||
|
|
||||||
|
expectCanMove([ event ], 'SubProcess_1', {
|
||||||
attach: 'attach',
|
attach: 'attach',
|
||||||
move: true
|
move: true
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should not allow to attach non-attachable events to SubProcess',
|
||||||
|
inject(function(elementRegistry) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var nonAttachableEvents = [
|
||||||
|
'MessageThrowEvent',
|
||||||
|
'EscalationThrowEvent',
|
||||||
|
'LinkCatchEvent',
|
||||||
|
'LinkThrowEvent',
|
||||||
|
'CompensateThrowEvent',
|
||||||
|
'SignalThrowEvent'
|
||||||
|
];
|
||||||
|
|
||||||
|
var events = nonAttachableEvents.map(function(eventId) {
|
||||||
|
return elementRegistry.get(eventId);
|
||||||
|
});
|
||||||
|
|
||||||
|
// then
|
||||||
|
events.forEach(function(event) {
|
||||||
|
|
||||||
|
expectCanMove([ event ], 'SubProcess_1', {
|
||||||
|
attach: false,
|
||||||
|
move: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue