Squashed 'bpmn-js-spiffworkflow/' changes from a547888ef..c4843c17b
c4843c17b Merge pull request #26 from sartography/feature/inherited-data-objects 9e2a8f384 minor tweak for adding data objects to lanes/participants. ada919e59 add a few tests on data object visibility 627e771d4 allow subprocesses to inherit data objects 887f318f7 Minor cleanup of display in bpmn-js git-subtree-dir: bpmn-js-spiffworkflow git-subtree-split: c4843c17b869d1c730494dc10ddb31d761e2ac40
This commit is contained in:
parent
3add069267
commit
1be006811b
|
@ -3,7 +3,7 @@ import {
|
|||
BpmnPropertiesPanelModule,
|
||||
BpmnPropertiesProviderModule,
|
||||
} from 'bpmn-js-properties-panel';
|
||||
import diagramXML from '../test/spec/bpmn/basic_message.bpmn';
|
||||
import diagramXML from '../test/spec/bpmn/empty_diagram.bpmn';
|
||||
import spiffworkflow from './spiffworkflow';
|
||||
import setupFileOperations from './fileOperations';
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @param container
|
||||
*/
|
||||
|
||||
|
||||
export function findDataObjects(parent) {
|
||||
let dataObjects = [];
|
||||
export function findDataObjects(parent, dataObjects) {
|
||||
if (typeof(dataObjects) === 'undefined')
|
||||
dataObjects = [];
|
||||
let process;
|
||||
if (!parent) {
|
||||
return [];
|
||||
|
@ -15,15 +15,12 @@ export function findDataObjects(parent) {
|
|||
process = parent.processRef;
|
||||
} else {
|
||||
process = parent;
|
||||
if (process.$type === 'bpmn:SubProcess')
|
||||
findDataObjects(process.$parent, dataObjects);
|
||||
}
|
||||
if (!process.flowElements) {
|
||||
return [];
|
||||
}
|
||||
if (typeof(process.flowElements) !== 'undefined') {
|
||||
for (const element of process.flowElements) {
|
||||
if (
|
||||
element.$type === 'bpmn:DataObject' &&
|
||||
dataObjects.indexOf(element) < 0
|
||||
) {
|
||||
if (element.$type === 'bpmn:DataObject')
|
||||
dataObjects.push(element);
|
||||
}
|
||||
}
|
||||
|
@ -38,16 +35,26 @@ export function findDataObject(process, id) {
|
|||
}
|
||||
}
|
||||
|
||||
export function findDataReferenceShapes(processShape, id) {
|
||||
let refs = [];
|
||||
for (const shape of processShape.children) {
|
||||
if (shape.type === 'bpmn:DataObjectReference') {
|
||||
if (shape.businessObject.dataObjectRef && shape.businessObject.dataObjectRef.id === id) {
|
||||
refs.push(shape);
|
||||
export function findDataObjectReferences(children, dataObjectId) {
|
||||
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 [];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return refs;
|
||||
|
||||
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) {
|
||||
|
|
|
@ -3,11 +3,12 @@ import { getDi, is } from 'bpmn-js/lib/util/ModelUtil';
|
|||
import { remove as collectionRemove } from 'diagram-js/lib/util/Collections';
|
||||
import {
|
||||
findDataObjects,
|
||||
findDataReferenceShapes,
|
||||
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.
|
||||
|
@ -20,9 +21,40 @@ const HIGH_PRIORITY = 1500;
|
|||
* 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) {
|
||||
|
||||
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');
|
||||
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(this, businessObject, parentBusinessObject);
|
||||
};
|
||||
|
||||
/**
|
||||
* For DataObjectReferences only ...
|
||||
* Prevent this from calling the CreateDataObjectBehavior in BPMN-js, as it will
|
||||
|
@ -52,9 +84,9 @@ export default class DataObjectInterceptor extends CommandInterceptor {
|
|||
} else {
|
||||
dataObject = bpmnFactory.create('bpmn:DataObject');
|
||||
}
|
||||
|
||||
// set the reference to the DataObject
|
||||
shape.businessObject.dataObjectRef = dataObject;
|
||||
shape.businessObject.$parent = process;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -84,38 +116,19 @@ export default class DataObjectInterceptor extends CommandInterceptor {
|
|||
*/
|
||||
this.executed(['shape.delete'], HIGH_PRIORITY, function (event) {
|
||||
const { context } = event;
|
||||
const { shape, oldParent } = context;
|
||||
const { shape } = context;
|
||||
if (is(shape, 'bpmn:DataObjectReference') && shape.type !== 'label') {
|
||||
const references = findDataReferenceShapes(
|
||||
oldParent,
|
||||
shape.businessObject.dataObjectRef.id
|
||||
);
|
||||
const dataObject = shape.businessObject.dataObjectRef;
|
||||
let flowElements = shape.businessObject.$parent.get('flowElements');
|
||||
collectionRemove(flowElements, shape.businessObject);
|
||||
let references = findDataObjectReferences(flowElements, dataObject.id);
|
||||
if (references.length === 0) {
|
||||
return; // Use the default bahavior and delete the data object.
|
||||
let flowElements = dataObject.$parent.get('flowElements');
|
||||
collectionRemove(flowElements, dataObject);
|
||||
}
|
||||
// Remove the business Object
|
||||
let containment = '';
|
||||
const { businessObject } = shape;
|
||||
if (is(businessObject, 'bpmn:DataOutputAssociation')) {
|
||||
containment = 'dataOutputAssociations';
|
||||
}
|
||||
if (is(businessObject, 'bpmn:DataInputAssociation')) {
|
||||
containment = 'dataInputAssociations';
|
||||
}
|
||||
const children = businessObject.$parent.get(containment);
|
||||
collectionRemove(children, businessObject);
|
||||
|
||||
// Remove the visible element.
|
||||
const di = getDi(shape);
|
||||
const planeElements = di.$parent.get('planeElement');
|
||||
collectionRemove(planeElements, di);
|
||||
di.$parent = null;
|
||||
|
||||
// Stop the propogation.
|
||||
event.stopPropagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
DataObjectInterceptor.$inject = ['eventBus', 'bpmnFactory', 'commandStack'];
|
||||
DataObjectInterceptor.$inject = ['eventBus', 'bpmnFactory', 'commandStack', 'bpmnUpdater'];
|
||||
|
|
|
@ -5,7 +5,11 @@ import {
|
|||
} from '@bpmn-io/properties-panel';
|
||||
import { without } from 'min-dash';
|
||||
import { is } from 'bpmn-js/lib/util/ModelUtil';
|
||||
import {findDataObjects, findDataReferenceShapes, idToHumanReadableName} from '../DataObjectHelpers';
|
||||
import {
|
||||
findDataObjects,
|
||||
findDataObjectReferenceShapes,
|
||||
idToHumanReadableName,
|
||||
} from '../DataObjectHelpers';
|
||||
|
||||
/**
|
||||
* Provides a list of data objects, and allows you to add / remove data objects, and change their ids.
|
||||
|
@ -20,7 +24,7 @@ export function DataObjectArray(props) {
|
|||
let process;
|
||||
|
||||
// This element might be a process, or something that will reference a process.
|
||||
if (is(element.businessObject, 'bpmn:Process')) {
|
||||
if (is(element.businessObject, 'bpmn:Process') || is(element.businessObject, 'bpmn:SubProcess')) {
|
||||
process = element.businessObject;
|
||||
} else if (element.businessObject.processRef) {
|
||||
process = element.businessObject.processRef;
|
||||
|
@ -53,6 +57,7 @@ export function DataObjectArray(props) {
|
|||
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,
|
||||
|
@ -79,7 +84,7 @@ function removeFactory(props) {
|
|||
},
|
||||
});
|
||||
// When a data object is removed, remove all references as well.
|
||||
const references = findDataReferenceShapes(element, dataObject.id);
|
||||
const references = findDataObjectReferenceShapes(element.children, dataObject.id);
|
||||
for (const ref of references) {
|
||||
commandStack.execute('shape.delete', { shape: ref });
|
||||
}
|
||||
|
@ -116,7 +121,7 @@ function DataObjectTextField(props) {
|
|||
});
|
||||
|
||||
// Also update the label of all the references
|
||||
const references = findDataReferenceShapes(element, dataObject.id);
|
||||
const references = findDataObjectReferenceShapes(element.children, dataObject.id);
|
||||
for (const ref of references) {
|
||||
commandStack.execute('element.updateProperties', {
|
||||
element: ref,
|
||||
|
|
|
@ -20,7 +20,8 @@ export default function DataObjectPropertiesProvider(
|
|||
);
|
||||
}
|
||||
if (
|
||||
isAny(element, ['bpmn:Process', 'bpmn:SubProcess', 'bpmn:Participant'])
|
||||
isAny(element, ['bpmn:Process', 'bpmn:Participant']) ||
|
||||
(is(element, 'bpmn:SubProcess') && !element.collapsed)
|
||||
) {
|
||||
groups.push(
|
||||
createDataObjectEditor(
|
||||
|
|
|
@ -37,7 +37,7 @@ export function CorrelationPropertiesArray(props) {
|
|||
});
|
||||
return {
|
||||
id,
|
||||
label: correlationPropertyModdleElement.id,
|
||||
label: correlationPropertyModdleElement.name,
|
||||
entries,
|
||||
autoFocusEntry: id,
|
||||
remove: removeFactory({
|
||||
|
|
|
@ -44,7 +44,7 @@ export function MessageCorrelationPropertiesArray(props) {
|
|||
});
|
||||
return {
|
||||
id,
|
||||
label: correlationPropertyModdleElement.id,
|
||||
label: correlationPropertyModdleElement.name,
|
||||
entries,
|
||||
autoFocusEntry: id,
|
||||
remove: removeFactory({
|
||||
|
|
|
@ -4,7 +4,11 @@ import { BpmnPropertiesPanelModule, BpmnPropertiesProviderModule } from 'bpmn-js
|
|||
import {
|
||||
inject,
|
||||
} from 'bpmn-js/test/helper';
|
||||
import {findDataObjects, idToHumanReadableName} from '../../app/spiffworkflow/DataObject/DataObjectHelpers';
|
||||
import {
|
||||
findDataObjects,
|
||||
findDataObjectReferenceShapes,
|
||||
idToHumanReadableName,
|
||||
} from '../../app/spiffworkflow/DataObject/DataObjectHelpers';
|
||||
|
||||
describe('DataObject Interceptor', function() {
|
||||
|
||||
|
@ -113,4 +117,52 @@ describe('DataObject Interceptor', function() {
|
|||
expect(dataObjects.length).to.equal(1);
|
||||
}));
|
||||
|
||||
it('Data objects in a process should be visible in a subprocess', inject(function(canvas, modeling, elementRegistry) {
|
||||
|
||||
let subProcessShape = elementRegistry.get('my_subprocess');
|
||||
let subProcess = subProcessShape.businessObject;
|
||||
let dataObjects = findDataObjects(subProcess);
|
||||
expect(dataObjects.length).to.equal(0);
|
||||
|
||||
let rootShape = canvas.getRootElement();
|
||||
const dataObjectRefShape = modeling.createShape({ type: 'bpmn:DataObjectReference' },
|
||||
{ x: 220, y: 220 }, rootShape);
|
||||
|
||||
dataObjects = findDataObjects(subProcess);
|
||||
expect(dataObjects.length).to.equal(1);
|
||||
}));
|
||||
|
||||
it('Data objects in a subprocess should not be visible in a process', inject(function(canvas, modeling, elementRegistry) {
|
||||
|
||||
let subProcessShape = elementRegistry.get('my_subprocess');
|
||||
let subProcess = subProcessShape.businessObject;
|
||||
const dataObjectRefShape = modeling.createShape({ type: 'bpmn:DataObjectReference' },
|
||||
{ x: 220, y: 220 }, subProcessShape);
|
||||
|
||||
let dataObjects = findDataObjects(subProcess);
|
||||
expect(dataObjects.length).to.equal(1);
|
||||
|
||||
let rootShape = canvas.getRootElement();
|
||||
dataObjects = findDataObjects(rootShape);
|
||||
expect(dataObjects.length).to.equal(0);
|
||||
}));
|
||||
|
||||
it('References inside subprocesses should be visible in a process', inject(function(canvas, modeling, elementRegistry) {
|
||||
|
||||
let rootShape = canvas.getRootElement();
|
||||
const refOne = modeling.createShape({ type: 'bpmn:DataObjectReference' },
|
||||
{ x: 220, y: 220 }, rootShape);
|
||||
|
||||
let subProcessShape = elementRegistry.get('my_subprocess');
|
||||
let subProcess = subProcessShape.businessObject;
|
||||
const refTwo = modeling.createShape({ type: 'bpmn:DataObjectReference' },
|
||||
{ x: 320, y: 220 }, subProcessShape);
|
||||
|
||||
let dataObjects = findDataObjects(subProcess);
|
||||
expect(dataObjects.length).to.equal(1);
|
||||
let references = findDataObjectReferenceShapes(rootShape.children, dataObjects[0].id);
|
||||
expect(references.length).to.equal(2);
|
||||
|
||||
}));
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue