feat(modeling): add subprocess with start event included

When:

1. Creating expanded subprocess from palette.
2. Replacing task with expanded subprocess.
This commit is contained in:
Gustavo E. Jimenez Folta 2019-05-16 16:55:38 +02:00 committed by Nico Rehwaldt
parent 9e5a5f4944
commit 3a0f044d9e
4 changed files with 216 additions and 0 deletions

View File

@ -0,0 +1,69 @@
import inherits from 'inherits';
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
import { is } from '../../../util/ModelUtil';
import { isExpanded } from '../../../util/DiUtil.js';
/**
* Add start event child by default when creating an expanded subprocess
* with create.start or replacing a task with an expanded subprocess.
*/
export default function SubProcessStartEventBehavior(eventBus, modeling) {
CommandInterceptor.call(this, eventBus);
eventBus.on('create.start', function(event) {
var shape = event.context.shape,
hints = event.context.hints;
hints.shouldAddStartEvent = is(shape, 'bpmn:SubProcess') && isExpanded(shape);
});
this.postExecuted('shape.create', function(event) {
var shape = event.context.shape,
hints = event.context.hints,
position;
if (!hints.shouldAddStartEvent) {
return;
}
position = calculatePositionRelativeToShape(shape);
modeling.createShape({ type: 'bpmn:StartEvent' }, position, shape);
});
this.postExecuted('shape.replace', function(event) {
var oldShape = event.context.oldShape,
newShape = event.context.newShape,
position;
if (
!is(newShape, 'bpmn:SubProcess') ||
!is(oldShape, 'bpmn:Task') ||
!isExpanded(newShape)
) {
return;
}
position = calculatePositionRelativeToShape(newShape);
modeling.createShape({ type: 'bpmn:StartEvent' }, position, newShape);
});
}
SubProcessStartEventBehavior.$inject = [
'eventBus',
'modeling'
];
inherits(SubProcessStartEventBehavior, CommandInterceptor);
// helpers //////////
function calculatePositionRelativeToShape(shape) {
return {
x: shape.x + shape.width / 6,
y: shape.y + shape.height / 2
};
}

View File

@ -20,6 +20,7 @@ import RemoveParticipantBehavior from './RemoveParticipantBehavior';
import ReplaceElementBehaviour from './ReplaceElementBehaviour'; import ReplaceElementBehaviour from './ReplaceElementBehaviour';
import ResizeLaneBehavior from './ResizeLaneBehavior'; import ResizeLaneBehavior from './ResizeLaneBehavior';
import RemoveElementBehavior from './RemoveElementBehavior'; import RemoveElementBehavior from './RemoveElementBehavior';
import SubProcessStartEventBehavior from './SubProcessStartEventBehavior';
import ToggleElementCollapseBehaviour from './ToggleElementCollapseBehaviour'; import ToggleElementCollapseBehaviour from './ToggleElementCollapseBehaviour';
import UnclaimIdBehavior from './UnclaimIdBehavior'; import UnclaimIdBehavior from './UnclaimIdBehavior';
import UpdateFlowNodeRefsBehavior from './UpdateFlowNodeRefsBehavior'; import UpdateFlowNodeRefsBehavior from './UpdateFlowNodeRefsBehavior';
@ -50,6 +51,7 @@ export default {
'replaceElementBehaviour', 'replaceElementBehaviour',
'resizeLaneBehavior', 'resizeLaneBehavior',
'toggleElementCollapseBehaviour', 'toggleElementCollapseBehaviour',
'subProcessStartEventBehavior',
'unclaimIdBehavior', 'unclaimIdBehavior',
'unsetDefaultFlowBehavior', 'unsetDefaultFlowBehavior',
'updateFlowNodeRefsBehavior' 'updateFlowNodeRefsBehavior'
@ -77,6 +79,7 @@ export default {
resizeLaneBehavior: [ 'type', ResizeLaneBehavior ], resizeLaneBehavior: [ 'type', ResizeLaneBehavior ],
removeElementBehavior: [ 'type', RemoveElementBehavior ], removeElementBehavior: [ 'type', RemoveElementBehavior ],
toggleElementCollapseBehaviour : [ 'type', ToggleElementCollapseBehaviour ], toggleElementCollapseBehaviour : [ 'type', ToggleElementCollapseBehaviour ],
subProcessStartEventBehavior: [ 'type', SubProcessStartEventBehavior ],
unclaimIdBehavior: [ 'type', UnclaimIdBehavior ], unclaimIdBehavior: [ 'type', UnclaimIdBehavior ],
updateFlowNodeRefsBehavior: [ 'type', UpdateFlowNodeRefsBehavior ], updateFlowNodeRefsBehavior: [ 'type', UpdateFlowNodeRefsBehavior ],
unsetDefaultFlowBehavior: [ 'type', UnsetDefaultFlowBehavior ] unsetDefaultFlowBehavior: [ 'type', UnsetDefaultFlowBehavior ]

View File

@ -0,0 +1,17 @@
<?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" id="Definitions_007va6i" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.2.0-dev">
<bpmn:process id="Process_1giw3j5" isExecutable="true">
<bpmn:task id="Task_1" />
<bpmn:subProcess id="SubProcess_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1giw3j5">
<bpmndi:BPMNShape id="Task_07xra8r_di" bpmnElement="Task_1">
<dc:Bounds x="156" y="81" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="SubProcess_01nq2r1_di" bpmnElement="SubProcess_1" isExpanded="true">
<dc:Bounds x="160" y="280" width="350" height="200" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,127 @@
import {
bootstrapModeler,
inject
} from 'test/TestHelper';
import coreModule from 'lib/core';
import createModule from 'diagram-js/lib/features/create';
import draggingModule from 'diagram-js/lib/features/create';
import modelingModule from 'lib/features/modeling';
import replaceModule from 'lib/features/replace';
import { is } from 'lib/util/ModelUtil';
import { createCanvasEvent as canvasEvent } from 'test/util/MockEvents';
describe('features/modeling/behavior - subprocess start event', function() {
var diagramXML = require('./SubProcessBehavior.start-event.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: [
coreModule,
createModule,
draggingModule,
modelingModule,
replaceModule
]
}));
describe('create', function() {
it('should contain start event child', inject(
function(canvas, elementFactory, create, dragging) {
// given
var rootElement = canvas.getRootElement(),
subProcess = elementFactory.createShape({
type: 'bpmn:SubProcess',
isExpanded: true
}),
startEvents;
// when
create.start(canvasEvent({ x: 0, y: 0 }), subProcess);
dragging.hover({ element: rootElement });
dragging.move(canvasEvent({ x: 600, y: 150 }));
dragging.end();
// then
startEvents = getChildStartEvents(subProcess);
expect(startEvents).to.have.length(1);
}
));
});
describe('replace', function() {
describe('task -> expanded subprocess', function() {
it('should add start event child to subprocess', inject(
function(elementRegistry, bpmnReplace) {
// given
var task = elementRegistry.get('Task_1'),
expandedSubProcess,
startEvents;
// when
expandedSubProcess = bpmnReplace.replaceElement(task, {
type: 'bpmn:SubProcess',
isExpanded: true
});
// then
startEvents = getChildStartEvents(expandedSubProcess);
expect(startEvents).to.have.length(1);
}
));
});
describe('task -> collapsed subprocess', function() {
it('should NOT add start event child to subprocess', inject(
function(elementRegistry, bpmnReplace) {
// given
var task = elementRegistry.get('Task_1'),
collapsedSubProcess,
startEvents;
// when
collapsedSubProcess = bpmnReplace.replaceElement(task, {
type: 'bpmn:SubProcess',
isExpanded: false
});
// then
startEvents = getChildStartEvents(collapsedSubProcess);
expect(startEvents).to.have.length(0);
}
));
});
});
});
// helpers //////////
function isStartEvent(element) {
return is(element, 'bpmn:StartEvent');
}
function getChildStartEvents(element) {
return element.children.filter(isStartEvent);
}