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 { is } from '../../../util/ModelUtil';
|
||||
import { isAny } from '../util/ModelingUtil';
|
||||
import { getBusinessObject } from '../../../util/ModelUtil';
|
||||
|
||||
|
||||
/**
|
||||
* BPMN specific attach event behavior
|
||||
*/
|
||||
export default function AttachEventBehavior(eventBus, bpmnFactory, bpmnReplace) {
|
||||
export default function AttachEventBehavior(eventBus, bpmnReplace) {
|
||||
|
||||
CommandInterceptor.call(this, eventBus);
|
||||
|
||||
|
@ -21,9 +22,9 @@ export default function AttachEventBehavior(eventBus, bpmnFactory, bpmnReplace)
|
|||
var shapes = context.shapes,
|
||||
host = context.newHost,
|
||||
shape,
|
||||
newShape,
|
||||
businessObject,
|
||||
boundaryEvent;
|
||||
eventDefinition,
|
||||
boundaryEvent,
|
||||
newShape;
|
||||
|
||||
if (shapes.length !== 1) {
|
||||
return;
|
||||
|
@ -31,20 +32,18 @@ export default function AttachEventBehavior(eventBus, bpmnFactory, bpmnReplace)
|
|||
|
||||
shape = shapes[0];
|
||||
|
||||
var attrs = {
|
||||
cancelActivity: true
|
||||
};
|
||||
if (host && isAny(shape, [ 'bpmn:IntermediateThrowEvent', 'bpmn:IntermediateCatchEvent' ])) {
|
||||
|
||||
if (host && is(shape, 'bpmn:IntermediateThrowEvent')) {
|
||||
attrs.attachedToRef = host.businessObject;
|
||||
|
||||
businessObject = bpmnFactory.create('bpmn:BoundaryEvent', attrs);
|
||||
eventDefinition = getEventDefinition(shape);
|
||||
|
||||
boundaryEvent = {
|
||||
type: 'bpmn:BoundaryEvent',
|
||||
businessObject: businessObject
|
||||
type: 'bpmn:BoundaryEvent'
|
||||
};
|
||||
|
||||
if (eventDefinition) {
|
||||
boundaryEvent.eventDefinitionType = eventDefinition.$type;
|
||||
}
|
||||
|
||||
newShape = bpmnReplace.replaceElement(shape, boundaryEvent);
|
||||
|
||||
context.shapes = [ newShape ];
|
||||
|
@ -54,8 +53,16 @@ export default function AttachEventBehavior(eventBus, bpmnFactory, bpmnReplace)
|
|||
|
||||
AttachEventBehavior.$inject = [
|
||||
'eventBus',
|
||||
'bpmnFactory',
|
||||
'bpmnReplace'
|
||||
];
|
||||
|
||||
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.
|
||||
*/
|
||||
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) {
|
||||
|
|
|
@ -11,49 +11,100 @@ describe('features/modeling/behavior - attach events', function() {
|
|||
|
||||
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 }));
|
||||
|
||||
|
||||
it('should execute on attach', inject(function(elementRegistry, modeling) {
|
||||
describe('basics', function() {
|
||||
|
||||
// given
|
||||
var eventId = 'IntermediateThrowEvent_1',
|
||||
intermediateThrowEvent = elementRegistry.get(eventId),
|
||||
subProcess = elementRegistry.get('SubProcess_1'),
|
||||
boundaryEvent;
|
||||
it('should execute on attach', inject(function(elementRegistry, modeling) {
|
||||
|
||||
var elements = [ intermediateThrowEvent ];
|
||||
// given
|
||||
var eventId = 'IntermediateThrowEvent',
|
||||
intermediateThrowEvent = elementRegistry.get(eventId),
|
||||
subProcess = elementRegistry.get('SubProcess_1'),
|
||||
boundaryEvent;
|
||||
|
||||
// when
|
||||
modeling.moveElements(elements, { x: 60, y: -131 }, subProcess, { attach: true });
|
||||
var elements = [ intermediateThrowEvent ];
|
||||
|
||||
// then
|
||||
boundaryEvent = elementRegistry.get(eventId);
|
||||
// when
|
||||
modeling.moveElements(elements, { x: 0, y: -90 }, subProcess, { attach: true });
|
||||
|
||||
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);
|
||||
}));
|
||||
// then
|
||||
boundaryEvent = elementRegistry.get(eventId);
|
||||
|
||||
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
|
||||
var eventId = 'IntermediateThrowEvent_1',
|
||||
intermediateThrowEvent = elementRegistry.get(eventId),
|
||||
subProcess = elementRegistry.get('SubProcess_1');
|
||||
// given
|
||||
var eventId = 'IntermediateThrowEvent',
|
||||
intermediateThrowEvent = elementRegistry.get(eventId),
|
||||
subProcess = elementRegistry.get('SubProcess_1');
|
||||
|
||||
var elements = [ intermediateThrowEvent ];
|
||||
var elements = [ intermediateThrowEvent ];
|
||||
|
||||
// when
|
||||
modeling.moveElements(elements, { x: 60, y: -191 }, subProcess);
|
||||
// when
|
||||
modeling.moveElements(elements, { x: 0, y: -150 }, subProcess);
|
||||
|
||||
// then
|
||||
expect(intermediateThrowEvent.parent).to.eql(subProcess);
|
||||
expect(intermediateThrowEvent.type).to.equal('bpmn:IntermediateThrowEvent');
|
||||
}));
|
||||
// then
|
||||
expect(intermediateThrowEvent.parent).to.eql(subProcess);
|
||||
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
|
||||
var intermediateThrowEvent = elementRegistry.get('IntermediateThrowEvent_1');
|
||||
describe('event attaching', function() {
|
||||
|
||||
var elements = [ intermediateThrowEvent ];
|
||||
var testXML = require('./BpmnRules.attaching.bpmn');
|
||||
|
||||
// then
|
||||
expectCanMove(elements, 'SubProcess_1', {
|
||||
beforeEach(bootstrapModeler(testXML, { modules: testModules }));
|
||||
|
||||
|
||||
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',
|
||||
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