mirror of
https://github.com/status-im/spiff-arena.git
synced 2025-02-13 02:06:47 +00:00
Merge commit '7db152f01049e0b788ccbfd3ce2358987df67cdc'
This commit is contained in:
commit
b9fd9279e0
@ -15,7 +15,7 @@ jobs:
|
||||
steps:
|
||||
- name: Dependabot metadata
|
||||
id: metadata
|
||||
uses: dependabot/fetch-metadata@v1.4.0
|
||||
uses: dependabot/fetch-metadata@v1.6.0
|
||||
with:
|
||||
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
- name: Enable auto-merge for Dependabot PRs
|
||||
|
@ -20,7 +20,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3 #Checkout Repo
|
||||
- uses: actions/setup-node@v3 #Setup Node
|
||||
- uses: nanasess/setup-chromedriver@v1
|
||||
- uses: nanasess/setup-chromedriver@v2 #Setup ChromeDriver
|
||||
with:
|
||||
node-version: '18'
|
||||
- name: Run Karma Tests
|
||||
|
@ -20,6 +20,7 @@ let bpmnModeler;
|
||||
try {
|
||||
bpmnModeler = new BpmnModeler({
|
||||
container: modelerEl,
|
||||
keyboard: { bindTo: document },
|
||||
propertiesPanel: {
|
||||
parent: panelEl,
|
||||
},
|
||||
@ -41,9 +42,6 @@ try {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// import XML
|
||||
bpmnModeler.importXML(diagramXML).then(() => {});
|
||||
|
||||
/**
|
||||
* It is possible to populate certain components using API calls to
|
||||
* a backend. Here we mock out the API call, but this gives you
|
||||
@ -191,6 +189,23 @@ bpmnModeler.on('spiff.callactivity.search', (event) => {
|
||||
});
|
||||
});
|
||||
|
||||
/* This restores unresolved references that camunda removes */
|
||||
|
||||
bpmnModeler.on('import.parse.complete', event => {
|
||||
const refs = event.references.filter(r => r.property === 'bpmn:loopDataInputRef' || r.property === 'bpmn:loopDataOutputRef');
|
||||
const desc = bpmnModeler._moddle.registry.getEffectiveDescriptor('bpmn:ItemAwareElement');
|
||||
refs.forEach(ref => {
|
||||
const props = {
|
||||
id: ref.id,
|
||||
name: ref.id ? typeof(ref.name) === 'undefined': ref.name,
|
||||
};
|
||||
let elem = bpmnModeler._moddle.create(desc, props);
|
||||
elem.$parent = ref.element;
|
||||
ref.element.set(ref.property, elem);
|
||||
});
|
||||
});
|
||||
|
||||
bpmnModeler.importXML(diagramXML).then(() => {});
|
||||
|
||||
// This handles the download and upload buttons - it isn't specific to
|
||||
// the BPMN modeler or these extensions, just a quick way to allow you to
|
||||
|
@ -12,6 +12,7 @@ export default function setupFileOperations(bpmnModeler) {
|
||||
* Just a quick bit of code so we can save the XML that is output.
|
||||
* Helps for debugging against other libraries (like SpiffWorkflow)
|
||||
*/
|
||||
|
||||
const btn = document.getElementById('downloadButton');
|
||||
btn.addEventListener('click', (_event) => {
|
||||
saveXML();
|
||||
@ -29,12 +30,8 @@ export default function setupFileOperations(bpmnModeler) {
|
||||
*/
|
||||
const uploadBtn = document.getElementById('uploadButton');
|
||||
uploadBtn.addEventListener('click', (_event) => {
|
||||
openFile(displayFile);
|
||||
openFile(bpmnModeler);
|
||||
});
|
||||
|
||||
function displayFile(contents) {
|
||||
bpmnModeler.importXML(contents).then(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
function clickElem(elem) {
|
||||
@ -59,7 +56,7 @@ function clickElem(elem) {
|
||||
elem.dispatchEvent(eventMouse);
|
||||
}
|
||||
|
||||
export function openFile(func) {
|
||||
export function openFile(bpmnModeler) {
|
||||
const readFile = function readFileCallback(e) {
|
||||
const file = e.target.files[0];
|
||||
if (!file) {
|
||||
@ -68,7 +65,7 @@ export function openFile(func) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function onloadCallback(onloadEvent) {
|
||||
const contents = onloadEvent.target.result;
|
||||
fileInput.func(contents);
|
||||
bpmnModeler.importXML(contents);
|
||||
document.body.removeChild(fileInput);
|
||||
};
|
||||
reader.readAsText(file);
|
||||
@ -77,7 +74,6 @@ export function openFile(func) {
|
||||
fileInput.type = 'file';
|
||||
fileInput.style.display = 'none';
|
||||
fileInput.onchange = readFile;
|
||||
fileInput.func = func;
|
||||
document.body.appendChild(fileInput);
|
||||
clickElem(fileInput);
|
||||
}
|
||||
|
@ -36,6 +36,9 @@ export function findDataObject(process, id) {
|
||||
}
|
||||
|
||||
export function findDataObjectReferences(children, dataObjectId) {
|
||||
if (children == null) {
|
||||
return [];
|
||||
}
|
||||
return children.flatMap((child) => {
|
||||
if (child.$type == 'bpmn:DataObjectReference' && child.dataObjectRef.id == dataObjectId)
|
||||
return [child];
|
||||
@ -58,7 +61,7 @@ export function findDataObjectReferenceShapes(children, dataObjectId) {
|
||||
}
|
||||
|
||||
export function idToHumanReadableName(id) {
|
||||
const words = id.match(/[A-Za-z][a-z]*/g) || [id];
|
||||
const words = id.match(/[A-Za-z][a-z]*|[0-9]+/g) || [id];
|
||||
return words.map(capitalize).join(' ');
|
||||
|
||||
function capitalize(word) {
|
||||
|
@ -42,7 +42,10 @@ export default class DataObjectInterceptor extends CommandInterceptor {
|
||||
// when the shape is deleted, but not interested in refactoring at the moment.
|
||||
if (realParent != null) {
|
||||
const flowElements = realParent.get('flowElements');
|
||||
flowElements.push(businessObject);
|
||||
const existingElement = flowElements.find(i => i.id === 1);
|
||||
if (!existingElement) {
|
||||
flowElements.push(businessObject);
|
||||
}
|
||||
}
|
||||
} else if (is(businessObject, 'bpmn:DataObject')) {
|
||||
// For data objects, only update the flowElements for new data objects, and set the parent so it doesn't get moved.
|
||||
@ -120,12 +123,17 @@ export default class DataObjectInterceptor extends CommandInterceptor {
|
||||
const { shape } = context;
|
||||
if (is(shape, 'bpmn:DataObjectReference') && shape.type !== 'label') {
|
||||
const dataObject = shape.businessObject.dataObjectRef;
|
||||
let flowElements = shape.businessObject.$parent.get('flowElements');
|
||||
let parent = shape.businessObject.$parent;
|
||||
if (parent.processRef) {
|
||||
// Our immediate parent may be a pool, so we need to get the process
|
||||
parent = parent.processRef;
|
||||
}
|
||||
const flowElements = parent.get('flowElements');
|
||||
collectionRemove(flowElements, shape.businessObject);
|
||||
let references = findDataObjectReferences(flowElements, dataObject.id);
|
||||
const references = findDataObjectReferences(flowElements, dataObject.id);
|
||||
if (references.length === 0) {
|
||||
let flowElements = dataObject.$parent.get('flowElements');
|
||||
collectionRemove(flowElements, dataObject);
|
||||
const dataFlowElements = dataObject.$parent.get('flowElements');
|
||||
collectionRemove(dataFlowElements, dataObject);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -31,7 +31,8 @@ export function DataObjectSelect(props) {
|
||||
|
||||
const setValue = value => {
|
||||
const businessObject = element.businessObject;
|
||||
for (const flowElem of businessObject.$parent.flowElements) {
|
||||
const dataObjects = findDataObjects(businessObject.$parent)
|
||||
for (const flowElem of dataObjects) {
|
||||
if (flowElem.$type === 'bpmn:DataObject' && flowElem.id === value) {
|
||||
commandStack.execute('element.updateModdleProperties', {
|
||||
element,
|
||||
|
6
bpmn-js-spiffworkflow/app/spiffworkflow/errors/index.js
Normal file
6
bpmn-js-spiffworkflow/app/spiffworkflow/errors/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
import ErrorPropertiesProvider from './propertiesPanel/ErrorPropertiesProvider';
|
||||
|
||||
export default {
|
||||
__init__: ['errorPropertiesProvider'],
|
||||
errorPropertiesProvider: ['type', ErrorPropertiesProvider],
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
import { is } from 'bpmn-js/lib/util/ModelUtil';
|
||||
import { getRoot } from '../../helpers';
|
||||
import { getArrayForType, getListGroupForType } from '../../eventList.js';
|
||||
import { hasEventType,
|
||||
replaceGroup,
|
||||
getSelectorForType,
|
||||
getConfigureGroupForType
|
||||
} from '../../eventSelect.js';
|
||||
|
||||
const LOW_PRIORITY = 500;
|
||||
|
||||
const eventDetails = {
|
||||
'eventType': 'bpmn:Error',
|
||||
'eventDefType': 'bpmn:ErrorEventDefinition',
|
||||
'referenceType': 'errorRef',
|
||||
'idPrefix': 'error',
|
||||
};
|
||||
|
||||
export default function ErrorPropertiesProvider(
|
||||
propertiesPanel,
|
||||
translate,
|
||||
moddle,
|
||||
commandStack,
|
||||
) {
|
||||
|
||||
this.getGroups = function (element) {
|
||||
return function (groups) {
|
||||
if (is(element, 'bpmn:Process') || is(element, 'bpmn:Collaboration')) {
|
||||
const getErrorArray = getArrayForType('bpmn:Error', 'errorRef', 'Error');
|
||||
const errorGroup = getListGroupForType('errors', 'Errors', getErrorArray);
|
||||
groups.push(errorGroup({ element, translate, moddle, commandStack }));
|
||||
} else if (hasEventType(element, 'bpmn:ErrorEventDefinition')) {
|
||||
const getErrorSelector = getSelectorForType(eventDetails);
|
||||
const errorGroup = getConfigureGroupForType(eventDetails, 'Error', true, getErrorSelector);
|
||||
const group = errorGroup({ element, translate, moddle, commandStack });
|
||||
replaceGroup('error', groups, group);
|
||||
}
|
||||
return groups;
|
||||
};
|
||||
};
|
||||
propertiesPanel.registerProvider(LOW_PRIORITY, this);
|
||||
}
|
||||
|
||||
ErrorPropertiesProvider.$inject = [
|
||||
'propertiesPanel',
|
||||
'translate',
|
||||
'moddle',
|
||||
'commandStack',
|
||||
];
|
@ -0,0 +1,6 @@
|
||||
import EscalationPropertiesProvider from './propertiesPanel/EscalationPropertiesProvider';
|
||||
|
||||
export default {
|
||||
__init__: ['escalationPropertiesProvider'],
|
||||
escalationrrorPropertiesProvider: ['type', EscalationPropertiesProvider],
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
import { is } from 'bpmn-js/lib/util/ModelUtil';
|
||||
import { getRoot } from '../../helpers';
|
||||
import { getArrayForType, getListGroupForType } from '../../eventList.js';
|
||||
import { hasEventType,
|
||||
replaceGroup,
|
||||
getSelectorForType,
|
||||
getConfigureGroupForType
|
||||
} from '../../eventSelect.js';
|
||||
|
||||
const LOW_PRIORITY = 500;
|
||||
|
||||
const eventDetails = {
|
||||
'eventType': 'bpmn:Escalation',
|
||||
'eventDefType': 'bpmn:EscalationEventDefinition',
|
||||
'referenceType': 'escalationRef',
|
||||
'idPrefix': 'escalation',
|
||||
};
|
||||
|
||||
export default function EscalationPropertiesProvider(
|
||||
propertiesPanel,
|
||||
translate,
|
||||
moddle,
|
||||
commandStack,
|
||||
) {
|
||||
|
||||
this.getGroups = function (element) {
|
||||
return function (groups) {
|
||||
if (is(element, 'bpmn:Process') || is(element, 'bpmn:Collaboration')) {
|
||||
const getEscalationArray = getArrayForType('bpmn:Escalation', 'escalationRef', 'Escalation');
|
||||
const escalationGroup = getListGroupForType('escalations', 'Escalations', getEscalationArray);
|
||||
groups.push(escalationGroup({ element, translate, moddle, commandStack }));
|
||||
} else if (hasEventType(element, 'bpmn:EscalationEventDefinition')) {
|
||||
const getEscalationSelector = getSelectorForType(eventDetails);
|
||||
const escalationGroup = getConfigureGroupForType(eventDetails, 'Escalation', true, getEscalationSelector);
|
||||
const group = escalationGroup({ element, translate, moddle, commandStack });
|
||||
replaceGroup('escalation', groups, group);
|
||||
}
|
||||
return groups;
|
||||
};
|
||||
};
|
||||
propertiesPanel.registerProvider(LOW_PRIORITY, this);
|
||||
}
|
||||
|
||||
EscalationPropertiesProvider.$inject = [
|
||||
'propertiesPanel',
|
||||
'translate',
|
||||
'moddle',
|
||||
'commandStack',
|
||||
];
|
163
bpmn-js-spiffworkflow/app/spiffworkflow/eventList.js
Normal file
163
bpmn-js-spiffworkflow/app/spiffworkflow/eventList.js
Normal file
@ -0,0 +1,163 @@
|
||||
import { is } from 'bpmn-js/lib/util/ModelUtil';
|
||||
import { useService } from 'bpmn-js-properties-panel';
|
||||
import {
|
||||
ListGroup,
|
||||
TextFieldEntry,
|
||||
isTextFieldEntryEdited
|
||||
} from '@bpmn-io/properties-panel';
|
||||
import { getRoot } from './helpers';
|
||||
|
||||
/* This function creates a list of a particular event type at the process level using the item list
|
||||
* and add function provided by `getArray`.
|
||||
*
|
||||
* Usage:
|
||||
* const getArray = getArrayForType('bpmn:Signal', 'signalRef', 'Signal');
|
||||
* const signalGroup = createGroupForType('signals', 'Signals', getArray);
|
||||
*/
|
||||
|
||||
function getListGroupForType(groupId, label, getArray) {
|
||||
|
||||
return function (props) {
|
||||
const { element, translate, moddle, commandStack } = props;
|
||||
const eventArray = {
|
||||
id: groupId,
|
||||
element,
|
||||
label: label,
|
||||
component: ListGroup,
|
||||
...getArray({ element, moddle, commandStack, translate }),
|
||||
};
|
||||
|
||||
if (eventArray.items) {
|
||||
return eventArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getArrayForType(itemType, referenceType, prefix) {
|
||||
|
||||
return function (props) {
|
||||
const { element, moddle, commandStack, translate } = props;
|
||||
const root = getRoot(element.businessObject);
|
||||
const matching = root.rootElements ? root.rootElements.filter(elem => elem.$type === itemType) : [];
|
||||
|
||||
function removeModelReferences(flowElements, match) {
|
||||
flowElements.map(elem => {
|
||||
if (elem.eventDefinitions)
|
||||
elem.eventDefinitions = elem.eventDefinitions.filter(def => def.get(referenceType) != match);
|
||||
else if (elem.flowElements)
|
||||
removeModelReferences(elem.flowElements, match);
|
||||
});
|
||||
}
|
||||
|
||||
function removeElementReferences(children, match) {
|
||||
children.map(child => {
|
||||
if (child.businessObject.eventDefinitions) {
|
||||
const bo = child.businessObject;
|
||||
bo.eventDefinitions = bo.eventDefinitions.filter(def => def.get(referenceType) != match);
|
||||
commandStack.execute('element.updateProperties', {
|
||||
element: child,
|
||||
moddleElement: bo,
|
||||
properties: {}
|
||||
});
|
||||
}
|
||||
if (child.children)
|
||||
removeElementReferences(child.children, match);
|
||||
});
|
||||
}
|
||||
|
||||
function removeFactory(item) {
|
||||
return function (event) {
|
||||
event.stopPropagation();
|
||||
if (root.rootElements) {
|
||||
root.rootElements = root.rootElements.filter(elem => elem != item);
|
||||
// This updates visible elements
|
||||
removeElementReferences(element.children, item);
|
||||
// This handles everything else (eg collapsed subprocesses) but does not update the shapes
|
||||
// I can't figure out how to do that
|
||||
root.rootElements.filter(elem => elem.$type === 'bpmn:Process').map(
|
||||
process => removeModelReferences(process.flowElements, item)
|
||||
);
|
||||
commandStack.execute('element.updateProperties', {
|
||||
element,
|
||||
properties: {},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const items = matching.map((item, idx) => {
|
||||
const itemId = `${prefix}-${idx}`;
|
||||
return {
|
||||
id: itemId,
|
||||
label: item.name,
|
||||
entries: getItemEditor({
|
||||
itemId,
|
||||
element,
|
||||
item,
|
||||
commandStack,
|
||||
translate,
|
||||
}),
|
||||
autoFocusEntry: itemId,
|
||||
remove: removeFactory(item),
|
||||
};
|
||||
});
|
||||
|
||||
function add(event) {
|
||||
event.stopPropagation();
|
||||
const item = moddle.create(itemType);
|
||||
item.id = moddle.ids.nextPrefixed(`${prefix}_`);
|
||||
item.name = item.id;
|
||||
if (root.rootElements)
|
||||
root.rootElements.push(item);
|
||||
commandStack.execute('element.updateProperties', {
|
||||
element,
|
||||
properties: {},
|
||||
});
|
||||
};
|
||||
|
||||
return { items, add };
|
||||
}
|
||||
}
|
||||
|
||||
function getItemEditor(props) {
|
||||
const { itemId, element, item, commandStack, translate } = props;
|
||||
return [
|
||||
{
|
||||
id: `${itemId}-name`,
|
||||
component: ItemTextField,
|
||||
item,
|
||||
commandStack,
|
||||
translate,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function ItemTextField(props) {
|
||||
const { itemId, element, item, commandStack, translate } = props;
|
||||
|
||||
const debounce = useService('debounceInput');
|
||||
|
||||
const setValue = (value) => {
|
||||
commandStack.execute('element.updateModdleProperties', {
|
||||
element,
|
||||
moddleElement: item,
|
||||
properties: {
|
||||
id: value,
|
||||
name: value,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const getValue = () => { return item.id; }
|
||||
|
||||
return TextFieldEntry({
|
||||
element,
|
||||
id: `${itemId}-id-textField`,
|
||||
label: translate('ID'),
|
||||
getValue,
|
||||
setValue,
|
||||
debounce,
|
||||
});
|
||||
}
|
||||
|
||||
export { getArrayForType, getListGroupForType };
|
251
bpmn-js-spiffworkflow/app/spiffworkflow/eventSelect.js
Normal file
251
bpmn-js-spiffworkflow/app/spiffworkflow/eventSelect.js
Normal file
@ -0,0 +1,251 @@
|
||||
import { is, isAny } from 'bpmn-js/lib/util/ModelUtil';
|
||||
import { useService } from 'bpmn-js-properties-panel';
|
||||
import {
|
||||
ListGroup,
|
||||
TextFieldEntry,
|
||||
TextAreaEntry,
|
||||
SelectEntry,
|
||||
isTextFieldEntryEdited
|
||||
} from '@bpmn-io/properties-panel';
|
||||
import { getRoot } from './helpers';
|
||||
|
||||
function hasEventType(element, eventType) {
|
||||
const events = element.businessObject.eventDefinitions;
|
||||
return events && events.filter(item => is(item, eventType)).length > 0;
|
||||
}
|
||||
|
||||
function replaceGroup(groupId, groups, group) {
|
||||
const idx = groups.map(g => g.id).indexOf(groupId);
|
||||
if (idx > -1)
|
||||
groups.splice(idx, 1, group);
|
||||
else
|
||||
groups.push(group);
|
||||
group.shouldOpen = true;
|
||||
}
|
||||
|
||||
function isCatchingEvent(element) {
|
||||
return isAny(element, ['bpmn:StartEvent', 'bpmn:IntermediateCatchEvent', 'bpmn:BoundaryEvent']);
|
||||
}
|
||||
|
||||
function isThrowingEvent(element) {
|
||||
return isAny(element, ['bpmn:EndEvent', 'bpmn:IntermediateThrowEvent']);
|
||||
}
|
||||
|
||||
function getConfigureGroupForType(eventDetails, label, includeCode, getSelect) {
|
||||
|
||||
const { eventType, eventDefType, referenceType, idPrefix } = eventDetails;
|
||||
|
||||
return function (props) {
|
||||
const { element, translate, moddle, commandStack } = props;
|
||||
|
||||
const variableName = getTextFieldForExtension(eventDetails, 'Variable Name', 'The name of the variable to store the payload in', true);
|
||||
const payloadDefinition = getTextFieldForExtension(eventDetails, 'Payload', 'The expression to create the payload with', false);
|
||||
|
||||
const entries = [
|
||||
{
|
||||
id: `${idPrefix}-select`,
|
||||
element,
|
||||
component: getSelect,
|
||||
isEdited: isTextFieldEntryEdited,
|
||||
moddle,
|
||||
commandStack,
|
||||
},
|
||||
];
|
||||
|
||||
if (includeCode) {
|
||||
const codeField = getCodeTextField(eventDetails, `${label} Code`);
|
||||
entries.push({
|
||||
id: `${idPrefix}-code`,
|
||||
element,
|
||||
component: codeField,
|
||||
isEdited: isTextFieldEntryEdited,
|
||||
moddle,
|
||||
commandStack,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (isCatchingEvent(element)) {
|
||||
entries.push({
|
||||
id: `${idPrefix}-variable`,
|
||||
element,
|
||||
component: variableName,
|
||||
isEdited: isTextFieldEntryEdited,
|
||||
moddle,
|
||||
commandStack,
|
||||
});
|
||||
} else if (isThrowingEvent(element)) {
|
||||
entries.push({
|
||||
id: `${idPrefix}-payload`,
|
||||
element,
|
||||
component: payloadDefinition,
|
||||
isEdited: isTextFieldEntryEdited,
|
||||
moddle,
|
||||
commandStack,
|
||||
});
|
||||
};
|
||||
return {
|
||||
id: `${idPrefix}-group`,
|
||||
label: label,
|
||||
entries,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getSelectorForType(eventDetails) {
|
||||
|
||||
const { eventType, eventDefType, referenceType, idPrefix } = eventDetails;
|
||||
|
||||
return function (props) {
|
||||
const { element, translate, moddle, commandStack } = props;
|
||||
const debounce = useService('debounceInput');
|
||||
const root = getRoot(element.businessObject);
|
||||
|
||||
const getValue = () => {
|
||||
const eventDef = element.businessObject.eventDefinitions.find(v => v.$type == eventDefType);
|
||||
return (eventDef && eventDef.get(referenceType)) ? eventDef.get(referenceType).id : '';
|
||||
};
|
||||
|
||||
const setValue = (value) => {
|
||||
const bpmnEvent = root.rootElements.find(e => e.id == value);
|
||||
// not sure how to handle multiple event definitions
|
||||
const eventDef = element.businessObject.eventDefinitions.find(v => v.$type == eventDefType);
|
||||
// really not sure what to do here if one of these can't be found either
|
||||
if (bpmnEvent && eventDef)
|
||||
eventDef.set(referenceType, bpmnEvent);
|
||||
commandStack.execute('element.updateProperties', {
|
||||
element,
|
||||
moddleElement: element.businessObject,
|
||||
properties: {},
|
||||
});
|
||||
};
|
||||
|
||||
const getOptions = (val) => {
|
||||
const matching = root.rootElements ? root.rootElements.filter(elem => elem.$type === eventType) : [];
|
||||
const options = [];
|
||||
matching.map(option => options.push({label: option.name, value: option.id}));
|
||||
return options;
|
||||
}
|
||||
|
||||
return SelectEntry({
|
||||
id: `${idPrefix}-select`,
|
||||
element,
|
||||
description: 'Select item',
|
||||
getValue,
|
||||
setValue,
|
||||
getOptions,
|
||||
debounce,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getTextFieldForExtension(eventDetails, label, description, catching) {
|
||||
|
||||
const { eventType, eventDefType, referenceType, idPrefix } = eventDetails;
|
||||
|
||||
return function (props) {
|
||||
const { element, moddle, commandStack } = props;
|
||||
const debounce = useService('debounceInput');
|
||||
const translate = useService('translate');
|
||||
const root = getRoot(element.businessObject);
|
||||
const extensionName = (catching) ? 'spiffworkflow:variableName' : 'spiffworkflow:payloadExpression';
|
||||
|
||||
const getEvent = () => {
|
||||
const eventDef = element.businessObject.eventDefinitions.find(v => v.$type == eventDefType);
|
||||
const bpmnEvent = eventDef.get(referenceType);
|
||||
return bpmnEvent;
|
||||
};
|
||||
|
||||
const getValue = () => {
|
||||
// I've put the variable name (and payload) on the event for consistency with messages.
|
||||
// However, when I think about this, I wonder if it shouldn't be on the event definition.
|
||||
// I think that's something we should address in the future.
|
||||
// Creating a payload and defining access to it are both process-specific, and that's an argument for leaving
|
||||
// it in the event definition
|
||||
const bpmnEvent = getEvent();
|
||||
if (bpmnEvent && bpmnEvent.extensionElements) {
|
||||
const extension = bpmnEvent.extensionElements.get('values').find(ext => ext.$instanceOf(extensionName));
|
||||
return (extension) ? extension.value : null;
|
||||
}
|
||||
}
|
||||
|
||||
const setValue = (value) => {
|
||||
const bpmnEvent = getEvent();
|
||||
if (bpmnEvent) {
|
||||
if (!bpmnEvent.extensionElements)
|
||||
bpmnEvent.extensionElements = moddle.create('bpmn:ExtensionElements');
|
||||
const extensions = bpmnEvent.extensionElements.get('values');
|
||||
const extension = extensions.find(ext => ext.$instanceOf(extensionName));
|
||||
if (!extension) {
|
||||
const newExt = moddle.create(extensionName);
|
||||
newExt.value = value;
|
||||
extensions.push(newExt);
|
||||
} else
|
||||
extension.value = value;
|
||||
} // not sure what to do if the event hasn't been set
|
||||
};
|
||||
|
||||
if (catching) {
|
||||
return TextFieldEntry({
|
||||
element,
|
||||
id: `${idPrefix}-variable-name`,
|
||||
description: description,
|
||||
label: translate(label),
|
||||
getValue,
|
||||
setValue,
|
||||
debounce,
|
||||
});
|
||||
} else {
|
||||
return TextAreaEntry({
|
||||
element,
|
||||
id: `${idPrefix}-payload-expression`,
|
||||
description: description,
|
||||
label: translate(label),
|
||||
getValue,
|
||||
setValue,
|
||||
debounce,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCodeTextField(eventDetails, label) {
|
||||
|
||||
const { eventType, eventDefType, referenceType, idPrefix } = eventDetails;
|
||||
|
||||
return function (props) {
|
||||
|
||||
const { element, moddle, commandStack } = props;
|
||||
const translate = useService('translate');
|
||||
const debounce = useService('debounceInput');
|
||||
const attrName = `${idPrefix}Code`;
|
||||
|
||||
const getEvent = () => {
|
||||
const eventDef = element.businessObject.eventDefinitions.find(v => v.$type == eventDefType);
|
||||
const bpmnEvent = eventDef.get(referenceType);
|
||||
return bpmnEvent;
|
||||
};
|
||||
|
||||
const getValue = () => {
|
||||
const bpmnEvent = getEvent();
|
||||
return (bpmnEvent) ? bpmnEvent.get(attrName) : null;
|
||||
};
|
||||
|
||||
const setValue = (value) => {
|
||||
const bpmnEvent = getEvent();
|
||||
if (bpmnEvent)
|
||||
bpmnEvent.set(attrName, value);
|
||||
};
|
||||
|
||||
return TextFieldEntry({
|
||||
element,
|
||||
id: `${idPrefix}-code-value`,
|
||||
label: translate(label),
|
||||
getValue,
|
||||
setValue,
|
||||
debounce,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { hasEventType, getSelectorForType, getConfigureGroupForType, replaceGroup };
|
@ -28,7 +28,6 @@ export function SpiffExtensionLaunchButton(props) {
|
||||
const { commandStack, moddle } = props;
|
||||
// Listen for a response, to update the script.
|
||||
eventBus.once(listenEvent, (response) => {
|
||||
console.log("Calling Update!")
|
||||
setExtensionValue(element, name, response.value, moddle, commandStack);
|
||||
});
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ export function SpiffExtensionSelect(props) {
|
||||
};
|
||||
|
||||
const setValue = (value) => {
|
||||
console.log(`Set Value called with ${ value}`);
|
||||
setExtensionValue(element, name, value, moddle, commandStack);
|
||||
};
|
||||
|
||||
|
@ -12,3 +12,27 @@ export function removeExtensionElementsIfEmpty(moddleElement) {
|
||||
moddleElement.extensionElements = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* loops up until it can find the root.
|
||||
* @param element
|
||||
*/
|
||||
export function getRoot(businessObject, moddle) {
|
||||
// HACK: get the root element. need a more formal way to do this
|
||||
if (moddle) {
|
||||
for (const elementId in moddle.ids._seed.hats) {
|
||||
if (elementId.startsWith('Definitions_')) {
|
||||
return moddle.ids._seed.hats[elementId];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// todo: Do we want businessObject to be a shape or moddle object?
|
||||
if (businessObject.$type === 'bpmn:Definitions') {
|
||||
return businessObject;
|
||||
}
|
||||
if (typeof businessObject.$parent !== 'undefined') {
|
||||
return getRoot(businessObject.$parent);
|
||||
}
|
||||
}
|
||||
return businessObject;
|
||||
}
|
||||
|
@ -9,7 +9,12 @@ import DataObjectPropertiesProvider from './DataObject/propertiesPanel/DataObjec
|
||||
import ConditionsPropertiesProvider from './conditions/propertiesPanel/ConditionsPropertiesProvider';
|
||||
import ExtensionsPropertiesProvider from './extensions/propertiesPanel/ExtensionsPropertiesProvider';
|
||||
import MessagesPropertiesProvider from './messages/propertiesPanel/MessagesPropertiesProvider';
|
||||
import SignalPropertiesProvider from './signals/propertiesPanel/SignalPropertiesProvider';
|
||||
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';
|
||||
|
||||
export default {
|
||||
__depends__: [RulesModule],
|
||||
@ -20,11 +25,16 @@ export default {
|
||||
'conditionsPropertiesProvider',
|
||||
'extensionsPropertiesProvider',
|
||||
'messagesPropertiesProvider',
|
||||
'signalPropertiesProvider',
|
||||
'errorPropertiesProvider',
|
||||
'escalationPropertiesProvider',
|
||||
'callActivityPropertiesProvider',
|
||||
'ioPalette',
|
||||
'ioRules',
|
||||
'ioInterceptor',
|
||||
'dataObjectRenderer',
|
||||
'multiInstancePropertiesProvider',
|
||||
'standardLoopPropertiesProvider',
|
||||
],
|
||||
dataObjectInterceptor: ['type', DataObjectInterceptor],
|
||||
dataObjectRules: ['type', DataObjectRules],
|
||||
@ -32,9 +42,14 @@ export default {
|
||||
dataObjectPropertiesProvider: ['type', DataObjectPropertiesProvider],
|
||||
conditionsPropertiesProvider: ['type', ConditionsPropertiesProvider],
|
||||
extensionsPropertiesProvider: ['type', ExtensionsPropertiesProvider],
|
||||
signalPropertiesProvider: ['type', SignalPropertiesProvider],
|
||||
errorPropertiesProvider: ['type', ErrorPropertiesProvider],
|
||||
escalationPropertiesProvider: ['type', EscalationPropertiesProvider],
|
||||
messagesPropertiesProvider: ['type', MessagesPropertiesProvider],
|
||||
callActivityPropertiesProvider: ['type', CallActivityPropertiesProvider],
|
||||
ioPalette: ['type', IoPalette],
|
||||
ioRules: ['type', IoRules],
|
||||
ioInterceptor: ['type', IoInterceptor],
|
||||
multiInstancePropertiesProvider: ['type', MultiInstancePropertiesProvider],
|
||||
standardLoopPropertiesProvider: ['type', StandardLoopPropertiesProvider],
|
||||
};
|
||||
|
@ -0,0 +1,30 @@
|
||||
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,
|
||||
});
|
||||
}
|
@ -0,0 +1,221 @@
|
||||
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'
|
||||
});
|
||||
}
|
||||
|
@ -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') || 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
|
||||
});
|
||||
}
|
@ -148,14 +148,24 @@ function getRetrievalExpressionFromCorrelationProperty(
|
||||
export function findCorrelationProperties(businessObject, moddle) {
|
||||
const root = getRoot(businessObject, moddle);
|
||||
const correlationProperties = [];
|
||||
for (const rootElement of root.rootElements) {
|
||||
if (rootElement.$type === 'bpmn:CorrelationProperty') {
|
||||
correlationProperties.push(rootElement);
|
||||
if (isIterable(root.rootElements)) {
|
||||
for (const rootElement of root.rootElements) {
|
||||
if (rootElement.$type === 'bpmn:CorrelationProperty') {
|
||||
correlationProperties.push(rootElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
return correlationProperties;
|
||||
}
|
||||
|
||||
function isIterable(obj) {
|
||||
// checks for null and undefined
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
return typeof obj[Symbol.iterator] === 'function';
|
||||
}
|
||||
|
||||
export function findCorrelationKeys(businessObject, moddle) {
|
||||
const root = getRoot(businessObject, moddle);
|
||||
const correlationKeys = [];
|
||||
|
@ -35,6 +35,9 @@ export function MessageSelect(props) {
|
||||
commandStack.execute('element.updateModdleProperties', {
|
||||
element: shapeElement,
|
||||
moddleElement: businessObject,
|
||||
properties: {
|
||||
messageRef: message,
|
||||
},
|
||||
});
|
||||
} else if (
|
||||
businessObject.$type === 'bpmn:ReceiveTask' ||
|
||||
|
@ -219,6 +219,28 @@
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "payloadExpression",
|
||||
"superClass": [ "Element" ],
|
||||
"properties": [
|
||||
{
|
||||
"name": "value",
|
||||
"isBody": true,
|
||||
"type": "String"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "variableName",
|
||||
"superClass": [ "Element" ],
|
||||
"properties": [
|
||||
{
|
||||
"name": "value",
|
||||
"isBody": true,
|
||||
"type": "String"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
6
bpmn-js-spiffworkflow/app/spiffworkflow/signals/index.js
Normal file
6
bpmn-js-spiffworkflow/app/spiffworkflow/signals/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
import SignalPropertiesProvider from './propertiesPanel/SignalPropertiesProvider';
|
||||
|
||||
export default {
|
||||
__init__: ['signalPropertiesProvider'],
|
||||
signalPropertiesProvider: ['type', SignalPropertiesProvider],
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
import { is } from 'bpmn-js/lib/util/ModelUtil';
|
||||
import { getRoot } from '../../helpers';
|
||||
import { getArrayForType, getListGroupForType } from '../../eventList.js';
|
||||
import { hasEventType,
|
||||
replaceGroup,
|
||||
getSelectorForType,
|
||||
getConfigureGroupForType
|
||||
} from '../../eventSelect.js';
|
||||
|
||||
const LOW_PRIORITY = 500;
|
||||
|
||||
const eventDetails = {
|
||||
'eventType': 'bpmn:Signal',
|
||||
'eventDefType': 'bpmn:SignalEventDefinition',
|
||||
'referenceType': 'signalRef',
|
||||
'idPrefix': 'signal',
|
||||
};
|
||||
|
||||
export default function SignalPropertiesProvider(
|
||||
propertiesPanel,
|
||||
translate,
|
||||
moddle,
|
||||
commandStack,
|
||||
) {
|
||||
|
||||
this.getGroups = function (element) {
|
||||
return function (groups) {
|
||||
if (is(element, 'bpmn:Process') || is(element, 'bpmn:Collaboration')) {
|
||||
const getSignalArray = getArrayForType('bpmn:Signal', 'signalRef', 'Signal');
|
||||
const signalGroup = getListGroupForType('signals', 'Signals', getSignalArray);
|
||||
groups.push(signalGroup({ element, translate, moddle, commandStack }));
|
||||
} else if (hasEventType(element, 'bpmn:SignalEventDefinition')) {
|
||||
const getSignalSelector = getSelectorForType(eventDetails);
|
||||
const signalGroup = getConfigureGroupForType(eventDetails, 'Signal', false, getSignalSelector);
|
||||
const group = signalGroup({ element, translate, moddle, commandStack });
|
||||
replaceGroup('signal', groups, group);
|
||||
}
|
||||
return groups;
|
||||
};
|
||||
};
|
||||
propertiesPanel.registerProvider(LOW_PRIORITY, this);
|
||||
}
|
||||
|
||||
SignalPropertiesProvider.$inject = [
|
||||
'propertiesPanel',
|
||||
'translate',
|
||||
'moddle',
|
||||
'commandStack',
|
||||
];
|
66
bpmn-js-spiffworkflow/test/spec/DataObjectInPoolsSpec.js
Normal file
66
bpmn-js-spiffworkflow/test/spec/DataObjectInPoolsSpec.js
Normal file
@ -0,0 +1,66 @@
|
||||
import {
|
||||
BpmnPropertiesPanelModule,
|
||||
BpmnPropertiesProviderModule,
|
||||
} from 'bpmn-js-properties-panel';
|
||||
import TestContainer from 'mocha-test-container-support';
|
||||
import {
|
||||
bootstrapPropertiesPanel,
|
||||
changeInput,
|
||||
expectSelected,
|
||||
findEntry,
|
||||
findSelect,
|
||||
} from './helpers';
|
||||
import spiffModdleExtension from '../../app/spiffworkflow/moddle/spiffworkflow.json';
|
||||
import DataObject from '../../app/spiffworkflow/DataObject';
|
||||
|
||||
describe('Properties Panel for Data Objects', function () {
|
||||
const xml = require('./bpmn/data_objects_in_pools.bpmn').default;
|
||||
let container;
|
||||
|
||||
beforeEach(function () {
|
||||
container = TestContainer.get(this);
|
||||
});
|
||||
|
||||
beforeEach(
|
||||
bootstrapPropertiesPanel(xml, {
|
||||
container,
|
||||
debounceInput: false,
|
||||
additionalModules: [
|
||||
DataObject,
|
||||
BpmnPropertiesPanelModule,
|
||||
BpmnPropertiesProviderModule,
|
||||
],
|
||||
moddleExtensions: {
|
||||
spiffworkflow: spiffModdleExtension,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
it('should allow you to select other data objects within the same participant', async function () {
|
||||
// IF - a data object reference is selected
|
||||
const doREF = await expectSelected('pool1Do1_REF');
|
||||
expect(doREF).to.exist;
|
||||
|
||||
// THEN - a select Data Object section should appear in the properties panel
|
||||
const entry = findEntry('selectDataObject', container);
|
||||
const selector = findSelect(entry);
|
||||
changeInput(selector, 'pool1Do2');
|
||||
// then this data reference object now references that data object.
|
||||
const { businessObject } = doREF;
|
||||
expect(businessObject.get('dataObjectRef').id).to.equal('pool1Do2');
|
||||
});
|
||||
|
||||
it('should NOT allow you to select data objects within other participants', async function () {
|
||||
// IF - a data object reference is selected
|
||||
const doREF = await expectSelected('pool1Do1_REF');
|
||||
expect(doREF).to.exist;
|
||||
|
||||
// THEN - a select Data Object section should appear in the properties panel but pool2Do1 should not be an option
|
||||
const entry = findEntry('selectDataObject', container);
|
||||
const selector = findSelect(entry);
|
||||
expect(selector.length).to.equal(2);
|
||||
expect(selector[0].value === 'pool1Do2');
|
||||
expect(selector[1].value === 'pool1Do1');
|
||||
});
|
||||
|
||||
});
|
@ -6,9 +6,6 @@ import {
|
||||
import { BpmnPropertiesPanelModule, BpmnPropertiesProviderModule } from 'bpmn-js-properties-panel';
|
||||
import spiffModdleExtension from '../../app/spiffworkflow/moddle/spiffworkflow.json';
|
||||
import TestContainer from 'mocha-test-container-support';
|
||||
import DataObjectPropertiesProvider
|
||||
from '../../app/spiffworkflow/DataObject/propertiesPanel/DataObjectPropertiesProvider';
|
||||
import spiffworkflow from '../../app/spiffworkflow';
|
||||
import DataObject from '../../app/spiffworkflow/DataObject';
|
||||
|
||||
describe('Properties Panel for Data Objects', function() {
|
||||
@ -78,4 +75,17 @@ describe('Properties Panel for Data Objects', function() {
|
||||
expect(my_data_ref_1.businessObject.name).to.equal('My Nifty New Name');
|
||||
});
|
||||
|
||||
it('renaming a data object creates a lable without losing the numbers', async function() {
|
||||
|
||||
// IF - a process is selected, and the name of a data object is changed.
|
||||
let entry = findEntry('ProcessTest-dataObj-2-id', container);
|
||||
let textInput = findInput('text', entry);
|
||||
changeInput(textInput, 'MyObject1');
|
||||
let my_data_ref_1 = await expectSelected('my_data_ref_1');
|
||||
|
||||
// THEN - both the data object itself, and the label of any references are updated.
|
||||
expect(my_data_ref_1.businessObject.dataObjectRef.id).to.equal('MyObject1');
|
||||
expect(my_data_ref_1.businessObject.name).to.equal('My Object 1');
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -0,0 +1,44 @@
|
||||
<?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:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_19o7vxg" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.0.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.17.0">
|
||||
<bpmn:collaboration id="Collaboration_0jmlu5k">
|
||||
<bpmn:participant id="Participant_11j98s8" processRef="ProcessTest" />
|
||||
<bpmn:participant id="Participant_1d4d2vr" processRef="Process_1y9rx5q" />
|
||||
</bpmn:collaboration>
|
||||
<bpmn:process id="ProcessTest" name="Process Test" isExecutable="true">
|
||||
<bpmn:dataObjectReference id="pool1Do2_REF" name="Pool 1 Do 2" dataObjectRef="pool1Do2" />
|
||||
<bpmn:dataObject id="pool1Do2" />
|
||||
<bpmn:dataObject id="pool1Do1" />
|
||||
<bpmn:dataObjectReference id="pool1Do2_REF" name="Pool 1 Do 2" dataObjectRef="pool1Do2" />
|
||||
<bpmn:dataObjectReference id="pool1Do1_REF" name="Pool 1 Do 1" dataObjectRef="pool1Do1" />
|
||||
</bpmn:process>
|
||||
<bpmn:process id="Process_1y9rx5q">
|
||||
<bpmn:dataObject id="Pool2do" />
|
||||
<bpmn:dataObjectReference id="pool2Do2" name="Pool 2 Do" dataObjectRef="Pool2do" />
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_0jmlu5k">
|
||||
<bpmndi:BPMNShape id="Participant_11j98s8_di" bpmnElement="Participant_11j98s8" isHorizontal="true">
|
||||
<dc:Bounds x="290" y="270" width="300" height="140" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="pool1Do2_REF_di" bpmnElement="pool1Do2_REF">
|
||||
<dc:Bounds x="462" y="295" width="36" height="50" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="453" y="352" width="58" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="pool1Do1_REF_di" bpmnElement="pool1Do1_REF">
|
||||
<dc:Bounds x="372" y="295" width="36" height="50" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="365" y="352" width="58" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Participant_1d4d2vr_di" bpmnElement="Participant_1d4d2vr" isHorizontal="true">
|
||||
<dc:Bounds x="290" y="430" width="390" height="130" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="DataObjectReference_18xfjvh_di" bpmnElement="DataObjectReference_18xfjvh">
|
||||
<dc:Bounds x="372" y="465" width="36" height="50" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
2984
bpmn-js-spiffworkflow/test/spec/bpmn/request_new_role.bpmn
Normal file
2984
bpmn-js-spiffworkflow/test/spec/bpmn/request_new_role.bpmn
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user