Skip to content

Commit

Permalink
feat(cloud): allow to set error code as FEEL expression
Browse files Browse the repository at this point in the history
Closes #836
  • Loading branch information
barmac authored and nikku committed Dec 15, 2022
1 parent 3408f79 commit 7f73d0e
Show file tree
Hide file tree
Showing 6 changed files with 329 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ All notable changes to [bpmn-js-properties-panel](https://github.com/bpmn-io/bpm

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

* `FEAT`: allow to set error code as FEEL expression ([#836](https://github.com/bpmn-io/bpmn-js-properties-panel/issues/836))

## 1.13.1

* `FIX`: correctly element template defined `Dropdown` showing incorrect value
Expand Down
15 changes: 15 additions & 0 deletions src/provider/zeebe/ZeebePropertiesProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
BusinessRuleImplementationProps,
CalledDecisionProps,
ConditionProps,
ErrorProps,
FormProps,
HeaderProps,
InputProps,
Expand Down Expand Up @@ -57,6 +58,7 @@ export default class ZeebePropertiesProvider {
groups = groups.concat(this._getGroups(element));

// (2) update existing groups with zeebe specific properties
updateErrorGroup(groups, element);
updateMessageGroup(groups, element);
updateTimerGroup(groups, element, this._injector);
updateMultiInstanceGroup(groups, element);
Expand Down Expand Up @@ -257,6 +259,19 @@ function ExtensionPropertiesGroup(element, injector) {
return null;
}

function updateErrorGroup(groups, element) {
const errorGroup = findGroup(groups, 'error');

if (!errorGroup) {
return;
}

errorGroup.entries = overrideGenericEntries(
errorGroup.entries,
ErrorProps({ element })
);
}

function updateMessageGroup(groups, element) {
const messageGroup = findGroup(groups, 'message');

Expand Down
73 changes: 73 additions & 0 deletions src/provider/zeebe/properties/ErrorProps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import {
isFeelEntryEdited
} from '@bpmn-io/properties-panel';

import { useService } from '../../../hooks';


import {
getError
} from '../../bpmn/utils/EventDefinitionUtil';

import { FeelEntryWithContext } from '../../../entries/FeelEntryWithContext';


export function ErrorProps(props) {
const {
element
} = props;

const error = getError(element);

const entries = [];

if (error) {
entries.push(
{
id: 'errorCode',
component: ErrorCode,
isEdited: isFeelEntryEdited
}
);
}

return entries;
}


function ErrorCode(props) {
const { element } = props;

const commandStack = useService('commandStack');
const translate = useService('translate');
const debounce = useService('debounceInput');

const error = getError(element);

const getValue = () => {
return error.get('errorCode');
};

const setValue = (value) => {
return commandStack.execute(
'element.updateModdleProperties',
{
element,
moddleElement: error,
properties: {
errorCode: value
}
}
);
};

return FeelEntryWithContext({
element,
id: 'errorCode',
label: translate('Code'),
feel: 'optional',
getValue,
setValue,
debounce
});
}
1 change: 1 addition & 0 deletions src/provider/zeebe/properties/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { AssignmentDefinitionProps } from './AssignmentDefinitionProps';
export { BusinessRuleImplementationProps } from './BusinessRuleImplementationProps';
export { CalledDecisionProps } from './CalledDecisionProps';
export { ConditionProps } from './ConditionProps';
export { ErrorProps } from './ErrorProps';
export { FormProps } from './FormProps';
export { HeaderProps } from './HeaderProps';
export { InputProps } from './InputProps';
Expand Down
33 changes: 33 additions & 0 deletions test/spec/provider/zeebe/ErrorProps.bpmn
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?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:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0upqbpl" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.6.0" modeler:executionPlatform="Camunda Cloud" modeler:executionPlatformVersion="8.2.0">
<bpmn:process id="Process_17fhhp5" isExecutable="true">
<bpmn:task id="Activity_0n7ntz0" />
<bpmn:boundaryEvent id="ErrorEventNoExpression" name="Error Boundary Event (no expression)" attachedToRef="Activity_0n7ntz0">
<bpmn:errorEventDefinition id="ErrorEventDefinition_0ggzuvs" errorRef="ErrorNoExpression" />
</bpmn:boundaryEvent>
<bpmn:boundaryEvent id="ErrorEventWithExpression" name="Error Boundary Event (expression)" attachedToRef="Activity_0n7ntz0">
<bpmn:errorEventDefinition id="ErrorEventDefinition_02zwcmh" errorRef="ErrorWithExpression" />
</bpmn:boundaryEvent>
</bpmn:process>
<bpmn:error id="ErrorNoExpression" name="ErrorNoExpression" errorCode="myCode" />
<bpmn:error id="ErrorWithExpression" name="ErrorWithExpression" errorCode="=myCode" />
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_17fhhp5">
<bpmndi:BPMNShape id="Activity_0n7ntz0_di" bpmnElement="Activity_0n7ntz0">
<dc:Bounds x="180" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_0cfnu3k" bpmnElement="ErrorEventWithExpression">
<dc:Bounds x="162" y="142" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="145" y="185" width="75" height="40" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0uqj7t6_di" bpmnElement="ErrorEventNoExpression">
<dc:Bounds x="262" y="142" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="245" y="185" width="75" height="40" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
205 changes: 205 additions & 0 deletions test/spec/provider/zeebe/ErrorProps.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import TestContainer from 'mocha-test-container-support';

import {
act
} from '@testing-library/preact';

import {
bootstrapPropertiesPanel,
changeInput,
inject
} from 'test/TestHelper';

import {
query as domQuery
} from 'min-dom';

import CoreModule from 'bpmn-js/lib/core';
import SelectionModule from 'diagram-js/lib/features/selection';
import ModelingModule from 'bpmn-js/lib/features/modeling';

import BpmnPropertiesPanel from 'src/render';

// these properties can't live without the generic BPMN error props
import BpmnPropertiesProvider from 'src/provider/bpmn';
import ZeebePropertiesProvider from 'src/provider/zeebe';

import DescriptionProvider from 'src/contextProvider/zeebe/DescriptionProvider';

import zeebeModdleExtensions from 'zeebe-bpmn-moddle/resources/zeebe';

import {
getError
} from 'src/provider/bpmn/utils/EventDefinitionUtil';

import diagramXML from './ErrorProps.bpmn';
import { setEditorValue } from '../../../TestHelper';


describe('provider/zeebe - ErrorProps', function() {

const testModules = [
CoreModule,
SelectionModule,
ModelingModule,
BpmnPropertiesPanel,
BpmnPropertiesProvider,
ZeebePropertiesProvider
];

const moddleExtensions = {
zeebe: zeebeModdleExtensions
};

let container;

beforeEach(function() {
container = TestContainer.get(this);
});

beforeEach(bootstrapPropertiesPanel(diagramXML, {
modules: testModules,
moddleExtensions,
propertiesPanel: {
description: DescriptionProvider
},
debounceInput: false
}));


describe('bpmn:Error#errorCode', function() {

it('should display (text)', inject(async function(elementRegistry, selection) {

// given
const errorEvent = elementRegistry.get('ErrorEventNoExpression');

await act(() => {
selection.select(errorEvent);
});

// when
const errorCodeInput = domQuery('input[name=errorCode]', container);

// then
expect(errorCodeInput).to.exist;
}));


it('should display (FEEL expression)', inject(async function(elementRegistry, selection) {

// given
const errorEvent = elementRegistry.get('ErrorEventWithExpression');

await act(() => {
selection.select(errorEvent);
});

// when
const errorCodeInput = domQuery('[name=errorCode]', container);

// then
expect(errorCodeInput).to.exist;
}));


it('should display FEEL icon', inject(async function(elementRegistry, selection) {

// given
const errorEvent = elementRegistry.get('ErrorEventNoExpression');

await act(() => {
selection.select(errorEvent);
});

// when
const errorCodeIcon = domQuery('[data-entry-id="errorCode"] .bio-properties-panel-feel-icon', container);

// then
expect(errorCodeIcon).to.exist;
}));


it('should update (text)', inject(async function(elementRegistry, selection) {

// given
const errorEvent = elementRegistry.get('ErrorEventNoExpression');

await act(() => {
selection.select(errorEvent);
});

// when
const errorCodeInput = domQuery('input[name=errorCode]', container);
await act(() => {
changeInput(errorCodeInput, 'newValue');
});

// then
expect(getError(errorEvent).get('errorCode')).to.eql('newValue');
}));


it('should update (FEEL expression)', inject(async function(elementRegistry, selection) {

// given
const errorEvent = elementRegistry.get('ErrorEventWithExpression');

await act(() => {
selection.select(errorEvent);
});

// when
const errorCodeInput = domQuery('[name=errorCode] [role=textbox]', container);
await setEditorValue(errorCodeInput, 'newValue');

// then
expect(getError(errorEvent).get('errorCode')).to.eql('=newValue');
}));


it('should update on external change',
inject(async function(elementRegistry, selection, commandStack) {

// given
const errorEvent = elementRegistry.get('ErrorEventNoExpression');
const originalValue = getError(errorEvent).get('errorCode');

await act(() => {
selection.select(errorEvent);
});
const errorCodeInput = domQuery('input[name=errorCode]', container);
changeInput(errorCodeInput, 'newValue');

// when
await act(() => {
commandStack.undo();
});

// then
expect(errorCodeInput.value).to.eql(originalValue);
})
);


it('should not blow up on empty error code', inject(async function(elementRegistry, selection) {

// given
const errorEvent = elementRegistry.get('ErrorEventNoExpression');

await act(() => {
selection.select(errorEvent);
});

// when
const errorCodeInput = domQuery('input[name=errorCode]', container);
await act(() => {
changeInput(errorCodeInput, '');
});

// then
expect(getError(errorEvent).get('errorCode')).to.eql(undefined);
}));

});
});

0 comments on commit 7f73d0e

Please sign in to comment.