diff --git a/src/contextProvider/zeebe/TooltipProvider.js b/src/contextProvider/zeebe/TooltipProvider.js
index f77c9403e..092498ff0 100644
--- a/src/contextProvider/zeebe/TooltipProvider.js
+++ b/src/contextProvider/zeebe/TooltipProvider.js
@@ -297,16 +297,41 @@ const TooltipProvider = {
);
},
'versionTag': (element) => {
-
const translate = useService('translate');
- return (
-
-
- { translate('Specifying a version tag will allow you to reference this process in another process.') }
-
-
- );
+ if (is(element, 'bpmn:Process')) {
+ return (
+
+
+ { translate('Version tag by which this process can be referenced.') }
+
+
+ );
+ } else if (is(element, 'bpmn:CallActivity')) {
+ return (
+
+
+ { translate('Version tag by which the called process will be referenced.') }
+
+
+ );
+ } else if (is(element, 'bpmn:BusinessRuleTask')) {
+ return (
+
+
+ { translate('Version tag by which the called decision will be referenced.') }
+
+
+ );
+ } else if (is(element, 'bpmn:UserTask')) {
+ return (
+
+
+ { translate('Version tag by which the linked form will be referenced.') }
+
+
+ );
+ }
},
'priorityDefinitionPriority': (element) => {
diff --git a/src/provider/zeebe/properties/CalledDecisionProps.js b/src/provider/zeebe/properties/CalledDecisionProps.js
index 83609ed7f..252365649 100644
--- a/src/provider/zeebe/properties/CalledDecisionProps.js
+++ b/src/provider/zeebe/properties/CalledDecisionProps.js
@@ -10,7 +10,8 @@ import {
TextFieldEntry
} from '@bpmn-io/properties-panel';
-import Binding from './shared/Binding';
+import Binding, { getBindingType } from './shared/Binding';
+import VersionTag from './shared/VersionTag.js';
import {
getExtensionElementsList
@@ -36,7 +37,7 @@ export function CalledDecisionProps(props) {
return [];
}
- return [
+ const entries = [
{
id: 'decisionId',
component: DecisionID,
@@ -46,13 +47,24 @@ export function CalledDecisionProps(props) {
id: 'bindingType',
component: withProps(Binding, { type: 'zeebe:CalledDecision' }),
isEdited: isSelectEntryEdited
- },
- {
- id: 'resultVariable',
- component: ResultVariable,
- isEdited: isTextFieldEntryEdited
}
];
+
+ if (getBindingType(element, 'zeebe:CalledDecision') === 'versionTag') {
+ entries.push({
+ id: 'versionTag',
+ component: withProps(VersionTag, { type: 'zeebe:CalledDecision' }),
+ isEdited: isTextFieldEntryEdited
+ });
+ }
+
+ entries.push({
+ id: 'resultVariable',
+ component: ResultVariable,
+ isEdited: isTextFieldEntryEdited
+ });
+
+ return entries;
}
function DecisionID(props) {
diff --git a/src/provider/zeebe/properties/FormProps.js b/src/provider/zeebe/properties/FormProps.js
index d863317d8..284979f10 100644
--- a/src/provider/zeebe/properties/FormProps.js
+++ b/src/provider/zeebe/properties/FormProps.js
@@ -18,7 +18,8 @@ import {
isTextAreaEntryEdited
} from '@bpmn-io/properties-panel';
-import Binding from './shared/Binding';
+import Binding, { getBindingType } from './shared/Binding';
+import VersionTag from './shared/VersionTag';
import { FeelEntryWithVariableContext } from '../../../entries/FeelEntryWithContext';
@@ -89,6 +90,14 @@ export function FormProps(props) {
component: withProps(Binding, { type: 'zeebe:FormDefinition' }),
isEdited: isSelectEntryEdited
});
+
+ if (getBindingType(element, 'zeebe:FormDefinition') === 'versionTag') {
+ entries.push({
+ id: 'versionTag',
+ component: withProps(VersionTag, { type: 'zeebe:FormDefinition' }),
+ isEdited: isTextFieldEntryEdited
+ });
+ }
}
return entries;
diff --git a/src/provider/zeebe/properties/TargetProps.js b/src/provider/zeebe/properties/TargetProps.js
index 98dce5e86..2ef720744 100644
--- a/src/provider/zeebe/properties/TargetProps.js
+++ b/src/provider/zeebe/properties/TargetProps.js
@@ -5,10 +5,12 @@ import {
import {
isFeelEntryEdited,
- isSelectEntryEdited
+ isSelectEntryEdited,
+ isTextFieldEntryEdited
} from '@bpmn-io/properties-panel';
-import Binding from './shared/Binding';
+import Binding, { getBindingType } from './shared/Binding';
+import VersionTag from './shared/VersionTag.js';
import {
createElement
@@ -35,7 +37,7 @@ export function TargetProps(props) {
return [];
}
- return [
+ const entries = [
{
id: 'targetProcessId',
component: TargetProcessId,
@@ -47,6 +49,16 @@ export function TargetProps(props) {
isEdited: isSelectEntryEdited
}
];
+
+ if (getBindingType(element, 'zeebe:CalledElement') === 'versionTag') {
+ entries.push({
+ id: 'versionTag',
+ component: withProps(VersionTag, { type: 'zeebe:CalledElement' }),
+ isEdited: isTextFieldEntryEdited
+ });
+ }
+
+ return entries;
}
function TargetProcessId(props) {
diff --git a/src/provider/zeebe/properties/shared/Binding.js b/src/provider/zeebe/properties/shared/Binding.js
index 7a563d889..c19235682 100644
--- a/src/provider/zeebe/properties/shared/Binding.js
+++ b/src/provider/zeebe/properties/shared/Binding.js
@@ -18,17 +18,7 @@ export default function Binding(props) {
commandStack = useService('commandStack'),
translate = useService('translate');
- const getValue = () => {
- const businessObject = getBusinessObject(element);
-
- const extensionElement = getExtensionElementsList(businessObject, type)[ 0 ];
-
- if (!extensionElement) {
- return 'latest';
- }
-
- return extensionElement.get('bindingType');
- };
+ const getValue = () => getBindingType(element, type);
const setValue = value => {
const commands = [];
@@ -98,7 +88,8 @@ export default function Binding(props) {
const getOptions = () => ([
{ value: 'latest', label: translate('latest') },
- { value: 'deployment', label: translate('deployment') }
+ { value: 'deployment', label: translate('deployment') },
+ { value: 'versionTag', label: translate('version tag') }
]);
return ;
+}
+
+export function getBindingType(element, type) {
+ const businessObject = getBusinessObject(element);
+
+ const extensionElement = getExtensionElementsList(businessObject, type)[ 0 ];
+
+ if (!extensionElement) {
+ return 'latest';
+ }
+
+ return extensionElement.get('bindingType');
}
\ No newline at end of file
diff --git a/src/provider/zeebe/properties/shared/VersionTag.js b/src/provider/zeebe/properties/shared/VersionTag.js
new file mode 100644
index 000000000..502be0d5c
--- /dev/null
+++ b/src/provider/zeebe/properties/shared/VersionTag.js
@@ -0,0 +1,110 @@
+import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil';
+
+import { TextFieldEntry } from '@bpmn-io/properties-panel';
+
+import { createElement } from '../../../../utils/ElementUtil';
+
+import { useService } from '../../../../hooks';
+
+import { getExtensionElementsList } from '../../../../utils/ExtensionElementsUtil';
+
+export default function VersionTag(props) {
+ const {
+ element,
+ type
+ } = props;
+
+ const bpmnFactory = useService('bpmnFactory'),
+ commandStack = useService('commandStack'),
+ debounce = useService('debounceInput'),
+ translate = useService('translate');
+
+ const getValue = () => getVersionTag(element, type);
+
+ const setValue = value => {
+ const commands = [];
+
+ const businessObject = getBusinessObject(element);
+
+ // (1) ensure extension elements
+ let extensionElements = businessObject.get('extensionElements');
+
+ if (!extensionElements) {
+ extensionElements = createElement(
+ 'bpmn:ExtensionElements',
+ { values: [] },
+ businessObject,
+ bpmnFactory
+ );
+
+ commands.push({
+ cmd: 'element.updateModdleProperties',
+ context: {
+ element,
+ moddleElement: businessObject,
+ properties: { extensionElements }
+ }
+ });
+ }
+
+ // (2) ensure extension element
+ let extensionElement = getExtensionElementsList(businessObject, type)[ 0 ];
+
+ if (!extensionElement) {
+ extensionElement = createElement(
+ type,
+ {},
+ extensionElements,
+ bpmnFactory
+ );
+
+ commands.push({
+ cmd: 'element.updateModdleProperties',
+ context: {
+ element,
+ moddleElement: extensionElements,
+ properties: {
+ values: [ ...extensionElements.get('values'), extensionElement ]
+ }
+ }
+ });
+
+ }
+
+ // (3) Update versionTag attribute
+ commands.push({
+ cmd: 'element.updateModdleProperties',
+ context: {
+ element,
+ moddleElement: extensionElement,
+ properties: {
+ versionTag: value
+ }
+ }
+ });
+
+ // (4) Execute the commands
+ commandStack.execute('properties-panel.multi-command-executor', commands);
+ };
+
+ return TextFieldEntry({
+ element,
+ id: 'versionTag',
+ label: translate('Version tag'),
+ getValue,
+ setValue,
+ debounce
+ });
+}
+
+export function getVersionTag(element, type) {
+ const businessObject = getBusinessObject(element);
+
+ const extensionElement = getExtensionElementsList(businessObject, type)[ 0 ];
+
+ if (!extensionElement) {
+ return '';
+ }
+
+ return extensionElement.get('versionTag') || '';
+}
\ No newline at end of file
diff --git a/test/spec/provider/zeebe/CalledDecisionProps.bpmn b/test/spec/provider/zeebe/CalledDecisionProps.bpmn
index 50760104a..c83f35831 100644
--- a/test/spec/provider/zeebe/CalledDecisionProps.bpmn
+++ b/test/spec/provider/zeebe/CalledDecisionProps.bpmn
@@ -7,7 +7,11 @@
-
+
+
+
+
+
@@ -22,4 +26,4 @@
-
+
\ No newline at end of file
diff --git a/test/spec/provider/zeebe/CalledDecisionProps.spec.js b/test/spec/provider/zeebe/CalledDecisionProps.spec.js
index f92724327..a373f167c 100644
--- a/test/spec/provider/zeebe/CalledDecisionProps.spec.js
+++ b/test/spec/provider/zeebe/CalledDecisionProps.spec.js
@@ -245,6 +245,98 @@ describe('provider/zeebe - CalledDecisionProps', function() {
});
+ describe('#calledDecision.versionTag', function() {
+
+ it('should display', inject(async function(elementRegistry, selection) {
+
+ // given
+ const businessRuleTask = elementRegistry.get('BusinessRuleTask_2');
+
+ // assume
+ const versionTag = getVersionTag(businessRuleTask);
+
+ expect(versionTag).to.equal('v1.0.0');
+
+ // when
+ await act(() => {
+ selection.select(businessRuleTask);
+ });
+
+ const versionTagInput = domQuery('input[name=versionTag]', container);
+
+ // then
+ expect(versionTagInput).to.exist;
+
+ expect(versionTagInput.value).to.equal('v1.0.0');
+ }));
+
+
+ it('should not display', inject(async function(elementRegistry, selection) {
+
+ // given
+ const task = elementRegistry.get('Task_1');
+
+ // when
+ await act(() => {
+ selection.select(task);
+ });
+
+ const versionTagInput = domQuery('input[name=versionTag]', container);
+
+ // then
+ expect(versionTagInput).not.to.exist;
+ }));
+
+
+ it('should update', inject(async function(elementRegistry, selection) {
+
+ // given
+ const businessRuleTask = elementRegistry.get('BusinessRuleTask_2');
+
+ await act(() => {
+ selection.select(businessRuleTask);
+ });
+
+ const versionTagInput = domQuery('input[name=versionTag]', container);
+
+ // when
+ changeInput(versionTagInput, 'v2.0.0');
+
+ // then
+ const versionTag = getVersionTag(businessRuleTask);
+
+ expect(versionTag).to.equal('v2.0.0');
+ }));
+
+
+ it('should update on external change',
+ inject(async function(elementRegistry, selection, commandStack) {
+
+ // given
+ const businessRuleTask = elementRegistry.get('BusinessRuleTask_2'),
+ originalValue = getVersionTag(businessRuleTask);
+
+ await act(() => {
+ selection.select(businessRuleTask);
+ });
+
+ const versionTagInput = domQuery('input[name=versionTag]', container);
+
+ changeInput(versionTagInput, 'v2.0.0');
+
+ // when
+ await act(() => {
+ commandStack.undo();
+ });
+
+ // then
+ expect(getVersionTag(businessRuleTask)).to.eql(originalValue);
+ })
+ );
+
+ });
+
+
describe('#calledDecision.resultVariable', function() {
it('should display', inject(async function(elementRegistry, selection) {
@@ -353,6 +445,12 @@ export function getBindingType(element) {
return calledDecision ? calledDecision.get('bindingType') : '';
}
+export function getVersionTag(element) {
+ const calledDecision = getCalledDecision(element);
+
+ return calledDecision ? calledDecision.get('versionTag') : '';
+}
+
export function getResultVariable(element) {
const calledDecision = getCalledDecision(element);
diff --git a/test/spec/provider/zeebe/Forms.bpmn b/test/spec/provider/zeebe/Forms.bpmn
index 87717bbec..c5d6f52b0 100644
--- a/test/spec/provider/zeebe/Forms.bpmn
+++ b/test/spec/provider/zeebe/Forms.bpmn
@@ -1,5 +1,5 @@
-
+
{}
@@ -37,37 +37,45 @@
+
+
+
+
+
-
-
-
-
-
+
-
-
-
-
-
+
-
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/spec/provider/zeebe/Forms.spec.js b/test/spec/provider/zeebe/Forms.spec.js
index f1baf1b54..4e9de85a8 100644
--- a/test/spec/provider/zeebe/Forms.spec.js
+++ b/test/spec/provider/zeebe/Forms.spec.js
@@ -540,6 +540,70 @@ describe('provider/zeebe - Forms', function() {
});
+
+ describe('version tag', function() {
+
+ it('should display', inject(async function(elementRegistry, selection) {
+
+ // given
+ const userTask = elementRegistry.get('CAMUNDA_FORM_LINKED_VERSION_TAG');
+
+ // when
+ await act(() => {
+ selection.select(userTask);
+ });
+
+ const versionTagInput = getVersionTagInput(container);
+
+ // then
+ expect(versionTagInput).to.exist;
+ }));
+
+
+ it('should update', inject(async function(elementRegistry, selection) {
+
+ // given
+ const userTask = elementRegistry.get('CAMUNDA_FORM_LINKED_VERSION_TAG');
+
+ await act(() => {
+ selection.select(userTask);
+ });
+
+ const versionTagInput = getVersionTagInput(container);
+
+ // when
+ changeInput(versionTagInput, 'v2.0.0');
+
+ // then
+ expectVersionTag(userTask, 'v2.0.0');
+ }));
+
+
+ it('should update on external change', inject(async function(commandStack, elementRegistry, selection) {
+
+ // given
+ const userTask = elementRegistry.get('CAMUNDA_FORM_LINKED_VERSION_TAG');
+
+ await act(() => {
+ selection.select(userTask);
+ });
+
+ const versionTagInput = getVersionTagInput(container);
+ const initialVersionTag = versionTagInput.value;
+
+ changeInput(versionTagInput, 'v2.0.0');
+ expectVersionTag(userTask, 'v2.0.0');
+
+ // when
+ await act(() => {
+ commandStack.undo();
+ });
+
+ expectVersionTag(userTask, initialVersionTag);
+ }));
+
+ });
+
});
@@ -769,6 +833,10 @@ function getBindingTypeSelect(container) {
return domQuery('select[name=bindingType]', container);
}
+function getVersionTagInput(container) {
+ return domQuery('input[name=versionTag]', container);
+}
+
function expectFormId(element, expected) {
const formDefinition = getFormDefinition(element);
@@ -783,6 +851,13 @@ function expectBindingType(element, expected) {
expect(formDefinition.get('bindingType')).to.eql(expected);
}
+function expectVersionTag(element, expected) {
+ const formDefinition = getFormDefinition(element);
+
+ expect(formDefinition).to.exist;
+ expect(formDefinition.get('versionTag')).to.eql(expected);
+}
+
function expectFormKey(element, expected) {
const formDefinition = getFormDefinition(element);
diff --git a/test/spec/provider/zeebe/TargetProps.bpmn b/test/spec/provider/zeebe/TargetProps.bpmn
index 7d60401d4..76e3831a7 100644
--- a/test/spec/provider/zeebe/TargetProps.bpmn
+++ b/test/spec/provider/zeebe/TargetProps.bpmn
@@ -1,5 +1,5 @@
-
+
@@ -20,7 +20,7 @@
-
+
diff --git a/test/spec/provider/zeebe/TargetProps.spec.js b/test/spec/provider/zeebe/TargetProps.spec.js
index 78156e561..3c5fe548e 100644
--- a/test/spec/provider/zeebe/TargetProps.spec.js
+++ b/test/spec/provider/zeebe/TargetProps.spec.js
@@ -28,6 +28,8 @@ import {
getProcessId
} from 'src/provider/zeebe/utils/CalledElementUtil.js';
+import { getVersionTag } from 'src/provider/zeebe/properties/shared/VersionTag';
+
import BpmnPropertiesPanel from 'src/render';
import CoreModule from 'bpmn-js/lib/core';
import ModelingModule from 'bpmn-js/lib/features/modeling';
@@ -316,4 +318,95 @@ describe('provider/zeebe - TargetProps', function() {
});
+
+ describe('bpmn:CallActivity#calledElement.versionTag', function() {
+
+ it('should display', inject(async function(elementRegistry, selection) {
+
+ // given
+ const callActivity = elementRegistry.get('CallActivity_4');
+
+ // assume
+ const versionTag = getVersionTag(callActivity);
+
+ expect(versionTag).to.equal('v1.0.0');
+
+ // when
+ await act(() => {
+ selection.select(callActivity);
+ });
+
+ const versionTagInput = domQuery('input[name=versionTag]', container);
+
+ // then
+ expect(versionTagInput).to.exist;
+
+ expect(versionTagInput.value).to.equal('v1.0.0');
+ }));
+
+
+ it('should not display', inject(async function(elementRegistry, selection) {
+
+ // given
+ const task = elementRegistry.get('Task_1');
+
+ // when
+ await act(() => {
+ selection.select(task);
+ });
+
+ const versionTagInput = domQuery('input[name=versionTag]', container);
+
+ // then
+ expect(versionTagInput).not.to.exist;
+ }));
+
+
+ it('should update', inject(async function(elementRegistry, selection) {
+
+ // given
+ const callActivity = elementRegistry.get('CallActivity_4');
+
+ await act(() => {
+ selection.select(callActivity);
+ });
+
+ const versionTagInput = domQuery('input[name=versionTag]', container);
+
+ // when
+ changeInput(versionTagInput, 'v2.0.0');
+
+ // then
+ const versionTag = getVersionTag(callActivity);
+
+ expect(versionTag).to.equal('v2.0.0');
+ }));
+
+
+ it('should update on external change',
+ inject(async function(elementRegistry, selection, commandStack) {
+
+ // given
+ const callActivity = elementRegistry.get('CallActivity_4'),
+ originalValue = getVersionTag(callActivity);
+
+ await act(() => {
+ selection.select(callActivity);
+ });
+
+ const versionTagInput = domQuery('input[name=versionTag]', container);
+ changeInput(versionTagInput, 'v2.0.0');
+
+ // when
+ await act(() => {
+ commandStack.undo();
+ });
+
+ // then
+ expect(getVersionTag(callActivity)).to.eql(originalValue);
+ })
+ );
+
+ });
+
});