Skip to content

Commit 63ccae1

Browse files
committed
feat: add _Binding_ entry
Related to camunda/camunda-modeler#4385
1 parent 26cfc66 commit 63ccae1

File tree

11 files changed

+444
-4
lines changed

11 files changed

+444
-4
lines changed

src/contextProvider/zeebe/TooltipProvider.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,23 @@ const TooltipProvider = {
278278
</p>
279279
</div>
280280
);
281+
},
282+
'bindingType': (element) => {
283+
284+
const translate = useService('translate');
285+
286+
return (
287+
<div>
288+
<p>
289+
<h1>{ translate('Latest binding') }</h1>
290+
{ translate('Uses the most recent deployed resource.') }
291+
</p>
292+
<p>
293+
<h1>{ translate('Deployment binding') }</h1>
294+
{ translate('Uses the resource found in the same deployment.') }
295+
</p>
296+
</div>
297+
);
281298
}
282299
};
283300

src/provider/HOCs/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
export { withProps } from './withProps';
12
export { withVariableContext } from './withVariableContext';
23
export { withTooltipContainer } from './withTooltipContainer';

src/provider/HOCs/withProps.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export function withProps(Component, otherProps) {
2+
return props => {
3+
return <Component { ...props } { ...otherProps } />;
4+
};
5+
}

src/provider/zeebe/properties/CalledDecisionProps.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ import {
44
} from 'bpmn-js/lib/util/ModelUtil';
55

66
import {
7-
TextFieldEntry, isTextFieldEntryEdited,
8-
isFeelEntryEdited
7+
isFeelEntryEdited,
8+
isSelectEntryEdited,
9+
isTextFieldEntryEdited,
10+
TextFieldEntry
911
} from '@bpmn-io/properties-panel';
1012

13+
import Binding from './shared/Binding';
14+
1115
import {
1216
getExtensionElementsList
1317
} from '../../../utils/ExtensionElementsUtil';
@@ -20,6 +24,7 @@ import { useService } from '../../../hooks';
2024

2125
import { FeelEntryWithVariableContext } from '../../../entries/FeelEntryWithContext';
2226

27+
import { withProps } from '../../HOCs/withProps.js';
2328

2429

2530
export function CalledDecisionProps(props) {
@@ -37,6 +42,11 @@ export function CalledDecisionProps(props) {
3742
component: DecisionID,
3843
isEdited: isFeelEntryEdited
3944
},
45+
{
46+
id: 'bindingType',
47+
component: withProps(Binding, { type: 'zeebe:CalledDecision' }),
48+
isEdited: isSelectEntryEdited
49+
},
4050
{
4151
id: 'resultVariable',
4252
component: ResultVariable,

src/provider/zeebe/properties/FormProps.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@ import {
1313
TextFieldEntry,
1414
TextAreaEntry,
1515
isFeelEntryEdited,
16+
isSelectEntryEdited,
1617
isTextFieldEntryEdited,
1718
isTextAreaEntryEdited
1819
} from '@bpmn-io/properties-panel';
1920

21+
import Binding from './shared/Binding';
22+
2023
import { FeelEntryWithVariableContext } from '../../../entries/FeelEntryWithContext';
2124

2225
import { createElement } from '../../../utils/ElementUtil';
@@ -34,6 +37,8 @@ import {
3437
userTaskFormIdToFormKey
3538
} from '../utils/FormUtil';
3639

40+
import { withProps } from '../../HOCs';
41+
3742
const NONE_VALUE = 'none';
3843

3944

@@ -78,6 +83,14 @@ export function FormProps(props) {
7883
});
7984
}
8085

86+
if (formType === FORM_TYPES.CAMUNDA_FORM_LINKED) {
87+
entries.push({
88+
id: 'bindingType',
89+
component: withProps(Binding, { type: 'zeebe:FormDefinition' }),
90+
isEdited: isSelectEntryEdited
91+
});
92+
}
93+
8194
return entries;
8295
}
8396

src/provider/zeebe/properties/TargetProps.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import {
44
} from 'bpmn-js/lib/util/ModelUtil';
55

66
import {
7-
isFeelEntryEdited
7+
isFeelEntryEdited,
8+
isSelectEntryEdited
89
} from '@bpmn-io/properties-panel';
910

11+
import Binding from './shared/Binding';
12+
1013
import {
1114
createElement
1215
} from '../../../utils/ElementUtil';
@@ -20,6 +23,8 @@ import { useService } from '../../../hooks';
2023

2124
import { FeelEntryWithVariableContext } from '../../../entries/FeelEntryWithContext';
2225

26+
import { withProps } from '../../HOCs/withProps.js';
27+
2328

2429
export function TargetProps(props) {
2530
const {
@@ -35,6 +40,11 @@ export function TargetProps(props) {
3540
id: 'targetProcessId',
3641
component: TargetProcessId,
3742
isEdited: isFeelEntryEdited
43+
},
44+
{
45+
id: 'bindingType',
46+
component: withProps(Binding, { type: 'zeebe:CalledElement' }),
47+
isEdited: isSelectEntryEdited
3848
}
3949
];
4050
}
@@ -128,4 +138,4 @@ function TargetProcessId(props) {
128138
setValue,
129139
debounce
130140
});
131-
}
141+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil';
2+
3+
import { SelectEntry } from '@bpmn-io/properties-panel';
4+
5+
import { createElement } from '../../../../utils/ElementUtil';
6+
7+
import { useService } from '../../../../hooks';
8+
9+
import { getExtensionElementsList } from '../../../../utils/ExtensionElementsUtil';
10+
11+
export default function Binding(props) {
12+
const {
13+
element,
14+
type
15+
} = props;
16+
17+
const bpmnFactory = useService('bpmnFactory'),
18+
commandStack = useService('commandStack'),
19+
translate = useService('translate');
20+
21+
const getValue = () => {
22+
const businessObject = getBusinessObject(element);
23+
24+
const extensionElement = getExtensionElementsList(businessObject, type)[ 0 ];
25+
26+
if (!extensionElement) {
27+
return 'latest';
28+
}
29+
30+
return extensionElement.get('bindingType');
31+
};
32+
33+
const setValue = value => {
34+
const commands = [];
35+
36+
const businessObject = getBusinessObject(element);
37+
38+
// (1) ensure extension elements
39+
let extensionElements = businessObject.get('extensionElements');
40+
41+
if (!extensionElements) {
42+
extensionElements = createElement(
43+
'bpmn:ExtensionElements',
44+
{ values: [] },
45+
businessObject,
46+
bpmnFactory
47+
);
48+
49+
commands.push({
50+
cmd: 'element.updateModdleProperties',
51+
context: {
52+
element,
53+
moddleElement: businessObject,
54+
properties: { extensionElements }
55+
}
56+
});
57+
}
58+
59+
// (2) ensure extension element
60+
let extensionElement = getExtensionElementsList(businessObject, type)[ 0 ];
61+
62+
if (!extensionElement) {
63+
extensionElement = createElement(
64+
type,
65+
{},
66+
extensionElements,
67+
bpmnFactory
68+
);
69+
70+
commands.push({
71+
cmd: 'element.updateModdleProperties',
72+
context: {
73+
element,
74+
moddleElement: extensionElements,
75+
properties: {
76+
values: [ ...extensionElements.get('values'), extensionElement ]
77+
}
78+
}
79+
});
80+
81+
}
82+
83+
// (3) Update bindingType attribute
84+
commands.push({
85+
cmd: 'element.updateModdleProperties',
86+
context: {
87+
element,
88+
moddleElement: extensionElement,
89+
properties: {
90+
bindingType: value
91+
}
92+
}
93+
});
94+
95+
// (4) Execute the commands
96+
commandStack.execute('properties-panel.multi-command-executor', commands);
97+
};
98+
99+
const getOptions = () => ([
100+
{ value: 'latest', label: translate('latest') },
101+
{ value: 'deployment', label: translate('deployment') }
102+
]);
103+
104+
return <SelectEntry
105+
element={ element }
106+
id="bindingType"
107+
label={ translate('Binding') }
108+
getValue={ getValue }
109+
setValue={ setValue }
110+
getOptions={ getOptions }
111+
/>;
112+
}

src/provider/zeebe/utils/CalledElementUtil.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ export function getProcessId(element) {
2525
return calledElement ? calledElement.get('processId') : '';
2626
}
2727

28+
export function getBindingType(element) {
29+
const calledElement = getCalledElement(element);
30+
31+
return calledElement ? calledElement.get('bindingType') : '';
32+
}
33+
2834
export function getCalledElement(element) {
2935
const calledElements = getCalledElements(element);
3036
return calledElements[0];

test/spec/provider/zeebe/CalledDecisionProps.spec.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,98 @@ describe('provider/zeebe - CalledDecisionProps', function() {
153153
});
154154

155155

156+
describe('#calledDecision.bindingType', function() {
157+
158+
it('should display', inject(async function(elementRegistry, selection) {
159+
160+
// given
161+
const businessRuleTask = elementRegistry.get('BusinessRuleTask_1');
162+
163+
// assume
164+
const bindingType = getBindingType(businessRuleTask);
165+
166+
expect(bindingType).to.equal('latest');
167+
168+
// when
169+
await act(() => {
170+
selection.select(businessRuleTask);
171+
});
172+
173+
const bindingTypeSelect = domQuery('select[name=bindingType]', container);
174+
175+
// then
176+
expect(bindingTypeSelect).to.exist;
177+
178+
expect(bindingTypeSelect.value).to.equal('latest');
179+
}));
180+
181+
182+
it('should not display', inject(async function(elementRegistry, selection) {
183+
184+
// given
185+
const task = elementRegistry.get('Task_1');
186+
187+
// when
188+
await act(() => {
189+
selection.select(task);
190+
});
191+
192+
const bindingTypeSelect = domQuery('select[name=bindingType]', container);
193+
194+
// then
195+
expect(bindingTypeSelect).not.to.exist;
196+
}));
197+
198+
199+
it('should update', inject(async function(elementRegistry, selection) {
200+
201+
// given
202+
const businessRuleTask = elementRegistry.get('BusinessRuleTask_1');
203+
204+
await act(() => {
205+
selection.select(businessRuleTask);
206+
});
207+
208+
const bindingTypeSelect = domQuery('select[name=bindingType]', container);
209+
210+
// when
211+
changeInput(bindingTypeSelect, 'deployment');
212+
213+
// then
214+
const bindingType = getBindingType(businessRuleTask);
215+
216+
expect(bindingType).to.equal('deployment');
217+
}));
218+
219+
220+
it('should update on external change',
221+
inject(async function(elementRegistry, selection, commandStack) {
222+
223+
// given
224+
const businessRuleTask = elementRegistry.get('BusinessRuleTask_1'),
225+
originalValue = getBindingType(businessRuleTask);
226+
227+
await act(() => {
228+
selection.select(businessRuleTask);
229+
});
230+
231+
const bindingTypeSelect = domQuery('select[name=bindingType]', container);
232+
233+
changeInput(bindingTypeSelect, 'deployment');
234+
235+
// when
236+
await act(() => {
237+
commandStack.undo();
238+
});
239+
240+
// then
241+
expect(getBindingType(businessRuleTask)).to.eql(originalValue);
242+
})
243+
);
244+
245+
});
246+
247+
156248
describe('#calledDecision.resultVariable', function() {
157249

158250
it('should display', inject(async function(elementRegistry, selection) {
@@ -255,6 +347,12 @@ export function getDecisionId(element) {
255347
return calledDecision ? calledDecision.get('decisionId') : '';
256348
}
257349

350+
export function getBindingType(element) {
351+
const calledDecision = getCalledDecision(element);
352+
353+
return calledDecision ? calledDecision.get('bindingType') : '';
354+
}
355+
258356
export function getResultVariable(element) {
259357
const calledDecision = getCalledDecision(element);
260358

0 commit comments

Comments
 (0)