Enhance UX to fix multi instance bug (#75)

* Enhance UX to fix multi instance bug

* Multinstance changes commit

* Add removeloopProperty
This commit is contained in:
Ayoub Ait Lachgar 2024-06-25 21:22:38 +01:00 committed by GitHub
parent 91aa2f5933
commit c39627b959
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 583 additions and 386 deletions

View File

@ -16,8 +16,8 @@ import SignalPropertiesProvider from './signals/propertiesPanel/SignalProperties
import ErrorPropertiesProvider from './errors/propertiesPanel/ErrorPropertiesProvider';
import EscalationPropertiesProvider from './escalations/propertiesPanel/EscalationPropertiesProvider';
import CallActivityPropertiesProvider from './callActivity/propertiesPanel/CallActivityPropertiesProvider';
import StandardLoopPropertiesProvider from './loops/propertiesPanel/StandardLoopPropertiesProvider';
import MultiInstancePropertiesProvider from './loops/propertiesPanel/MultiInstancePropertiesProvider';
import StandardLoopPropertiesProvider from './loops/StandardLoopPropertiesProvider';
import MultiInstancePropertiesProvider from './loops/MultiInstancePropertiesProvider';
import CallActivityInterceptor from './callActivity/CallActivityInterceptor';
import MessageInterceptor from './messages/MessageInterceptor';

View File

@ -0,0 +1,83 @@
/* eslint-disable prettier/prettier */
/* eslint-disable no-param-reassign */
/* eslint-disable import/no-extraneous-dependencies */
import { is } from 'bpmn-js/lib/util/ModelUtil';
import { isTextFieldEntryEdited, isCheckboxEntryEdited } from '@bpmn-io/properties-panel';
import { InputItem } from './propertiesPanel/InputItemEntry';
import { LoopCardinality } from './propertiesPanel/LoopCardinalityEntry';
import { InputCollection } from './propertiesPanel/InputCollectionEntry';
import { OutputItem } from './propertiesPanel/OutputItemEntry';
import { OutputCollection } from './propertiesPanel/OutputCollectionEntry';
import { CompletionCondition } from './propertiesPanel/CompletionConditionEntry';
import { IsOutputElSync } from './propertiesPanel/IsIOSyncEntry';
const LOW_PRIORITY = 500;
export default function MultiInstancePropertiesProvider(propertiesPanel) {
this.getGroups = function getGroupsCallback(element) {
return function pushGroup(groups) {
if (
is(element, 'bpmn:Task') ||
is(element, 'bpmn:CallActivity') ||
is(element, 'bpmn:SubProcess')
) {
const group = groups.filter((g) => g.id === 'multiInstance');
if (group.length === 1) updateMultiInstanceGroup(element, group[0]);
}
return groups;
};
};
propertiesPanel.registerProvider(LOW_PRIORITY, this);
}
MultiInstancePropertiesProvider.$inject = ['propertiesPanel'];
function updateMultiInstanceGroup(element, group) {
group.entries = MultiInstanceProps({ element });
group.shouldOpen = true;
}
function MultiInstanceProps(props) {
const { element } = props;
const { businessObject } = element;
return [
{
id: 'loopCardinality',
component: LoopCardinality,
isEdited: isTextFieldEntryEdited,
},
{
id: 'loopDataInputRef',
component: InputCollection,
isEdited: isTextFieldEntryEdited,
},
{
id: 'dataInputItem',
component: InputItem,
isEdited: isTextFieldEntryEdited,
},
{
id: 'isOutputElSynchronized',
component: IsOutputElSync,
isEdited: isCheckboxEntryEdited,
},
{
id: 'loopDataOutputRef',
component: OutputCollection,
isEdited: isTextFieldEntryEdited,
},
!businessObject.get('spiffworkflow:isOutputSynced')
? {
id: 'dataOutputItem',
component: OutputItem,
isEdited: isTextFieldEntryEdited,
}
: {},
{
id: 'completionCondition',
component: CompletionCondition,
isEdited: isTextFieldEntryEdited,
},
];
}

View File

@ -1,133 +1,133 @@
import { is } from 'bpmn-js/lib/util/ModelUtil';
import { useService } from 'bpmn-js-properties-panel';
import {
Group,
TextFieldEntry,
isTextFieldEntryEdited,
CheckboxEntry,
isCheckboxEntryEdited,
} from '@bpmn-io/properties-panel';
import { getLoopProperty, setLoopProperty } from './LoopProperty';
const LOW_PRIORITY = 500;
export default function StandardLoopPropertiesProvider(propertiesPanel) {
this.getGroups = function getGroupsCallback(element) {
return function pushGroup(groups) {
if (
(is(element, 'bpmn:Task') || is(element, 'bpmn:CallActivity') || is(element, 'bpmn:SubProcess')) &&
typeof(element.businessObject.loopCharacteristics) !== 'undefined' &&
element.businessObject.loopCharacteristics.$type === 'bpmn:StandardLoopCharacteristics'
) {
const group = {
id: 'standardLoopCharacteristics',
component: Group,
label: 'Standard Loop',
entries: StandardLoopProps(element),
shouldOpen: true,
};
if (groups.length < 3)
groups.push(group);
else
groups.splice(2, 0, group);
}
return groups;
};
};
propertiesPanel.registerProvider(LOW_PRIORITY, this);
}
StandardLoopPropertiesProvider.$inject = ['propertiesPanel'];
function StandardLoopProps(props) {
const { element } = props;
return [{
id: 'loopMaximum',
component: LoopMaximum,
isEdited: isTextFieldEntryEdited
}, {
id: 'loopCondition',
component: LoopCondition,
isEdited: isTextFieldEntryEdited
}, {
id: 'testBefore',
component: TestBefore,
isEdited: isCheckboxEntryEdited
}];
}
function LoopMaximum(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'loopMaximum');
};
const setValue = value => {
setLoopProperty(element, 'loopMaximum', value, commandStack);
};
return TextFieldEntry({
element,
id: 'loopMaximum',
label: translate('Loop Maximum'),
getValue,
setValue,
debounce
});
}
function TestBefore(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'testBefore');
};
const setValue = value => {
setLoopProperty(element, 'testBefore', value, commandStack);
};
return CheckboxEntry({
element,
id: 'testBefore',
label: translate('Test Before'),
getValue,
setValue,
});
}
function LoopCondition(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'loopCondition');
};
const setValue = value => {
const loopCondition = bpmnFactory.create('bpmn:FormalExpression', {body: value})
setLoopProperty(element, 'loopCondition', loopCondition, commandStack);
};
return TextFieldEntry({
element,
id: 'loopCondition',
label: translate('Loop Condition'),
getValue,
setValue,
debounce
});
}
import { is } from 'bpmn-js/lib/util/ModelUtil';
import { useService } from 'bpmn-js-properties-panel';
import {
Group,
TextFieldEntry,
isTextFieldEntryEdited,
CheckboxEntry,
isCheckboxEntryEdited,
} from '@bpmn-io/properties-panel';
import { getLoopProperty, setLoopProperty } from './helpers';
const LOW_PRIORITY = 500;
export default function StandardLoopPropertiesProvider(propertiesPanel) {
this.getGroups = function getGroupsCallback(element) {
return function pushGroup(groups) {
if (
(is(element, 'bpmn:Task') || is(element, 'bpmn:CallActivity') || is(element, 'bpmn:SubProcess')) &&
typeof(element.businessObject.loopCharacteristics) !== 'undefined' &&
element.businessObject.loopCharacteristics.$type === 'bpmn:StandardLoopCharacteristics'
) {
const group = {
id: 'standardLoopCharacteristics',
component: Group,
label: 'Standard Loop',
entries: StandardLoopProps(element),
shouldOpen: true,
};
if (groups.length < 3)
groups.push(group);
else
groups.splice(2, 0, group);
}
return groups;
};
};
propertiesPanel.registerProvider(LOW_PRIORITY, this);
}
StandardLoopPropertiesProvider.$inject = ['propertiesPanel'];
function StandardLoopProps(props) {
const { element } = props;
return [{
id: 'loopMaximum',
component: LoopMaximum,
isEdited: isTextFieldEntryEdited
}, {
id: 'loopCondition',
component: LoopCondition,
isEdited: isTextFieldEntryEdited
}, {
id: 'testBefore',
component: TestBefore,
isEdited: isCheckboxEntryEdited
}];
}
function LoopMaximum(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'loopMaximum');
};
const setValue = value => {
setLoopProperty(element, 'loopMaximum', value, commandStack);
};
return TextFieldEntry({
element,
id: 'loopMaximum',
label: translate('Loop Maximum'),
getValue,
setValue,
debounce
});
}
function TestBefore(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'testBefore');
};
const setValue = value => {
setLoopProperty(element, 'testBefore', value, commandStack);
};
return CheckboxEntry({
element,
id: 'testBefore',
label: translate('Test Before'),
getValue,
setValue,
});
}
function LoopCondition(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'loopCondition');
};
const setValue = value => {
const loopCondition = bpmnFactory.create('bpmn:FormalExpression', {body: value})
setLoopProperty(element, 'loopCondition', loopCondition, commandStack);
};
return TextFieldEntry({
element,
id: 'loopCondition',
label: translate('Loop Condition'),
getValue,
setValue,
debounce
});
}

View File

@ -0,0 +1,54 @@
/* eslint-disable prettier/prettier */
/* eslint-disable no-param-reassign */
export function getLoopProperty(element, propertyName) {
const { loopCharacteristics } = element.businessObject;
const prop = loopCharacteristics.get(propertyName);
let value = '';
if (typeof (prop) !== 'object') {
value = prop;
} else if (typeof (prop) !== 'undefined') {
if (prop.$type === 'bpmn:FormalExpression')
value = prop.get('body');
else
value = prop.get('id');
}
return value;
}
export function setLoopProperty(element, propertyName, value, commandStack) {
const { loopCharacteristics } = element.businessObject;
if (typeof (value) === 'object') {
value.$parent = loopCharacteristics;
}
const properties = { [propertyName]: value };
if (propertyName === 'loopCardinality') properties.loopDataInputRef = undefined;
if (propertyName === 'loopDataInputRef') properties.loopCardinality = undefined;
commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: loopCharacteristics,
properties,
});
}
export function removeLoopProperty(element, propertyName, commandStack) {
const { loopCharacteristics } = element.businessObject;
const properties = { [propertyName]: undefined };
commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: loopCharacteristics,
properties,
});
}
export function setIsIOValue(element, value, commandStack) {
commandStack.execute('element.updateProperties', {
element,
properties: {
'spiffworkflow:isOutputSynced': value,
},
});
}

View File

@ -0,0 +1,46 @@
/* eslint-disable prettier/prettier */
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import/order */
import { useService } from "bpmn-js-properties-panel";
import { getLoopProperty, removeLoopProperty, setLoopProperty } from "../helpers";
import { TextFieldEntry } from '@bpmn-io/properties-panel';
export function CompletionCondition(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'completionCondition');
};
const setValue = (value) => {
if (!value || value === '') {
// If value is empty, remove completionCondition from XML
removeLoopProperty(element, 'completionCondition', commandStack);
return;
}
const completionCondition = bpmnFactory.create('bpmn:FormalExpression', {
body: value,
});
setLoopProperty(
element,
'completionCondition',
completionCondition,
commandStack
);
};
return TextFieldEntry({
element,
id: 'completionCondition',
label: translate('Completion Condition'),
getValue,
setValue,
debounce,
description: 'Stop executing this task when this condition is met',
});
}

View File

@ -0,0 +1,41 @@
/* eslint-disable prettier/prettier */
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import/order */
import { useService } from "bpmn-js-properties-panel";
import { getLoopProperty, removeLoopProperty, setLoopProperty } from "../helpers";
import { TextFieldEntry } from '@bpmn-io/properties-panel';
export function InputCollection(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'loopDataInputRef');
};
const setValue = (value) => {
if (!value || value === '') {
// If value is empty or undefined, remove loopDataInputRef from XML
removeLoopProperty(element, 'loopDataInputRef', commandStack);
return;
}
const collection = bpmnFactory.create('bpmn:ItemAwareElement', {
id: value,
});
setLoopProperty(element, 'loopDataInputRef', collection, commandStack);
};
return TextFieldEntry({
element,
id: 'loopDataInputRef',
label: translate('Input Collection'),
getValue,
setValue,
debounce,
description: 'Create an instance for each item in this collection',
});
}

View File

@ -0,0 +1,46 @@
/* eslint-disable prettier/prettier */
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import/order */
import { useService } from "bpmn-js-properties-panel";
import { getLoopProperty, setLoopProperty } from "../helpers";
import { TextFieldEntry } from '@bpmn-io/properties-panel';
export function InputItem(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'inputDataItem');
};
const setValue = (value) => {
const item =
typeof value !== 'undefined' && value !== ''
? bpmnFactory.create('bpmn:DataInput', { id: value, name: value })
: undefined;
setLoopProperty(element, 'inputDataItem', item, commandStack);
try {
const { businessObject } = element;
if (businessObject.get('spiffworkflow:isOutputSynced')) {
setLoopProperty(element, 'outputDataItem', item, commandStack);
}
} catch (error) {
console.log('Error caught while set value Input item', error);
}
};
return TextFieldEntry({
element,
id: 'inputDataItem',
label: translate('Input Element'),
getValue,
setValue,
debounce,
description: 'Each item in the collection will be copied to this variable',
});
}

View File

@ -0,0 +1,48 @@
/* eslint-disable prettier/prettier */
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import/order */
import { useService } from "bpmn-js-properties-panel";
import { getLoopProperty, removeLoopProperty, setIsIOValue, setLoopProperty } from "../helpers";
import { CheckboxEntry } from '@bpmn-io/properties-panel';
export function IsOutputElSync(props) {
const { element } = props;
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
const { businessObject } = element;
return businessObject.get('spiffworkflow:isOutputSynced')
? businessObject.get('spiffworkflow:isOutputSynced')
: false;
};
const setValue = (value) => {
if (value) {
const valIn = getLoopProperty(element, 'inputDataItem');
const item =
typeof valIn !== 'undefined' && valIn !== ''
? bpmnFactory.create('bpmn:DataOutput', { id: valIn, name: valIn })
: undefined;
if(item){
// If DataInput Item is found and set, add new DataOut with same value
setLoopProperty(element, 'outputDataItem', item, commandStack);
}
} else {
// Remove DataOutput value when isIoSync is disabled
removeLoopProperty(element, 'outputDataItem', commandStack);
}
setIsIOValue(element, value, commandStack);
};
return CheckboxEntry({
element,
id: 'testBefore',
label: translate('Output Element is Synchronized with Input Element'),
getValue,
setValue,
});
}

View File

@ -0,0 +1,41 @@
/* eslint-disable prettier/prettier */
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import/order */
import { useService } from "bpmn-js-properties-panel";
import { getLoopProperty, removeLoopProperty, setLoopProperty } from "../helpers";
import { TextFieldEntry } from '@bpmn-io/properties-panel';
export function LoopCardinality(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'loopCardinality');
};
const setValue = (value) => {
if (!value || value === '') {
// If value is empty or undefined, remove loopCardinality from XML
removeLoopProperty(element, 'loopCardinality', commandStack);
return;
}
const loopCardinality = bpmnFactory.create('bpmn:FormalExpression', {
body: value,
});
setLoopProperty(element, 'loopCardinality', loopCardinality, commandStack);
};
return TextFieldEntry({
element,
id: 'loopCardinality',
label: translate('Loop Cardinality'),
getValue,
setValue,
debounce,
description: 'Explicitly set the number of instances',
});
}

View File

@ -1,30 +0,0 @@
export function getLoopProperty(element, propertyName) {
const loopCharacteristics = element.businessObject.loopCharacteristics;
const prop = loopCharacteristics.get(propertyName);
let value = '';
if (typeof(prop) !== 'object') {
value = prop;
} else if (typeof(prop) !== 'undefined') {
if (prop.$type === 'bpmn:FormalExpression')
value = prop.get('body');
else
value = prop.get('id');
}
return value;
}
export function setLoopProperty(element, propertyName, value, commandStack) {
const loopCharacteristics = element.businessObject.loopCharacteristics;
if (typeof(value) === 'object')
value.$parent = loopCharacteristics;
let properties = { [propertyName]: value };
if (propertyName === 'loopCardinality') properties['loopDataInputRef'] = undefined;
if (propertyName === 'loopDataInputRef') properties['loopCardinality'] = undefined;
commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: loopCharacteristics,
properties: properties,
});
}

View File

@ -1,221 +0,0 @@
import { is } from 'bpmn-js/lib/util/ModelUtil';
import { useService } from 'bpmn-js-properties-panel';
import { TextFieldEntry, isTextFieldEntryEdited } from '@bpmn-io/properties-panel';
import { getLoopProperty, setLoopProperty } from './LoopProperty';
const LOW_PRIORITY = 500;
export default function MultiInstancePropertiesProvider(propertiesPanel) {
this.getGroups = function getGroupsCallback(element) {
return function pushGroup(groups) {
if (is(element, 'bpmn:Task') || is(element, 'bpmn:CallActivity') || is(element, 'bpmn:SubProcess')) {
let group = groups.filter(g => g.id == 'multiInstance');
if (group.length == 1)
updateMultiInstanceGroup(element, group[0]);
}
return groups;
};
};
propertiesPanel.registerProvider(LOW_PRIORITY, this);
}
MultiInstancePropertiesProvider.$inject = ['propertiesPanel'];
function updateMultiInstanceGroup(element, group) {
group.entries = MultiInstanceProps({element});
group.shouldOpen = true;
}
function MultiInstanceProps(props) {
const { element } = props;
const entries = [{
id: 'loopCardinality',
component: LoopCardinality,
isEdited: isTextFieldEntryEdited
}, {
id: 'loopDataInputRef',
component: InputCollection,
isEdited: isTextFieldEntryEdited
}, {
id: 'dataInputItem',
component: InputItem,
isEdited: isTextFieldEntryEdited
}, {
id: 'loopDataOutputRef',
component: OutputCollection,
isEdited: isTextFieldEntryEdited
}, {
id: 'dataOutputItem',
component: OutputItem,
isEdited: isTextFieldEntryEdited
}, {
id: 'completionCondition',
component: CompletionCondition,
isEdited: isTextFieldEntryEdited
}];
return entries;
}
function LoopCardinality(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'loopCardinality');
};
const setValue = value => {
const loopCardinality = bpmnFactory.create('bpmn:FormalExpression', {body: value})
setLoopProperty(element, 'loopCardinality', loopCardinality, commandStack);
};
return TextFieldEntry({
element,
id: 'loopCardinality',
label: translate('Loop Cardinality'),
getValue,
setValue,
debounce,
description: 'Explicitly set the number of instances'
});
}
function InputCollection(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'loopDataInputRef');
};
const setValue = value => {
const collection = bpmnFactory.create('bpmn:ItemAwareElement', {id: value});
setLoopProperty(element, 'loopDataInputRef', collection, commandStack);
};
return TextFieldEntry({
element,
id: 'loopDataInputRef',
label: translate('Input Collection'),
getValue,
setValue,
debounce,
description: 'Create an instance for each item in this collection'
});
}
function InputItem(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'inputDataItem');
};
const setValue = value => {
const item = (typeof(value) !== 'undefined') ? bpmnFactory.create('bpmn:DataInput', {id: value, name: value}) : undefined;
setLoopProperty(element, 'inputDataItem', item, commandStack);
};
return TextFieldEntry({
element,
id: 'inputDataItem',
label: translate('Input Element'),
getValue,
setValue,
debounce,
description: 'Each item in the collection will be copied to this variable'
});
}
function OutputCollection(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'loopDataOutputRef');
};
const setValue = value => {
const collection = bpmnFactory.create('bpmn:ItemAwareElement', {id: value});
setLoopProperty(element, 'loopDataOutputRef', collection, commandStack);
};
return TextFieldEntry({
element,
id: 'loopDataOutputRef',
label: translate('Output Collection'),
getValue,
setValue,
debounce,
description: 'Create or update this collection with the instance results'
});
}
function OutputItem(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'outputDataItem');
};
const setValue = value => {
const item = (typeof(value) !== 'undefined') ? bpmnFactory.create('bpmn:DataOutput', {id: value, name: value}) : undefined;
setLoopProperty(element, 'outputDataItem', item, commandStack);
};
return TextFieldEntry({
element,
id: 'outputDataItem',
label: translate('Output Element'),
getValue,
setValue,
debounce,
description: 'The value of this variable will be added to the output collection'
});
}
function CompletionCondition(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'completionCondition');
};
const setValue = value => {
const completionCondition = bpmnFactory.create('bpmn:FormalExpression', {body: value})
setLoopProperty(element, 'completionCondition', completionCondition, commandStack);
};
return TextFieldEntry({
element,
id: 'completionCondition',
label: translate('Completion Condition'),
getValue,
setValue,
debounce,
description: 'Stop executing this task when this condition is met'
});
}

View File

@ -0,0 +1,41 @@
/* eslint-disable prettier/prettier */
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import/order */
import { useService } from "bpmn-js-properties-panel";
import { getLoopProperty, removeLoopProperty, setLoopProperty } from "../helpers";
import { TextFieldEntry } from '@bpmn-io/properties-panel';
export function OutputCollection(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'loopDataOutputRef');
};
const setValue = (value) => {
if (!value || value === '') {
// If value is empty or undefined, remove loopDataOutputRef from XML
removeLoopProperty(element, 'loopDataOutputRef', commandStack);
return;
}
const collection = bpmnFactory.create('bpmn:ItemAwareElement', {
id: value,
});
setLoopProperty(element, 'loopDataOutputRef', collection, commandStack);
};
return TextFieldEntry({
element,
id: 'loopDataOutputRef',
label: translate('Output Collection'),
getValue,
setValue,
debounce,
description: 'Create or update this collection with the instance results',
});
}

View File

@ -0,0 +1,48 @@
/* eslint-disable prettier/prettier */
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import/order */
import { useService } from "bpmn-js-properties-panel";
import { getLoopProperty, setLoopProperty } from "../helpers";
import { TextFieldEntry } from '@bpmn-io/properties-panel';
export function OutputItem(props) {
const { element } = props;
const debounce = useService('debounceInput');
const translate = useService('translate');
const commandStack = useService('commandStack');
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
return getLoopProperty(element, 'outputDataItem');
};
const setValue = (value) => {
try {
const inVal = getLoopProperty(element, 'inputDataItem');
if (inVal === value) {
alert( 'You have entered the same value for both Input and Output elements without enabling synchronization. Please confirm if this is intended.' );
return;
}
} catch (error) {
console.log('Error caught while Set Value OutputItem', error);
}
const item =
typeof value !== 'undefined' && value !== ''
? bpmnFactory.create('bpmn:DataOutput', { id: value, name: value })
: undefined;
setLoopProperty(element, 'outputDataItem', item, commandStack);
};
return TextFieldEntry({
element,
id: 'outputDataItem',
label: translate('Output Element'),
getValue,
setValue,
debounce,
description:
'The value of this variable will be added to the output collection',
});
}