@processmaker/modeler 1.26.0 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/img/clipboard.bcc7796a.svg +1 -0
- package/dist/modeler.common.js +1790 -740
- package/dist/modeler.common.js.map +1 -1
- package/dist/modeler.umd.js +1790 -740
- package/dist/modeler.umd.js.map +1 -1
- package/dist/modeler.umd.min.js +3 -3
- package/dist/modeler.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/NodeIdGenerator.js +55 -22
- package/src/NodeInspector.js +2 -2
- package/src/assets/clipboard.svg +1 -0
- package/src/components/crown/crownButtons/copyButton.vue +3 -3
- package/src/components/crown/crownButtons/duplicateButton.vue +40 -0
- package/src/components/crown/crownConfig/crownConfig.vue +7 -1
- package/src/components/crown/crownMultiselect/crownMultiselect.vue +15 -6
- package/src/components/crown/utils.js +12 -1
- package/src/components/hotkeys/copyPaste.js +26 -0
- package/src/components/hotkeys/main.js +9 -2
- package/src/components/inspectors/InspectorPanel.vue +1 -0
- package/src/components/inspectors/LoopCharacteristics.vue +5 -2
- package/src/components/inspectors/process.js +5 -1
- package/src/components/modeler/Modeler.vue +104 -4
- package/src/components/modeler/Selection.vue +18 -4
- package/src/components/nodes/association/index.js +3 -0
- package/src/components/nodes/dataInputAssociation/dataInputAssociation.vue +36 -26
- package/src/components/nodes/genericFlow/DataOutputAssociation.js +54 -2
- package/src/components/nodes/genericFlow/genericFlow.vue +0 -17
- package/src/components/nodes/node.js +106 -2
- package/src/components/toolbar/ToolBar.vue +17 -3
- package/src/components/toolbar/breadcrumb/Breadcrumb.vue +7 -0
- package/src/components/toolbar/toolbar.scss +11 -0
- package/src/mixins/cloneSelection.js +145 -0
- package/src/mixins/linkConfig.js +4 -1
- package/src/store.js +11 -0
|
@@ -29,6 +29,7 @@ import { id as poolId } from '@/components/nodes/pool/config';
|
|
|
29
29
|
import { id as laneId } from '@/components/nodes/poolLane/config';
|
|
30
30
|
import { id as genericFlowId } from '@/components/nodes/genericFlow/config';
|
|
31
31
|
import { labelWidth, poolPadding } from '../nodes/pool/poolSizes';
|
|
32
|
+
|
|
32
33
|
export default {
|
|
33
34
|
name: 'Selection',
|
|
34
35
|
components: {
|
|
@@ -85,6 +86,17 @@ export default {
|
|
|
85
86
|
},
|
|
86
87
|
},
|
|
87
88
|
methods: {
|
|
89
|
+
async selectElements(elements) {
|
|
90
|
+
await this.$nextTick();
|
|
91
|
+
this.clearSelection();
|
|
92
|
+
this.selected = elements;
|
|
93
|
+
this.showLasso = true;
|
|
94
|
+
this.isSelected = true;
|
|
95
|
+
this.isSelecting = true;
|
|
96
|
+
this.start = null;
|
|
97
|
+
await this.$nextTick();
|
|
98
|
+
this.updateSelectionBox();
|
|
99
|
+
},
|
|
88
100
|
/**
|
|
89
101
|
* Select an element dinamically.
|
|
90
102
|
* Shift key will manage the condition to push to selection
|
|
@@ -321,18 +333,17 @@ export default {
|
|
|
321
333
|
* Filter the selected elements
|
|
322
334
|
*/
|
|
323
335
|
filterSelected() {
|
|
324
|
-
//
|
|
336
|
+
// Get the selected pools IDs
|
|
325
337
|
const selectedPoolsIds = this.selected
|
|
326
338
|
.filter(shape => shape.model.component)
|
|
327
339
|
.filter(shape => shape.model.component.node.type === 'processmaker-modeler-pool')
|
|
328
340
|
.map(shape => shape.model.component.node.id);
|
|
341
|
+
// remove from selection the selected children that belongs to a selected pool
|
|
329
342
|
this.selected = this.selected.filter(shape => {
|
|
330
343
|
if (shape.model.component && shape.model.component.node.pool) {
|
|
331
344
|
return shape.model.component.node.pool && !selectedPoolsIds.includes(shape.model.component.node.pool.component.node.id);
|
|
332
345
|
}
|
|
333
346
|
return true;
|
|
334
|
-
}).filter(shape => {
|
|
335
|
-
return !(shape.model.getParentCell() && shape.model.getParentCell().get('parent'));
|
|
336
347
|
});
|
|
337
348
|
},
|
|
338
349
|
/**
|
|
@@ -377,7 +388,7 @@ export default {
|
|
|
377
388
|
return shapes && selected.length === shapes.length;
|
|
378
389
|
},
|
|
379
390
|
/**
|
|
380
|
-
* Start the drag procedure for the
|
|
391
|
+
* Start the drag procedure for the select box
|
|
381
392
|
* @param {Object} event
|
|
382
393
|
*/
|
|
383
394
|
startDrag(event) {
|
|
@@ -440,6 +451,9 @@ export default {
|
|
|
440
451
|
this.$emit('save-state');
|
|
441
452
|
this.dragging = false;
|
|
442
453
|
this.stopForceMove = false;
|
|
454
|
+
// Readjusts the selection box, taking into consideration elements
|
|
455
|
+
// that are anchored and did not move, such as boundary events.
|
|
456
|
+
this.updateSelectionBox();
|
|
443
457
|
},
|
|
444
458
|
/**
|
|
445
459
|
* Translate the Selected shapes adding some custom validations
|
|
@@ -21,7 +21,7 @@ import linkConfig from '@/mixins/linkConfig';
|
|
|
21
21
|
import get from 'lodash/get';
|
|
22
22
|
import associationHead from '!!url-loader!@/assets/association-head.svg';
|
|
23
23
|
import CrownConfig from '@/components/crown/crownConfig/crownConfig';
|
|
24
|
-
import { getOrFindDataInput, removeDataInput } from '@/components/crown/utils';
|
|
24
|
+
import { getOrFindDataInput, removeDataInput, findIOSpecificationOwner } from '@/components/crown/utils';
|
|
25
25
|
import { pull } from 'lodash';
|
|
26
26
|
|
|
27
27
|
export default {
|
|
@@ -50,20 +50,38 @@ export default {
|
|
|
50
50
|
},
|
|
51
51
|
computed: {
|
|
52
52
|
isValidConnection() {
|
|
53
|
-
const targetType = get(this.target, 'component.node.type');
|
|
53
|
+
const targetType = get(this.target, 'component.node.definition.$type');
|
|
54
54
|
|
|
55
55
|
if (!targetType) {
|
|
56
56
|
return false;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
const dataStoreValidTargets = [
|
|
60
|
+
'bpmn:Task',
|
|
61
|
+
'bpmn:SubProcess',
|
|
62
|
+
'bpmn:CallActivity',
|
|
63
|
+
'bpmn:ManualTask',
|
|
64
|
+
'bpmn:ScriptTask',
|
|
65
|
+
'bpmn:ServiceTask',
|
|
66
|
+
];
|
|
67
|
+
const dataObjectValidTargets = [
|
|
68
|
+
'bpmn:Task',
|
|
69
|
+
'bpmn:SubProcess',
|
|
70
|
+
'bpmn:CallActivity',
|
|
71
|
+
'bpmn:ManualTask',
|
|
72
|
+
'bpmn:ScriptTask',
|
|
73
|
+
'bpmn:ServiceTask',
|
|
74
|
+
'bpmn:IntermediateThrowEvent',
|
|
75
|
+
'bpmn:EndEvent',
|
|
76
|
+
];
|
|
61
77
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
78
|
+
const sourceIsDataStore = this.sourceNode.definition.$type === 'bpmn:DataStoreReference';
|
|
79
|
+
const sourceIsDataObject = this.sourceNode.definition.$type === 'bpmn:DataObjectReference';
|
|
65
80
|
|
|
66
|
-
|
|
81
|
+
if (sourceIsDataStore && dataStoreValidTargets.includes(targetType)) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
return (sourceIsDataObject && dataObjectValidTargets.includes(targetType));
|
|
67
85
|
},
|
|
68
86
|
},
|
|
69
87
|
methods: {
|
|
@@ -71,29 +89,16 @@ export default {
|
|
|
71
89
|
if (this.node.dataAssociationProps) {
|
|
72
90
|
return this.node.dataAssociationProps.sourceShape;
|
|
73
91
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
const dataObjectDefinition = taskWithInputAssociation.component.node.definition.get('dataInputAssociations')[0].sourceRef[0];
|
|
81
|
-
|
|
82
|
-
return this.graph.getElements().find(element => {
|
|
83
|
-
return element.component && element.component.node.definition === dataObjectDefinition;
|
|
84
|
-
});
|
|
92
|
+
const source = this.node.definition.sourceRef[0];
|
|
93
|
+
// find shape
|
|
94
|
+
const shape = this.graph.getElements().find(e=>e.component.node.definition === source);
|
|
95
|
+
return shape;
|
|
85
96
|
},
|
|
86
97
|
getTargetRef() {
|
|
87
98
|
if (this.node.dataAssociationProps) {
|
|
88
99
|
return this.node.dataAssociationProps.targetCoords;
|
|
89
100
|
}
|
|
90
|
-
|
|
91
|
-
const taskWithInputAssociation = this.graph.getElements().find(element => {
|
|
92
|
-
return element.component && element.component.node.definition.get('dataInputAssociations') &&
|
|
93
|
-
element.component.node.definition.get('dataInputAssociations')[0] === this.node.definition;
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
return taskWithInputAssociation.component.node.definition;
|
|
101
|
+
return findIOSpecificationOwner(this.node.definition.targetRef.$parent, this.$parent);
|
|
97
102
|
},
|
|
98
103
|
updateRouter() {
|
|
99
104
|
this.shape.router('normal', { elementPadding: this.elementPadding });
|
|
@@ -102,6 +107,7 @@ export default {
|
|
|
102
107
|
const targetShape = this.shape.getTargetElement();
|
|
103
108
|
const dataInput = getOrFindDataInput(this.moddle, targetShape.component.node, this.sourceNode.definition);
|
|
104
109
|
this.node.definition.set('targetRef', dataInput);
|
|
110
|
+
// @todo Review why this needs to be and array. When saving the BPMN, if this is not an array the sourceRef is not stored
|
|
105
111
|
this.node.definition.set('sourceRef', [this.sourceNode.definition]);
|
|
106
112
|
targetShape.component.node.definition.set('dataInputAssociations', [this.node.definition]);
|
|
107
113
|
},
|
|
@@ -129,6 +135,10 @@ export default {
|
|
|
129
135
|
this.shape.component = this;
|
|
130
136
|
},
|
|
131
137
|
destroyed() {
|
|
138
|
+
// when a association was not completed this.targetNode will be undefined
|
|
139
|
+
if (!this.targetNode) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
132
142
|
removeDataInput(this.targetNode, this.sourceNode.definition);
|
|
133
143
|
pull(this.targetNode.definition.get('dataInputAssociations'), this.node.definition);
|
|
134
144
|
},
|
|
@@ -12,8 +12,60 @@ export default class DataOutputAssociation extends DataAssociation {
|
|
|
12
12
|
return false;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const dataStoreValidSources = [
|
|
16
|
+
'bpmn:Task',
|
|
17
|
+
'bpmn:SubProcess',
|
|
18
|
+
'bpmn:CallActivity',
|
|
19
|
+
'bpmn:ManualTask',
|
|
20
|
+
'bpmn:ScriptTask',
|
|
21
|
+
'bpmn:ServiceTask',
|
|
22
|
+
];
|
|
23
|
+
const dataStoreValidTargets = [
|
|
24
|
+
'bpmn:Task',
|
|
25
|
+
'bpmn:SubProcess',
|
|
26
|
+
'bpmn:CallActivity',
|
|
27
|
+
'bpmn:ManualTask',
|
|
28
|
+
'bpmn:ScriptTask',
|
|
29
|
+
'bpmn:ServiceTask',
|
|
30
|
+
];
|
|
31
|
+
const dataObjectValidSources = [
|
|
32
|
+
'bpmn:Task',
|
|
33
|
+
'bpmn:SubProcess',
|
|
34
|
+
'bpmn:CallActivity',
|
|
35
|
+
'bpmn:ManualTask',
|
|
36
|
+
'bpmn:ScriptTask',
|
|
37
|
+
'bpmn:ServiceTask',
|
|
38
|
+
'bpmn:IntermediateCatchEvent',
|
|
39
|
+
'bpmn:StartEvent',
|
|
40
|
+
];
|
|
41
|
+
const dataObjectValidTargets = [
|
|
42
|
+
'bpmn:Task',
|
|
43
|
+
'bpmn:SubProcess',
|
|
44
|
+
'bpmn:CallActivity',
|
|
45
|
+
'bpmn:ManualTask',
|
|
46
|
+
'bpmn:ScriptTask',
|
|
47
|
+
'bpmn:ServiceTask',
|
|
48
|
+
'bpmn:IntermediateThrowEvent',
|
|
49
|
+
'bpmn:EndEvent',
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const sourceType = sourceNode.definition.$type;
|
|
53
|
+
const targetType = targetNode.definition.$type;
|
|
54
|
+
const sourceIsDataStore = sourceNode.definition.$type === 'bpmn:DataStoreReference';
|
|
55
|
+
const sourceIsDataObject = sourceNode.definition.$type === 'bpmn:DataObjectReference';
|
|
56
|
+
const targetIsDataStore = targetNode.definition.$type === 'bpmn:DataStoreReference';
|
|
57
|
+
const targetIsDataObject = targetNode.definition.$type === 'bpmn:DataObjectReference';
|
|
58
|
+
|
|
59
|
+
if (sourceIsDataStore && dataStoreValidTargets.includes(targetType)) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
if (sourceIsDataObject && dataObjectValidTargets.includes(targetType)) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
if (targetIsDataStore && dataStoreValidSources.includes(sourceType)) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return (targetIsDataObject && dataObjectValidSources.includes(sourceType));
|
|
17
69
|
}
|
|
18
70
|
|
|
19
71
|
makeFlowNode(sourceShape, targetShape, genericLink) {
|
|
@@ -86,23 +86,6 @@ export default {
|
|
|
86
86
|
},
|
|
87
87
|
},
|
|
88
88
|
watch: {
|
|
89
|
-
'node.definition': {
|
|
90
|
-
handler() {
|
|
91
|
-
const newNameLabel = this.shapeName;
|
|
92
|
-
|
|
93
|
-
if (newNameLabel !== this.nameLabel) {
|
|
94
|
-
this.nameLabel = newNameLabel;
|
|
95
|
-
}
|
|
96
|
-
this.setDefaultMarker(this.isDefaultFlow());
|
|
97
|
-
},
|
|
98
|
-
deep: true,
|
|
99
|
-
},
|
|
100
|
-
'node.definition.sourceRef': {
|
|
101
|
-
handler() {
|
|
102
|
-
this.setDefaultMarker(this.isDefaultFlow());
|
|
103
|
-
},
|
|
104
|
-
deep: true,
|
|
105
|
-
},
|
|
106
89
|
},
|
|
107
90
|
methods: {
|
|
108
91
|
completeLink() {
|
|
@@ -10,7 +10,8 @@ import cloneDeep from 'lodash/cloneDeep';
|
|
|
10
10
|
|
|
11
11
|
export default class Node {
|
|
12
12
|
static diagramPropertiesToCopy = ['x', 'y', 'width', 'height'];
|
|
13
|
-
static definitionPropertiesToNotCopy = ['$type', 'id'];
|
|
13
|
+
static definitionPropertiesToNotCopy = ['$type', 'id', 'dataOutputAssociations'];
|
|
14
|
+
static flowDefinitionPropertiesToNotCopy = ['$type', 'id', 'sourceRef', 'targetRef'];
|
|
14
15
|
static eventDefinitionPropertiesToNotCopy = ['errorRef', 'messageRef'];
|
|
15
16
|
|
|
16
17
|
type;
|
|
@@ -80,6 +81,70 @@ export default class Node {
|
|
|
80
81
|
this.diagram.id = diagramId;
|
|
81
82
|
this.diagram.bpmnElement = this.definition;
|
|
82
83
|
}
|
|
84
|
+
if (this.definition.loopCharacteristics && this.definition.loopCharacteristics.$type === 'bpmn:StandardLoopCharacteristics') {
|
|
85
|
+
this.definition.loopCharacteristics.set('id', nodeIdGenerator.generate()[0]);
|
|
86
|
+
if (this.definition.loopCharacteristics.loopCondition) {
|
|
87
|
+
this.definition.loopCharacteristics.get('loopCondition').set('id', nodeIdGenerator.generate()[0]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
let dataInputRef, dataOutputRef;
|
|
91
|
+
if (this.definition.ioSpecification) {
|
|
92
|
+
this.definition.ioSpecification.set('id', nodeIdGenerator.generate()[0]);
|
|
93
|
+
const taskId = this.definition.id;
|
|
94
|
+
if (this.definition.ioSpecification.get('dataInputs')) {
|
|
95
|
+
this.definition.ioSpecification.get('dataInputs').forEach(dataInput => {
|
|
96
|
+
const id = dataInput.get('id');
|
|
97
|
+
if (id.substring(0, this.cloneOf.length) === this.cloneOf) {
|
|
98
|
+
dataInput.set('id', id.replace(this.cloneOf + '_', taskId + '_'));
|
|
99
|
+
dataInputRef = dataInput;
|
|
100
|
+
} else {
|
|
101
|
+
dataInput.set('id', nodeIdGenerator.generate()[0]);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (this.definition.ioSpecification.get('dataOutputs')) {
|
|
106
|
+
this.definition.ioSpecification.get('dataOutputs').forEach(dataOutput => {
|
|
107
|
+
const id = dataOutput.get('id');
|
|
108
|
+
if (id.substring(0, this.cloneOf.length) === this.cloneOf) {
|
|
109
|
+
dataOutput.set('id', id.replace(this.cloneOf + '_', taskId + '_'));
|
|
110
|
+
dataOutputRef = dataOutput;
|
|
111
|
+
} else {
|
|
112
|
+
dataOutput.set('id', nodeIdGenerator.generate()[0]);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
if (this.definition.ioSpecification.get('inputSets')) {
|
|
117
|
+
this.definition.ioSpecification.get('inputSets').forEach(inputSet => {
|
|
118
|
+
inputSet.set('id', nodeIdGenerator.generate()[0]);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (this.definition.ioSpecification.get('outputSets')) {
|
|
122
|
+
this.definition.ioSpecification.get('outputSets').forEach(outputSet => {
|
|
123
|
+
outputSet.set('id', nodeIdGenerator.generate()[0]);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (this.definition.loopCharacteristics && this.definition.loopCharacteristics.$type === 'bpmn:MultiInstanceLoopCharacteristics') {
|
|
128
|
+
this.definition.loopCharacteristics.set('id', nodeIdGenerator.generate()[0]);
|
|
129
|
+
if (this.definition.loopCharacteristics.loopCardinality) {
|
|
130
|
+
this.definition.loopCharacteristics.get('loopCardinality').set('id', nodeIdGenerator.generate()[0]);
|
|
131
|
+
}
|
|
132
|
+
if (this.definition.loopCharacteristics.loopDataInputRef && dataInputRef) {
|
|
133
|
+
this.definition.loopCharacteristics.set('loopDataInputRef', dataInputRef);
|
|
134
|
+
}
|
|
135
|
+
if (this.definition.loopCharacteristics.loopDataOutputRef && dataOutputRef) {
|
|
136
|
+
this.definition.loopCharacteristics.set('loopDataOutputRef', dataOutputRef);
|
|
137
|
+
}
|
|
138
|
+
if (this.definition.loopCharacteristics.inputDataItem) {
|
|
139
|
+
this.definition.loopCharacteristics.get('inputDataItem').set('id', nodeIdGenerator.generate()[0]);
|
|
140
|
+
}
|
|
141
|
+
if (this.definition.loopCharacteristics.outputDataItem) {
|
|
142
|
+
this.definition.loopCharacteristics.get('outputDataItem').set('id', nodeIdGenerator.generate()[0]);
|
|
143
|
+
}
|
|
144
|
+
if (this.definition.loopCharacteristics.completionCondition) {
|
|
145
|
+
this.definition.loopCharacteristics.get('completionCondition').set('id', nodeIdGenerator.generate()[0]);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
83
148
|
}
|
|
84
149
|
|
|
85
150
|
clone(nodeRegistry, moddle, $t) {
|
|
@@ -89,6 +154,8 @@ export default class Node {
|
|
|
89
154
|
|
|
90
155
|
clonedNode.id = null;
|
|
91
156
|
clonedNode.pool = this.pool;
|
|
157
|
+
clonedNode.cloneOf = this.id;
|
|
158
|
+
|
|
92
159
|
Node.diagramPropertiesToCopy.forEach(prop => clonedNode.diagram.bounds[prop] = this.diagram.bounds[prop]);
|
|
93
160
|
Object.keys(this.definition).filter(key => !Node.definitionPropertiesToNotCopy.includes(key)).forEach(key => {
|
|
94
161
|
const definition = this.definition.get(key);
|
|
@@ -96,7 +163,7 @@ export default class Node {
|
|
|
96
163
|
if (key === 'eventDefinitions') {
|
|
97
164
|
for (var i in clonedDefinition) {
|
|
98
165
|
if (definition[i].signalRef && !clonedDefinition[i].signalRef) {
|
|
99
|
-
clonedDefinition[i].signalRef
|
|
166
|
+
clonedDefinition[i].set('signalRef', { ...definition[i].signalRef });
|
|
100
167
|
}
|
|
101
168
|
}
|
|
102
169
|
}
|
|
@@ -112,6 +179,43 @@ export default class Node {
|
|
|
112
179
|
return clonedNode;
|
|
113
180
|
}
|
|
114
181
|
|
|
182
|
+
cloneFlow(nodeRegistry, moddle, $t) {
|
|
183
|
+
const definition = nodeRegistry[this.type].definition(moddle, $t);
|
|
184
|
+
const diagram = nodeRegistry[this.type].diagram(moddle);
|
|
185
|
+
const clonedFlow = new this.constructor(this.type, definition, diagram);
|
|
186
|
+
|
|
187
|
+
clonedFlow.id = null;
|
|
188
|
+
clonedFlow.pool = this.pool;
|
|
189
|
+
clonedFlow.cloneOf = this.id;
|
|
190
|
+
clonedFlow.diagram.waypoint = [];
|
|
191
|
+
|
|
192
|
+
this.diagram.waypoint.forEach(point => clonedFlow.diagram.waypoint.push(point));
|
|
193
|
+
|
|
194
|
+
Object.keys(this.definition).filter(key => !Node.flowDefinitionPropertiesToNotCopy.includes(key)).forEach(key => {
|
|
195
|
+
const definition = this.definition.get(key);
|
|
196
|
+
const clonedDefinition = typeof definition === 'object' ? cloneDeep(definition) : definition;
|
|
197
|
+
if (key === 'eventDefinitions') {
|
|
198
|
+
for (var i in clonedDefinition) {
|
|
199
|
+
if (definition[i].signalRef && !clonedDefinition[i].signalRef) {
|
|
200
|
+
clonedDefinition[i].set('signalRef', { ...definition[i].signalRef });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
clonedFlow.definition.set(key, clonedDefinition);
|
|
205
|
+
clonedFlow.definition.set('sourceRef', null);
|
|
206
|
+
clonedFlow.definition.set('targetRef', null);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
Node.eventDefinitionPropertiesToNotCopy.forEach(
|
|
210
|
+
prop => clonedFlow.definition.eventDefinitions &&
|
|
211
|
+
clonedFlow.definition.eventDefinitions[0] &&
|
|
212
|
+
clonedFlow.definition.eventDefinitions[0].hasOwnProperty(prop) &&
|
|
213
|
+
clonedFlow.definition.eventDefinitions[0].set(prop, null)
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
return clonedFlow;
|
|
217
|
+
}
|
|
218
|
+
|
|
115
219
|
getTargetProcess(processes, processNode) {
|
|
116
220
|
return this.pool
|
|
117
221
|
? processes.find(({ id }) => id === this.pool.component.node.definition.get('processRef').id)
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
</span>
|
|
102
102
|
</div>
|
|
103
103
|
<a
|
|
104
|
-
class="btn btn-sm btn-primary
|
|
104
|
+
class="btn btn-sm btn-primary autosave-btn text-uppercase mx-2"
|
|
105
105
|
data-test="publish-btn"
|
|
106
106
|
:title="$t('Publish')"
|
|
107
107
|
@click="$emit('saveBpmn')"
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
{{ $t('Publish') }}
|
|
110
110
|
</a>
|
|
111
111
|
<a
|
|
112
|
-
class="btn btn-sm btn-link toolbar-item
|
|
112
|
+
class="btn btn-sm btn-link toolbar-item autosave-btn text-black text-uppercase"
|
|
113
113
|
data-test="close-btn"
|
|
114
114
|
:title="$t('Close')"
|
|
115
115
|
@click="$emit('close')"
|
|
@@ -117,9 +117,11 @@
|
|
|
117
117
|
{{ $t('Close') }}
|
|
118
118
|
</a>
|
|
119
119
|
<EllipsisMenu
|
|
120
|
-
@navigate="onNavigate"
|
|
121
120
|
:actions="ellipsisMenuActions"
|
|
122
121
|
:divider="false"
|
|
122
|
+
@navigate="onNavigate"
|
|
123
|
+
@show="onShow"
|
|
124
|
+
@hide="onHide"
|
|
123
125
|
/>
|
|
124
126
|
</template>
|
|
125
127
|
<b-button
|
|
@@ -258,6 +260,18 @@ export default {
|
|
|
258
260
|
break;
|
|
259
261
|
}
|
|
260
262
|
},
|
|
263
|
+
onShow() {
|
|
264
|
+
const inspectorDiv = document.getElementById('inspector');
|
|
265
|
+
if (inspectorDiv) {
|
|
266
|
+
inspectorDiv.style.zIndex = '1';
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
onHide() {
|
|
270
|
+
const inspectorDiv = document.getElementById('inspector');
|
|
271
|
+
if (inspectorDiv) {
|
|
272
|
+
inspectorDiv.style.zIndex = '2';
|
|
273
|
+
}
|
|
274
|
+
},
|
|
261
275
|
},
|
|
262
276
|
};
|
|
263
277
|
</script>
|
|
@@ -27,3 +27,14 @@ $toolbar-background-color: #fff;
|
|
|
27
27
|
.cursor-default {
|
|
28
28
|
cursor: default !important;
|
|
29
29
|
}
|
|
30
|
+
|
|
31
|
+
.autosave-btn {
|
|
32
|
+
display: flex;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
align-items: center;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.btn-ellipsis {
|
|
38
|
+
border-top-left-radius: 4px !important;
|
|
39
|
+
border-bottom-left-radius: 4px !important;
|
|
40
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { id as laneId } from '../components/nodes/poolLane/config';
|
|
2
|
+
import { id as sequenceFlowId } from '../components/nodes/sequenceFlow';
|
|
3
|
+
import { id as associationId } from '../components/nodes/association';
|
|
4
|
+
import { id as messageFlowId } from '../components/nodes/messageFlow/config';
|
|
5
|
+
import { id as dataOutputAssociationFlowId } from '../components/nodes/dataOutputAssociation/config';
|
|
6
|
+
import { id as dataInputAssociationFlowId } from '../components/nodes/dataInputAssociation/config';
|
|
7
|
+
import { id as genericFlowId } from '../components/nodes/genericFlow/config';
|
|
8
|
+
import { getOrFindDataInput, findIOSpecificationOwner } from '../components/crown/utils';
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
methods: {
|
|
12
|
+
cloneSelection() {
|
|
13
|
+
let clonedNodes = [], clonedFlows = [], clonedDataInputAssociations = [], clonedDataOutputAssociations = [];
|
|
14
|
+
const nodes = this.highlightedNodes;
|
|
15
|
+
const selector = this.$refs.selector.$el;
|
|
16
|
+
const flowNodeTypes = [
|
|
17
|
+
sequenceFlowId,
|
|
18
|
+
laneId,
|
|
19
|
+
associationId,
|
|
20
|
+
messageFlowId,
|
|
21
|
+
genericFlowId,
|
|
22
|
+
];
|
|
23
|
+
const dataInputAssociationNodeTypes = [
|
|
24
|
+
dataInputAssociationFlowId,
|
|
25
|
+
];
|
|
26
|
+
const dataOutputAssociationNodeTypes = [
|
|
27
|
+
dataOutputAssociationFlowId,
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
if (typeof selector.getBoundingClientRect === 'function') {
|
|
31
|
+
nodes.forEach(node => {
|
|
32
|
+
if (flowNodeTypes.includes(node.type)) {
|
|
33
|
+
const clonedFlow = this.cloneFlowAndSetNewId(node);
|
|
34
|
+
clonedFlows.push(clonedFlow);
|
|
35
|
+
clonedNodes.push(clonedFlow);
|
|
36
|
+
} else if (dataInputAssociationNodeTypes.includes(node.type)) {
|
|
37
|
+
const clonedFlow = this.cloneFlowAndSetNewId(node);
|
|
38
|
+
clonedDataInputAssociations.push(clonedFlow);
|
|
39
|
+
clonedNodes.push(clonedFlow);
|
|
40
|
+
} else if (dataOutputAssociationNodeTypes.includes(node.type)) {
|
|
41
|
+
const clonedFlow = this.cloneFlowAndSetNewId(node);
|
|
42
|
+
clonedDataOutputAssociations.push(clonedFlow);
|
|
43
|
+
clonedNodes.push(clonedFlow);
|
|
44
|
+
} else {
|
|
45
|
+
const clonedElement = this.cloneElementAndCalculateOffset(node);
|
|
46
|
+
clonedNodes.push(clonedElement);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.connectClonedFlows(clonedFlows, clonedNodes);
|
|
52
|
+
this.connectClonedDataInputAssociations(clonedDataInputAssociations, clonedNodes);
|
|
53
|
+
this.connectClonedDataOutputAssociations(clonedDataOutputAssociations, clonedNodes);
|
|
54
|
+
|
|
55
|
+
return clonedNodes;
|
|
56
|
+
},
|
|
57
|
+
// Returns the Flow Element (Task| DataStore| DataObject) that is the target of the association
|
|
58
|
+
getDataInputOutputAssociationTargetRef(association) {
|
|
59
|
+
if (association.targetRef.$type === 'bpmn:DataInput') {
|
|
60
|
+
const ioSpec = association.targetRef.$parent;
|
|
61
|
+
return findIOSpecificationOwner(ioSpec, this);
|
|
62
|
+
}
|
|
63
|
+
if (association.targetRef.$type === 'bpmn:DataInputAssociation') {
|
|
64
|
+
const ioSpec = association.targetRef.$parent;
|
|
65
|
+
return findIOSpecificationOwner(ioSpec, this);
|
|
66
|
+
}
|
|
67
|
+
return association.targetRef;
|
|
68
|
+
},
|
|
69
|
+
cloneFlowAndSetNewId(node) {
|
|
70
|
+
const clonedFlow = node.cloneFlow(this.nodeRegistry, this.moddle, this.$t);
|
|
71
|
+
clonedFlow.setIds(this.nodeIdGenerator);
|
|
72
|
+
return clonedFlow;
|
|
73
|
+
},
|
|
74
|
+
cloneElementAndCalculateOffset(node) {
|
|
75
|
+
const clonedElement = node.clone(this.nodeRegistry, this.moddle, this.$t);
|
|
76
|
+
const { height: selectorHeight } = this.$refs.selector.$el.getBoundingClientRect();
|
|
77
|
+
const { sy } = this.paper.scale();
|
|
78
|
+
const yOffset = selectorHeight / sy;
|
|
79
|
+
clonedElement.diagram.bounds.y += yOffset;
|
|
80
|
+
clonedElement.setIds(this.nodeIdGenerator);
|
|
81
|
+
return clonedElement;
|
|
82
|
+
},
|
|
83
|
+
connectClonedFlows(clonedFlows, clonedNodes) {
|
|
84
|
+
clonedFlows.forEach(clonedFlow => {
|
|
85
|
+
const originalFlow = this.nodes.find(node => node.definition.id === clonedFlow.cloneOf);
|
|
86
|
+
const src = originalFlow.definition.sourceRef;
|
|
87
|
+
const target = originalFlow.definition.targetRef;
|
|
88
|
+
const srcClone = clonedNodes.find(node => node.cloneOf === src.id);
|
|
89
|
+
const targetClone = clonedNodes.find(node => node.cloneOf === target.id);
|
|
90
|
+
if (!srcClone || !targetClone) {
|
|
91
|
+
clonedNodes.splice(clonedNodes.indexOf(clonedFlow), 1);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
clonedFlow.definition.set('sourceRef', srcClone.definition);
|
|
95
|
+
clonedFlow.definition.set('targetRef', targetClone.definition);
|
|
96
|
+
|
|
97
|
+
if (srcClone.definition.outgoing) {
|
|
98
|
+
srcClone.definition.outgoing.push(clonedFlow.definition);
|
|
99
|
+
} else {
|
|
100
|
+
srcClone.definition.set('outgoing', [clonedFlow.definition]);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (targetClone.definition.incoming) {
|
|
104
|
+
targetClone.definition.incoming.push(clonedFlow.definition);
|
|
105
|
+
} else {
|
|
106
|
+
targetClone.definition.set('incoming', [clonedFlow.definition]);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
clonedFlow.diagram.waypoint.forEach(point => {
|
|
110
|
+
const { height: selectorHeight } = this.$refs.selector.$el.getBoundingClientRect();
|
|
111
|
+
point.y += selectorHeight;
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
connectClonedDataInputAssociations(clonedDataInputAssociations, clonedNodes) {
|
|
116
|
+
clonedDataInputAssociations.forEach(clonedAssociation => {
|
|
117
|
+
const originalAssociation = this.nodes.find(node => node.definition.id === clonedAssociation.cloneOf);
|
|
118
|
+
const src = originalAssociation.definition.sourceRef[0];
|
|
119
|
+
const srcClone = clonedNodes.find(node => node.cloneOf === src.id);
|
|
120
|
+
const originalTargetElement = this.getDataInputOutputAssociationTargetRef(originalAssociation.definition);
|
|
121
|
+
const clonedElement = clonedNodes.find(node => node.cloneOf === originalTargetElement.id);
|
|
122
|
+
const clonedDataInput = getOrFindDataInput(this.moddle, clonedElement, srcClone.definition);
|
|
123
|
+
|
|
124
|
+
clonedAssociation.definition.set('sourceRef', [srcClone.definition]);
|
|
125
|
+
clonedAssociation.definition.set('targetRef', clonedDataInput);
|
|
126
|
+
clonedElement.definition.set('dataInputAssociations', [clonedAssociation.definition]);
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
connectClonedDataOutputAssociations(clonedDataOutputAssociations, clonedNodes) {
|
|
130
|
+
clonedDataOutputAssociations.forEach(clonedAssociation => {
|
|
131
|
+
const originalAssociation = this.nodes.find(node => node.definition.id === clonedAssociation.cloneOf);
|
|
132
|
+
const src = originalAssociation.definition.sourceRef || originalAssociation.definition.$parent;
|
|
133
|
+
const target = originalAssociation.definition.targetRef;
|
|
134
|
+
const srcClone = clonedNodes.find(node => node.cloneOf === src.id);
|
|
135
|
+
const targetClone = clonedNodes.find(node => node.cloneOf === target.id);
|
|
136
|
+
|
|
137
|
+
clonedAssociation.definition.set('targetRef', targetClone.definition);
|
|
138
|
+
clonedAssociation.definition.set('sourceRef', srcClone.definition);
|
|
139
|
+
|
|
140
|
+
const existingOutputAssociations = srcClone.definition.get('dataOutputAssociations') || [];
|
|
141
|
+
srcClone.definition.set('dataOutputAssociations', [...existingOutputAssociations, clonedAssociation.definition]);
|
|
142
|
+
});
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
};
|
package/src/mixins/linkConfig.js
CHANGED
|
@@ -78,7 +78,7 @@ export default {
|
|
|
78
78
|
});
|
|
79
79
|
},
|
|
80
80
|
setEndpoint(shape, endpoint, connectionOffset) {
|
|
81
|
-
if (isPoint(shape)) {
|
|
81
|
+
if (shape && isPoint(shape)) {
|
|
82
82
|
return this.shape[endpoint](shape, {
|
|
83
83
|
anchor: {
|
|
84
84
|
name: 'modelCenter',
|
|
@@ -253,6 +253,9 @@ export default {
|
|
|
253
253
|
? this.getTargetRef()
|
|
254
254
|
: this.node.definition.get('targetRef');
|
|
255
255
|
|
|
256
|
+
// if flow doesn't have a targetRef such as incomplete node, return
|
|
257
|
+
if (!targetRef) return;
|
|
258
|
+
|
|
256
259
|
if (targetRef.id) {
|
|
257
260
|
const targetShape = this.graph.getElements().find(element => {
|
|
258
261
|
return element.component && element.component.node.definition === targetRef;
|