add multi instance configuration panel

This commit is contained in:
Elizabeth Esswein 2023-04-06 10:44:06 -04:00
parent 6391337a86
commit e504af9bb0
4 changed files with 395 additions and 0 deletions

View File

@ -10,6 +10,8 @@ import ConditionsPropertiesProvider from './conditions/propertiesPanel/Condition
import ExtensionsPropertiesProvider from './extensions/propertiesPanel/ExtensionsPropertiesProvider';
import MessagesPropertiesProvider from './messages/propertiesPanel/MessagesPropertiesProvider';
import CallActivityPropertiesProvider from './callActivity/propertiesPanel/CallActivityPropertiesProvider';
import StandardLoopPropertiesProvider from './loops/propertiesPanel/StandardLoopPropertiesProvider';
import MultiInstancePropertiesProvider from './loops/propertiesPanel/MultiInstancePropertiesProvider';
export default {
__depends__: [RulesModule],
@ -25,6 +27,8 @@ export default {
'ioRules',
'ioInterceptor',
'dataObjectRenderer',
'multiInstancePropertiesProvider',
'standardLoopPropertiesProvider',
],
dataObjectInterceptor: ['type', DataObjectInterceptor],
dataObjectRules: ['type', DataObjectRules],
@ -37,4 +41,6 @@ export default {
ioPalette: ['type', IoPalette],
ioRules: ['type', IoRules],
ioInterceptor: ['type', IoInterceptor],
multiInstancePropertiesProvider: ['type', MultiInstancePropertiesProvider],
standardLoopPropertiesProvider: ['type', StandardLoopPropertiesProvider],
};

View File

@ -0,0 +1,29 @@
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;
commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: loopCharacteristics,
properties: {
[propertyName]: value
}
});
}

View File

@ -0,0 +1,227 @@
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')) {
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);
let inputCollection = getLoopProperty(element, 'loopDataInputRef');
if (typeof(value) !== 'undefined' && typeof(inputCollection) !== 'undefined')
setLoopProperty(element, 'loopDataInputRef', undefined, 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);
let cardinality = getLoopProperty(element, 'loopCardinality');
if (typeof(value) !== 'undefined' && typeof(cardinality) !== 'undefined')
setLoopProperty(element, 'loopCardinality', undefined, 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 = bpmnFactory.create('bpmn:DataInput', {id: value, name: value});
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 = bpmnFactory.create('bpmn:DataOutput', {id: value, name: value});
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,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') &&
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
});
}