Skip to content

Commit

Permalink
feat(camunda-platform): add input output behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
Niklas Kiefer committed Sep 7, 2021
1 parent 3993ad2 commit 6a25b23
Show file tree
Hide file tree
Showing 4 changed files with 346 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import inherits from 'inherits';

import {
getBusinessObject,
is
} from 'bpmn-js/lib/util/ModelUtil';

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

/**
* Camunda BPMN specific `camunda:inputOutput` behavior.
*/
export default function UpdateInputOutputBehavior(eventBus) {

CommandInterceptor.call(this, eventBus);

this.executed([ 'properties-panel.update-businessobject-list' ], function(context) {
const {
element
} = context;

const businessObject = getBusinessObject(element);
const inputOutput = getInputOutput(businessObject);
const extensionElements = businessObject.get('extensionElements');

// Remove camunda:inputOutput if there are no input/output parameters anymore.
if (inputOutput && isEmpty(inputOutput)) {
context.withRemovedInputOutput = extensionElements.values;

extensionElements.values = extensionElements.values.filter(function(element) {
element === inputOutput;
});
}
}, true);

this.reverted([ 'properties-panel.update-businessobject-list' ], function({ context }) {
const {
element,
withRemovedInputOutput: oldExtensionElements
} = context;

const businessObject = getBusinessObject(element);

// only intercept the revert, if the behavior became active
if (oldExtensionElements) {
const extensionElements = businessObject.extensionElements;

extensionElements.values = oldExtensionElements;
}
});
}


UpdateInputOutputBehavior.$inject = [
'eventBus'
];

inherits(UpdateInputOutputBehavior, CommandInterceptor);


// helper //////////////////

function getInputParameters(inputOutput) {
return inputOutput.get('inputParameters');
}

function getOutputParameters(inputOutput) {
return inputOutput.get('outputParameters');
}

function getInputOutput(businessObject) {
return (getExtensionElementsList(businessObject, 'camunda:InputOutput') || [])[0];
}

function getExtensionElementsList(businessObject, type = undefined) {
const elements = ((businessObject.get('extensionElements') &&
businessObject.get('extensionElements').get('values')) || []);

return (elements.length && type) ?
elements.filter((value) => is(value, type)) :
elements;
}

function isEmpty(inputOutput) {
const inputParameters = getInputParameters(inputOutput);
const outputParameters = getOutputParameters(inputOutput);

return inputParameters.length === 0 && outputParameters.length === 0;
}
3 changes: 3 additions & 0 deletions lib/camunda-platform/features/modeling/behavior/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import DeleteErrorEventDefinitionBehavior from './DeleteErrorEventDefinitionBehavior';
import DeleteRetryTimeCycleBehavior from './DeleteRetryTimeCycleBehavior';
import UpdateCamundaExclusiveBehavior from './UpdateCamundaExclusiveBehavior';
import UpdateInputOutputBehavior from './UpdateInputOutputBehavior';
import UpdateResultVariableBehavior from './UpdateResultVariableBehavior';

export default {
__init__: [
'deleteErrorEventDefinitionBehavior',
'deleteRetryTimeCycleBehavior',
'updateCamundaExclusiveBehavior',
'updateInputOutputBehavior',
'updateResultVariableBehavior'
],
deleteErrorEventDefinitionBehavior: [ 'type', DeleteErrorEventDefinitionBehavior ],
deleteRetryTimeCycleBehavior: [ 'type', DeleteRetryTimeCycleBehavior ],
updateCamundaExclusiveBehavior: [ 'type', UpdateCamundaExclusiveBehavior ],
updateInputOutputBehavior: [ 'type', UpdateInputOutputBehavior ],
updateResultVariableBehavior: [ 'type', UpdateResultVariableBehavior ]
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
import {
bootstrapCamundaPlatformModeler,
inject
} from 'test/TestHelper';

import {
getBusinessObject,
is
} from 'bpmn-js/lib/util/ModelUtil';

import coreModule from 'bpmn-js/lib/core';

import modelingModule from 'bpmn-js/lib/features/modeling';

import camundaModdleExtensions from 'camunda-bpmn-moddle/resources/camunda';

import camundaPlatformModelingModules from 'lib/camunda-platform/features/modeling';

import propertiesPanelCommandHandler from 'bpmn-js-properties-panel/lib/cmd';

import diagramXML from './camunda-input-output-diagram.bpmn';


describe('camunda-platform/features/modeling - UpdateInputOutputBehavior', function() {

const testModules = [
camundaPlatformModelingModules,
coreModule,
modelingModule,
propertiesPanelCommandHandler
];

const moddleExtensions = {
camunda: camundaModdleExtensions
};

beforeEach(bootstrapCamundaPlatformModeler(diagramXML, {
modules: testModules,
moddleExtensions
}));

describe('properties-panel.update-businessobject', function() {

it('should NOT execute if there are still parameters',
inject(function(elementRegistry, commandStack) {

// given
const shape = elementRegistry.get('ServiceTask_3');
const businessObject = getBusinessObject(shape);

const inputOutput = getInputOutput(businessObject);
const inputParameters = getInputParameters(inputOutput);

const context = {
element: shape,
currentObject: inputOutput,
propertyName: 'inputParameters',
objectsToRemove: inputParameters
};

// assume
expect(inputOutput).to.exist;

// when
commandStack.execute('properties-panel.update-businessobject-list', context);

// then
expect(getInputOutput(businessObject)).to.exist;
})
);


describe('delete last input parameter', function() {

let shape, context, businessObject;

beforeEach(inject(function(elementRegistry, commandStack) {

// given
shape = elementRegistry.get('ServiceTask_1');
businessObject = getBusinessObject(shape);

const inputOutput = getInputOutput(businessObject);
const inputParameters = getInputParameters(inputOutput);

context = {
element: shape,
currentObject: inputOutput,
propertyName: 'inputParameters',
objectsToRemove: inputParameters
};

// assume
expect(inputOutput).to.exist;

// when
commandStack.execute('properties-panel.update-businessobject-list', context);
}));


it('should execute', inject(function() {

// then
expect(getInputOutput(businessObject)).to.not.exist;
}));


it('should undo', inject(function(commandStack) {

// when
commandStack.undo();

// then
expect(getInputOutput(businessObject)).to.exist;
}));


it('should redo', inject(function(commandStack) {

// when
commandStack.undo();
commandStack.redo();

// then
expect(getInputOutput(businessObject)).to.not.exist;
}));

});


describe('delete last output parameter', function() {

let shape, context, businessObject;

beforeEach(inject(function(elementRegistry, commandStack) {

// given
shape = elementRegistry.get('ServiceTask_2');
businessObject = getBusinessObject(shape);

const inputOutput = getInputOutput(businessObject);
const outputParameters = getOutputParameters(inputOutput);

context = {
element: shape,
currentObject: inputOutput,
propertyName: 'outputParameters',
objectsToRemove: outputParameters
};

// assume
expect(inputOutput).to.exist;

// when
commandStack.execute('properties-panel.update-businessobject-list', context);
}));


it('should execute', inject(function() {

// then
expect(getInputOutput(businessObject)).to.not.exist;
}));


it('should undo', inject(function(commandStack) {

// when
commandStack.undo();

// then
expect(getInputOutput(businessObject)).to.exist;
}));


it('should redo', inject(function(commandStack) {

// when
commandStack.undo();
commandStack.redo();

// then
expect(getInputOutput(businessObject)).to.not.exist;
}));

});

});

});


// helper //////////////////

function getOutputParameters(inputOutput) {
return inputOutput.get('outputParameters');
}

function getInputParameters(inputOutput) {
return inputOutput.get('inputParameters');
}

function getInputOutput(businessObject) {
return (getExtensionElementsList(businessObject, 'camunda:InputOutput') || [])[0];
}

function getExtensionElementsList(businessObject, type = undefined) {
const elements = ((businessObject.get('extensionElements') &&
businessObject.get('extensionElements').get('values')) || []);

return (elements.length && type) ?
elements.filter((value) => is(value, type)) :
elements;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?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:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0uf0lod" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.10.0-nightly.20210902" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
<bpmn:process id="Process_1" isExecutable="true">
<bpmn:serviceTask id="ServiceTask_1">
<bpmn:extensionElements>
<camunda:inputOutput>
<camunda:inputParameter name="Input_1" />
</camunda:inputOutput>
</bpmn:extensionElements>
</bpmn:serviceTask>
<bpmn:serviceTask id="ServiceTask_2">
<bpmn:extensionElements>
<camunda:inputOutput>
<camunda:outputParameter name="Output_1" />
</camunda:inputOutput>
</bpmn:extensionElements>
</bpmn:serviceTask>
<bpmn:serviceTask id="ServiceTask_3">
<bpmn:extensionElements>
<camunda:inputOutput>
<camunda:inputParameter name="Input_1" />
<camunda:outputParameter name="Output_1" />
</camunda:inputOutput>
</bpmn:extensionElements>
</bpmn:serviceTask>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="Activity_0m9gwek_di" bpmnElement="ServiceTask_1">
<dc:Bounds x="160" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1maqshx_di" bpmnElement="ServiceTask_2">
<dc:Bounds x="160" y="190" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1w8u78i_di" bpmnElement="ServiceTask_3">
<dc:Bounds x="160" y="310" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

0 comments on commit 6a25b23

Please sign in to comment.