Copy and rename files
This commit is contained in:
parent
04186b9032
commit
72dc832478
|
@ -0,0 +1,70 @@
|
||||||
|
/**
|
||||||
|
* Returns the moddelElement if it is a process, otherwise, returns the
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function findDataObjects(parent, dataObjects) {
|
||||||
|
if (typeof(dataObjects) === 'undefined')
|
||||||
|
dataObjects = [];
|
||||||
|
let process;
|
||||||
|
if (!parent) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (parent.processRef) {
|
||||||
|
process = parent.processRef;
|
||||||
|
} else {
|
||||||
|
process = parent;
|
||||||
|
if (process.$type === 'bpmn:SubProcess')
|
||||||
|
findDataObjects(process.$parent, dataObjects);
|
||||||
|
}
|
||||||
|
if (typeof(process.flowElements) !== 'undefined') {
|
||||||
|
for (const element of process.flowElements) {
|
||||||
|
if (element.$type === 'bpmn:DataObject')
|
||||||
|
dataObjects.push(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dataObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findDataObject(process, id) {
|
||||||
|
for (const dataObj of findDataObjects(process)) {
|
||||||
|
if (dataObj.id === id) {
|
||||||
|
return dataObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findDataObjectReferences(children, dataObjectId) {
|
||||||
|
if (children == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return children.flatMap((child) => {
|
||||||
|
if (child.$type == 'bpmn:DataObjectReference' && child.dataObjectRef.id == dataObjectId)
|
||||||
|
return [child];
|
||||||
|
else if (child.$type == 'bpmn:SubProcess')
|
||||||
|
return findDataObjectReferences(child.get('flowElements'), dataObjectId);
|
||||||
|
else
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findDataObjectReferenceShapes(children, dataObjectId) {
|
||||||
|
return children.flatMap((child) => {
|
||||||
|
if (child.type == 'bpmn:DataObjectReference' && child.businessObject.dataObjectRef.id == dataObjectId)
|
||||||
|
return [child];
|
||||||
|
else if (child.type == 'bpmn:SubProcess')
|
||||||
|
return findDataObjectReferenceShapes(child.children, dataObjectId);
|
||||||
|
else
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function idToHumanReadableName(id) {
|
||||||
|
const words = id.match(/[A-Za-z][a-z]*|[0-9]+/g) || [id];
|
||||||
|
return words.map(capitalize).join(' ');
|
||||||
|
|
||||||
|
function capitalize(word) {
|
||||||
|
return word.charAt(0).toUpperCase() + word.substring(1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
|
||||||
|
import { getDi, is } from 'bpmn-js/lib/util/ModelUtil';
|
||||||
|
import { remove as collectionRemove } from 'diagram-js/lib/util/Collections';
|
||||||
|
import {
|
||||||
|
findDataObjects,
|
||||||
|
findDataObjectReferences,
|
||||||
|
idToHumanReadableName,
|
||||||
|
} from './DataObjectHelpers';
|
||||||
|
|
||||||
|
const HIGH_PRIORITY = 1500;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This Command Interceptor functions like the BpmnUpdator in BPMN.js - It hooks into events
|
||||||
|
* from Diagram.js and updates the underlying BPMN model accordingly.
|
||||||
|
*
|
||||||
|
* This handles some special cases we want to handle for DataObjects and DataObjectReferences,
|
||||||
|
* for instance:
|
||||||
|
* 1) Use existing data objects if possible when creating a new reference (don't create new objects each time)
|
||||||
|
* 2) Don't automatically delete a data object when you delete the reference - unless all references are removed.
|
||||||
|
* 3) Update the name of the DataObjectReference to match the id of the DataObject.
|
||||||
|
* 4) Don't allow someone to move a DataObjectReference from one process to another process.
|
||||||
|
*/
|
||||||
|
export default class DataObjectInterceptor extends CommandInterceptor {
|
||||||
|
|
||||||
|
constructor(eventBus, bpmnFactory, commandStack, bpmnUpdater) {
|
||||||
|
super(eventBus);
|
||||||
|
|
||||||
|
/* The default behavior is to move the data object into whatever object the reference is being created in.
|
||||||
|
* If a data object already has a parent, don't change it.
|
||||||
|
*/
|
||||||
|
bpmnUpdater.updateSemanticParent = (businessObject, parentBusinessObject) => {
|
||||||
|
// Special case for participant - which is a valid place to drop a data object, but it needs to be added
|
||||||
|
// to the particpant's Process (which isn't directly accessible in BPMN.io
|
||||||
|
let realParent = parentBusinessObject;
|
||||||
|
if (is(realParent, 'bpmn:Participant')) {
|
||||||
|
realParent = realParent.processRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is(businessObject, 'bpmn:DataObjectReference')) {
|
||||||
|
// For data object references, always update the flowElements when a parent is provided
|
||||||
|
// The parent could be null if it's being deleted, and I could probably handle that here instead of
|
||||||
|
// when the shape is deleted, but not interested in refactoring at the moment.
|
||||||
|
if (realParent != null) {
|
||||||
|
const flowElements = realParent.get('flowElements');
|
||||||
|
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.
|
||||||
|
if (typeof (businessObject.$parent) === 'undefined') {
|
||||||
|
const flowElements = realParent.get('flowElements');
|
||||||
|
flowElements.push(businessObject);
|
||||||
|
businessObject.$parent = realParent;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bpmnUpdater.__proto__.updateSemanticParent.call(bpmnUpdater, businessObject, parentBusinessObject);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For DataObjectReferences only ...
|
||||||
|
* Prevent this from calling the CreateDataObjectBehavior in BPMN-js, as it will
|
||||||
|
* attempt to crete a dataObject immediately. We can't create the dataObject until
|
||||||
|
* we know where it is placed - as we want to reuse data objects of the parent when
|
||||||
|
* possible */
|
||||||
|
this.preExecute(['shape.create'], HIGH_PRIORITY, function (event) {
|
||||||
|
const { context } = event;
|
||||||
|
const { shape } = context;
|
||||||
|
if (is(shape, 'bpmn:DataObjectReference') && shape.type !== 'label') {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't just create a new data object, use the first existing one if it already exists
|
||||||
|
*/
|
||||||
|
this.executed(['shape.create'], HIGH_PRIORITY, function (event) {
|
||||||
|
const { context } = event;
|
||||||
|
const { shape } = context;
|
||||||
|
if (is(shape, 'bpmn:DataObjectReference') && shape.type !== 'label') {
|
||||||
|
const process = shape.parent.businessObject;
|
||||||
|
const existingDataObjects = findDataObjects(process);
|
||||||
|
let dataObject;
|
||||||
|
if (existingDataObjects.length > 0) {
|
||||||
|
dataObject = existingDataObjects[0];
|
||||||
|
} else {
|
||||||
|
dataObject = bpmnFactory.create('bpmn:DataObject');
|
||||||
|
}
|
||||||
|
// set the reference to the DataObject
|
||||||
|
shape.businessObject.dataObjectRef = dataObject;
|
||||||
|
shape.businessObject.$parent = process;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In order for the label to display correctly, we need to update it in POST step.
|
||||||
|
*/
|
||||||
|
this.postExecuted(['shape.create'], HIGH_PRIORITY, function (event) {
|
||||||
|
const { context } = event;
|
||||||
|
const { shape } = context;
|
||||||
|
// set the reference to the DataObject
|
||||||
|
// Update the name of the reference to match the data object's id.
|
||||||
|
if (is(shape, 'bpmn:DataObjectReference') && shape.type !== 'label') {
|
||||||
|
commandStack.execute('element.updateProperties', {
|
||||||
|
element: shape,
|
||||||
|
moddleElement: shape.businessObject,
|
||||||
|
properties: {
|
||||||
|
name: idToHumanReadableName(shape.businessObject.dataObjectRef.id),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't remove the associated DataObject, unless all references to that data object
|
||||||
|
* Difficult to do given placement of this logic in the BPMN Updater, so we have
|
||||||
|
* to manually handle the removal.
|
||||||
|
*/
|
||||||
|
this.executed(['shape.delete'], HIGH_PRIORITY, function (event) {
|
||||||
|
const { context } = event;
|
||||||
|
const { shape } = context;
|
||||||
|
if (is(shape, 'bpmn:DataObjectReference') && shape.type !== 'label') {
|
||||||
|
const dataObject = shape.businessObject.dataObjectRef;
|
||||||
|
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);
|
||||||
|
const references = findDataObjectReferences(flowElements, dataObject.id);
|
||||||
|
if (references.length === 0) {
|
||||||
|
const dataFlowElements = dataObject.$parent.get('flowElements');
|
||||||
|
collectionRemove(dataFlowElements, dataObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataObjectInterceptor.$inject = ['eventBus', 'bpmnFactory', 'commandStack', 'bpmnUpdater'];
|
|
@ -0,0 +1,44 @@
|
||||||
|
import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer';
|
||||||
|
|
||||||
|
import {
|
||||||
|
attr as svgAttr
|
||||||
|
} from 'tiny-svg';
|
||||||
|
|
||||||
|
import { getBusinessObject, is } from 'bpmn-js/lib/util/ModelUtil';
|
||||||
|
import { isAny } from 'bpmn-js/lib/features/modeling/util/ModelingUtil';
|
||||||
|
import { findDataObject } from './DataObjectHelpers';
|
||||||
|
|
||||||
|
const HIGH_PRIORITY = 1500;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Work in progress -- render data object references in red if they are
|
||||||
|
* not valid.
|
||||||
|
*/
|
||||||
|
export default class DataObjectRenderer extends BaseRenderer {
|
||||||
|
constructor(eventBus, bpmnRenderer) {
|
||||||
|
super(eventBus, HIGH_PRIORITY);
|
||||||
|
this.bpmnRenderer = bpmnRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
canRender(element) {
|
||||||
|
return isAny(element, [ 'bpmn:DataObjectReference' ]) && !element.labelTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawShape(parentNode, element) {
|
||||||
|
const shape = this.bpmnRenderer.drawShape(parentNode, element);
|
||||||
|
if (is(element, 'bpmn:DataObjectReference')) {
|
||||||
|
let businessObject = getBusinessObject(element);
|
||||||
|
let dataObject = businessObject.dataObjectRef;
|
||||||
|
if (dataObject && dataObject.id) {
|
||||||
|
let parentObject = businessObject.$parent;
|
||||||
|
dataObject = findDataObject(parentObject, dataObject.id);
|
||||||
|
}
|
||||||
|
if (!dataObject) {
|
||||||
|
svgAttr(shape, 'stroke', 'red');
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataObjectRenderer.$inject = [ 'eventBus', 'bpmnRenderer' ];
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* Custom Rules for the DataObject - Rules allow you to prevent an
|
||||||
|
* action from happening in the diagram, such as dropping an element
|
||||||
|
* where it doesn't belong.
|
||||||
|
*
|
||||||
|
* Here we don't allow people to move a data object Reference
|
||||||
|
* from one parent to another, as we can't move the data objects
|
||||||
|
* from one parent to another.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import RuleProvider from 'diagram-js/lib/features/rules/RuleProvider';
|
||||||
|
import inherits from 'inherits-browser';
|
||||||
|
import { is } from 'bpmn-js/lib/util/ModelUtil';
|
||||||
|
|
||||||
|
export default function DataObjectRules(eventBus) {
|
||||||
|
RuleProvider.call(this, eventBus);
|
||||||
|
}
|
||||||
|
inherits(DataObjectRules, RuleProvider);
|
||||||
|
const HIGH_PRIORITY = 1500;
|
||||||
|
|
||||||
|
DataObjectRules.prototype.init = function() {
|
||||||
|
this.addRule('elements.move', HIGH_PRIORITY,function(context) {
|
||||||
|
let elements = context.shapes;
|
||||||
|
let target = context.target;
|
||||||
|
return canDrop(elements, target);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function canDrop(elements, target) {
|
||||||
|
for (let element of elements) {
|
||||||
|
if (is(element, 'bpmn:DataObjectReference') && element.parent && target) {
|
||||||
|
return target === element.parent;
|
||||||
|
}
|
||||||
|
// Intentionally returning null here to allow other rules to fire.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataObjectRules.prototype.canDrop = canDrop;
|
||||||
|
DataObjectRules.$inject = [ 'eventBus' ];
|
|
@ -0,0 +1,20 @@
|
||||||
|
import DataObjectInterceptor from './DataObjectInterceptor';
|
||||||
|
import DataObjectRules from './DataObjectRules';
|
||||||
|
import RulesModule from 'diagram-js/lib/features/rules';
|
||||||
|
import DataObjectRenderer from './DataObjectRenderer';
|
||||||
|
import DataObjectPropertiesProvider from './propertiesPanel/DataObjectPropertiesProvider';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
__depends__: [
|
||||||
|
RulesModule
|
||||||
|
],
|
||||||
|
__init__: [ 'dataInterceptor', 'dataObjectRules', 'dataObjectRenderer', 'dataObjectPropertiesProvider' ],
|
||||||
|
dataInterceptor: [ 'type', DataObjectInterceptor ],
|
||||||
|
dataObjectRules: [ 'type', DataObjectRules ],
|
||||||
|
dataObjectRenderer: [ 'type', DataObjectRenderer ],
|
||||||
|
dataObjectPropertiesProvider: [ 'type', DataObjectPropertiesProvider ]
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { ListGroup } from '@bpmn-io/properties-panel';
|
||||||
|
import { DataObjectArray } from './DataObjectArray';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Also allows you to select which Data Objects are available
|
||||||
|
* in the process element.
|
||||||
|
* @param element The selected process
|
||||||
|
* @param moddle For updating the underlying xml object
|
||||||
|
* @returns {[{component: (function(*)), isEdited: *, id: string, element},{component:
|
||||||
|
* (function(*)), isEdited: *, id: string, element}]}
|
||||||
|
*/
|
||||||
|
export default function(element, moddle) {
|
||||||
|
|
||||||
|
const groupSections = [];
|
||||||
|
const dataObjectArray = {
|
||||||
|
id: 'editDataObjects',
|
||||||
|
element,
|
||||||
|
label: 'Available Data Objects',
|
||||||
|
component: ListGroup,
|
||||||
|
...DataObjectArray({ element, moddle })
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dataObjectArray.items) {
|
||||||
|
groupSections.push(dataObjectArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupSections;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
import { useService } from 'bpmn-js-properties-panel';
|
||||||
|
import {
|
||||||
|
isTextFieldEntryEdited,
|
||||||
|
TextFieldEntry,
|
||||||
|
} from '@bpmn-io/properties-panel';
|
||||||
|
import { without } from 'min-dash';
|
||||||
|
import { is } from 'bpmn-js/lib/util/ModelUtil';
|
||||||
|
import {
|
||||||
|
findDataObjects,
|
||||||
|
findDataObjectReferenceShapes,
|
||||||
|
idToHumanReadableName,
|
||||||
|
} from '../DataObjectHelpers';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a list of data objects, and allows you to add / remove data objects, and change their ids.
|
||||||
|
* @param props
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
export function DataObjectArray(props) {
|
||||||
|
const { moddle } = props;
|
||||||
|
const { element } = props;
|
||||||
|
const { commandStack } = props;
|
||||||
|
const { elementRegistry } = props;
|
||||||
|
let process;
|
||||||
|
|
||||||
|
// This element might be a process, or something that will reference a process.
|
||||||
|
if (is(element.businessObject, 'bpmn:Process') || is(element.businessObject, 'bpmn:SubProcess')) {
|
||||||
|
process = element.businessObject;
|
||||||
|
} else if (element.businessObject.processRef) {
|
||||||
|
process = element.businessObject.processRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataObjects = findDataObjects(process);
|
||||||
|
const items = dataObjects.map((dataObject, index) => {
|
||||||
|
const id = `${process.id}-dataObj-${index}`;
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
label: dataObject.id,
|
||||||
|
entries: DataObjectGroup({
|
||||||
|
idPrefix: id,
|
||||||
|
element,
|
||||||
|
dataObject,
|
||||||
|
}),
|
||||||
|
autoFocusEntry: `${id}-dataObject`,
|
||||||
|
remove: removeFactory({
|
||||||
|
element,
|
||||||
|
dataObject,
|
||||||
|
process,
|
||||||
|
commandStack,
|
||||||
|
elementRegistry,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function add(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const newDataObject = moddle.create('bpmn:DataObject');
|
||||||
|
const newElements = process.get('flowElements');
|
||||||
|
newDataObject.id = moddle.ids.nextPrefixed('DataObject_');
|
||||||
|
newDataObject.$parent = process;
|
||||||
|
newElements.push(newDataObject);
|
||||||
|
commandStack.execute('element.updateModdleProperties', {
|
||||||
|
element,
|
||||||
|
moddleElement: process,
|
||||||
|
properties: {
|
||||||
|
flowElements: newElements,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { items, add };
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFactory(props) {
|
||||||
|
const { element, dataObject, process, commandStack } = props;
|
||||||
|
|
||||||
|
return function (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
commandStack.execute('element.updateModdleProperties', {
|
||||||
|
element,
|
||||||
|
moddleElement: process,
|
||||||
|
properties: {
|
||||||
|
flowElements: without(process.get('flowElements'), dataObject),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// When a data object is removed, remove all references as well.
|
||||||
|
const references = findDataObjectReferenceShapes(element.children, dataObject.id);
|
||||||
|
for (const ref of references) {
|
||||||
|
commandStack.execute('shape.delete', { shape: ref });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function DataObjectGroup(props) {
|
||||||
|
const { idPrefix, dataObject } = props;
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: `${idPrefix}-dataObject`,
|
||||||
|
component: DataObjectTextField,
|
||||||
|
isEdited: isTextFieldEntryEdited,
|
||||||
|
idPrefix,
|
||||||
|
dataObject,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function DataObjectTextField(props) {
|
||||||
|
const { idPrefix, element, parameter, dataObject } = props;
|
||||||
|
|
||||||
|
const commandStack = useService('commandStack');
|
||||||
|
const debounce = useService('debounceInput');
|
||||||
|
|
||||||
|
const setValue = (value) => {
|
||||||
|
commandStack.execute('element.updateModdleProperties', {
|
||||||
|
element,
|
||||||
|
moddleElement: dataObject,
|
||||||
|
properties: {
|
||||||
|
id: value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Also update the label of all the references
|
||||||
|
const references = findDataObjectReferenceShapes(element.children, dataObject.id);
|
||||||
|
for (const ref of references) {
|
||||||
|
commandStack.execute('element.updateProperties', {
|
||||||
|
element: ref,
|
||||||
|
moddleElement: ref.businessObject,
|
||||||
|
properties: {
|
||||||
|
name: idToHumanReadableName(value),
|
||||||
|
},
|
||||||
|
changed: [ref], // everything is already marked as changed, don't recalculate.
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getValue = () => {
|
||||||
|
return dataObject.id;
|
||||||
|
};
|
||||||
|
|
||||||
|
return TextFieldEntry({
|
||||||
|
element: parameter,
|
||||||
|
id: `${idPrefix}-id`,
|
||||||
|
label: 'Data Object Id',
|
||||||
|
getValue,
|
||||||
|
setValue,
|
||||||
|
debounce,
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
import { is, isAny } from 'bpmn-js/lib/util/ModelUtil';
|
||||||
|
import { ListGroup, isTextFieldEntryEdited } from '@bpmn-io/properties-panel';
|
||||||
|
import { DataObjectSelect } from './DataObjectSelect';
|
||||||
|
import { DataObjectArray } from './DataObjectArray';
|
||||||
|
|
||||||
|
const LOW_PRIORITY = 500;
|
||||||
|
|
||||||
|
export default function DataObjectPropertiesProvider(
|
||||||
|
propertiesPanel,
|
||||||
|
translate,
|
||||||
|
moddle,
|
||||||
|
commandStack,
|
||||||
|
elementRegistry
|
||||||
|
) {
|
||||||
|
this.getGroups = function (element) {
|
||||||
|
return function (groups) {
|
||||||
|
if (is(element, 'bpmn:DataObjectReference')) {
|
||||||
|
groups.push(
|
||||||
|
createDataObjectSelector(element, translate, moddle, commandStack)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
isAny(element, ['bpmn:Process', 'bpmn:Participant']) ||
|
||||||
|
(is(element, 'bpmn:SubProcess') && !element.collapsed)
|
||||||
|
) {
|
||||||
|
groups.push(
|
||||||
|
createDataObjectEditor(
|
||||||
|
element,
|
||||||
|
translate,
|
||||||
|
moddle,
|
||||||
|
commandStack,
|
||||||
|
elementRegistry
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return groups;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
propertiesPanel.registerProvider(LOW_PRIORITY, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataObjectPropertiesProvider.$inject = [
|
||||||
|
'propertiesPanel',
|
||||||
|
'translate',
|
||||||
|
'moddle',
|
||||||
|
'commandStack',
|
||||||
|
'elementRegistry',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a group on the main panel with a select box (for choosing the Data Object to connect)
|
||||||
|
* @param element
|
||||||
|
* @param translate
|
||||||
|
* @param moddle
|
||||||
|
* @returns entries
|
||||||
|
*/
|
||||||
|
function createDataObjectSelector(element, translate, moddle, commandStack) {
|
||||||
|
return {
|
||||||
|
id: 'data_object_properties',
|
||||||
|
label: translate('Data Object Properties'),
|
||||||
|
entries: [
|
||||||
|
{
|
||||||
|
id: 'selectDataObject',
|
||||||
|
element,
|
||||||
|
component: DataObjectSelect,
|
||||||
|
isEdited: isTextFieldEntryEdited,
|
||||||
|
moddle,
|
||||||
|
commandStack,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a group on the main panel with a select box (for choosing the Data Object to connect) AND a
|
||||||
|
* full Data Object Array for modifying all the data objects.
|
||||||
|
* @param element
|
||||||
|
* @param translate
|
||||||
|
* @param moddle
|
||||||
|
* @returns entries
|
||||||
|
*/
|
||||||
|
function createDataObjectEditor(
|
||||||
|
element,
|
||||||
|
translate,
|
||||||
|
moddle,
|
||||||
|
commandStack,
|
||||||
|
elementRegistry
|
||||||
|
) {
|
||||||
|
const dataObjectArray = {
|
||||||
|
id: 'editDataObjects',
|
||||||
|
element,
|
||||||
|
label: 'Data Objects',
|
||||||
|
component: ListGroup,
|
||||||
|
...DataObjectArray({ element, moddle, commandStack, elementRegistry }),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dataObjectArray.items) {
|
||||||
|
return dataObjectArray;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
import {useService } from 'bpmn-js-properties-panel';
|
||||||
|
import { SelectEntry } from '@bpmn-io/properties-panel';
|
||||||
|
import {findDataObjects, idToHumanReadableName} from '../DataObjectHelpers';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the value of the given type within the extensionElements
|
||||||
|
* given a type of "spiff:preScript", would find it in this, and return
|
||||||
|
* the object.
|
||||||
|
*
|
||||||
|
* <bpmn:
|
||||||
|
<bpmn:userTask id="123" name="My User Task!">
|
||||||
|
<bpmn:extensionElements>
|
||||||
|
<spiffworkflow:preScript>
|
||||||
|
me = "100% awesome"
|
||||||
|
</spiffworkflow:preScript>
|
||||||
|
</bpmn:extensionElements>
|
||||||
|
...
|
||||||
|
</bpmn:userTask>
|
||||||
|
*
|
||||||
|
* @returns {string|null|*}
|
||||||
|
*/
|
||||||
|
export function DataObjectSelect(props) {
|
||||||
|
const element = props.element;
|
||||||
|
const commandStack = props.commandStack;
|
||||||
|
const debounce = useService('debounceInput');
|
||||||
|
|
||||||
|
|
||||||
|
const getValue = () => {
|
||||||
|
return element.businessObject.dataObjectRef.id
|
||||||
|
}
|
||||||
|
|
||||||
|
const setValue = value => {
|
||||||
|
const businessObject = element.businessObject;
|
||||||
|
const dataObjects = findDataObjects(businessObject.$parent)
|
||||||
|
for (const flowElem of dataObjects) {
|
||||||
|
if (flowElem.$type === 'bpmn:DataObject' && flowElem.id === value) {
|
||||||
|
commandStack.execute('element.updateModdleProperties', {
|
||||||
|
element,
|
||||||
|
moddleElement: businessObject,
|
||||||
|
properties: {
|
||||||
|
dataObjectRef: flowElem
|
||||||
|
}
|
||||||
|
});
|
||||||
|
commandStack.execute('element.updateProperties', {
|
||||||
|
element,
|
||||||
|
moddleElement: businessObject,
|
||||||
|
properties: {
|
||||||
|
'name': idToHumanReadableName(flowElem.id)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getOptions = value => {
|
||||||
|
const businessObject = element.businessObject;
|
||||||
|
const parent = businessObject.$parent;
|
||||||
|
let dataObjects = findDataObjects(parent);
|
||||||
|
let options = [];
|
||||||
|
dataObjects.forEach(dataObj => {
|
||||||
|
options.push({label: dataObj.id, value: dataObj.id})
|
||||||
|
});
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <SelectEntry
|
||||||
|
id={'selectDataObject'}
|
||||||
|
element={element}
|
||||||
|
description={"Select the Data Object this represents."}
|
||||||
|
label={"Which Data Object does this reference?"}
|
||||||
|
getValue={ getValue }
|
||||||
|
setValue={ setValue }
|
||||||
|
getOptions={ getOptions }
|
||||||
|
debounce={debounce}
|
||||||
|
/>;
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue