@processmaker/modeler 1.39.20 → 1.39.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@processmaker/modeler",
3
- "version": "1.39.20",
3
+ "version": "1.39.22",
4
4
  "scripts": {
5
5
  "serve": "vue-cli-service serve --mode development",
6
6
  "test:unit": "vue-cli-service test:unit",
@@ -90,6 +90,7 @@ export default {
90
90
 
91
91
  const node = new Node(nodeType, definition, diagram);
92
92
  node.pool = this.node.pool;
93
+ node.fromCrown = true;
93
94
 
94
95
  store.commit('highlightNode', node);
95
96
 
@@ -137,7 +137,7 @@ export default {
137
137
  store.commit('updateNodeProp', { node: this.node, key: 'color', value: color });
138
138
  Vue.set(this.node.definition, 'color', color);
139
139
  this.$emit('save-state');
140
-
140
+
141
141
  const properties = {
142
142
  id: this.node.definition.id,
143
143
  properties: {
@@ -148,6 +148,7 @@ export default {
148
148
  width: this.node.diagram.bounds.width,
149
149
  type: this.node.type,
150
150
  id: this.node.definition.id,
151
+ attachedToRefId: this.node.definition.get('attachedToRef')?.id,
151
152
  },
152
153
  };
153
154
  window.ProcessMaker.EventBus.$emit('multiplayer-updateNodes', [properties]);
@@ -952,7 +952,25 @@ export default {
952
952
  },
953
953
  async createNodeAsync(type, definition, diagram) {
954
954
  const node = this.createNode(type, definition, diagram);
955
+ if (!this.isMultiplayer) {
956
+ store.commit('addNode', node);
957
+ }
958
+ else {
959
+ this.loadNodeForMultiplayer(node);
960
+ }
961
+ },
962
+ async loadNodeForMultiplayer(node) {
963
+ if (node.type === 'processmaker-modeler-lane') {
964
+ await this.addNode(node, node.definition.id, true);
965
+ this.nodeIdGenerator.updateCounters();
966
+ await this.$nextTick();
967
+ await this.paperManager.awaitScheduledUpdates();
968
+ window.ProcessMaker.EventBus.$emit('multiplayer-addLanes', [node]);
969
+ return;
970
+ }
971
+ this.multiplayerHook(node, false);
955
972
  store.commit('addNode', node);
973
+ this.poolTarget = null;
956
974
  },
957
975
  createNode(type, definition, diagram) {
958
976
  if (Node.isTimerType(type)) {
@@ -1076,7 +1094,6 @@ export default {
1076
1094
  diagram.bounds.y = y;
1077
1095
 
1078
1096
  const newNode = this.createNode(control.type, definition, diagram);
1079
-
1080
1097
  if (newNode.isBpmnType('bpmn:BoundaryEvent')) {
1081
1098
  this.setShapeCenterUnderCursor(diagram);
1082
1099
  }
@@ -1112,16 +1129,20 @@ export default {
1112
1129
  const view = newNodeComponent.shapeView;
1113
1130
  await this.$refs.selector.selectElement(view);
1114
1131
  },
1115
- multiplayerHook(node, fromClient) {
1132
+ multiplayerHook(node, fromClient, isProcessRequested = false) {
1116
1133
  const blackList = [
1117
1134
  'processmaker-modeler-lane',
1118
1135
  'processmaker-modeler-generic-flow',
1119
1136
  'processmaker-modeler-sequence-flow',
1120
1137
  'processmaker-modeler-association',
1121
1138
  'processmaker-modeler-data-input-association',
1122
- 'processmaker-modeler-data-output-association',
1139
+ 'processmaker-modeler-data-input-association',
1140
+ 'processmaker-modeler-boundary-timer-event',
1141
+ 'processmaker-modeler-boundary-error-event',
1142
+ 'processmaker-modeler-boundary-signal-event',
1143
+ 'processmaker-modeler-boundary-conditional-even',
1144
+ 'processmaker-modeler-boundary-message-event',
1123
1145
  ];
1124
-
1125
1146
  if (!this.isMultiplayer) {
1126
1147
  return;
1127
1148
  }
@@ -1141,6 +1162,11 @@ export default {
1141
1162
  if (node?.pool?.component) {
1142
1163
  defaultData['poolId'] = node.pool.component.id;
1143
1164
  }
1165
+
1166
+ if (isProcessRequested) {
1167
+ return defaultData;
1168
+ }
1169
+
1144
1170
  window.ProcessMaker.EventBus.$emit('multiplayer-addNode', defaultData);
1145
1171
  }
1146
1172
  if (this.flowTypes.includes(node.type)) {
@@ -1149,17 +1175,23 @@ export default {
1149
1175
 
1150
1176
  if (node.type === 'processmaker-modeler-data-input-association') {
1151
1177
  sourceRefId = Array.isArray(node.definition.sourceRef) && node.definition.sourceRef[0]?.id;
1152
- targetRefId = node.definition.targetRef?.$parent?.$parent.get('id');
1178
+ targetRefId = node.definition.targetRef?.$parent?.$parent?.get('id');
1153
1179
  }
1154
1180
 
1155
1181
  if (sourceRefId && targetRefId) {
1156
- window.ProcessMaker.EventBus.$emit('multiplayer-addFlow', {
1182
+ const flowData = {
1157
1183
  id: node.definition.id,
1158
1184
  type: node.type,
1159
1185
  sourceRefId,
1160
1186
  targetRefId,
1161
1187
  waypoint: node.diagram.waypoint,
1162
- });
1188
+ };
1189
+
1190
+ if (isProcessRequested) {
1191
+ return flowData;
1192
+ }
1193
+
1194
+ window.ProcessMaker.EventBus.$emit('multiplayer-addFlow', flowData);
1163
1195
  }
1164
1196
  }
1165
1197
  }
@@ -1282,36 +1314,34 @@ export default {
1282
1314
  nodeThatWillBeReplaced: node,
1283
1315
  };
1284
1316
 
1285
- if (this.isMultiplayer) {
1286
- // Get all node types
1287
- const nodeTypes = nodeTypesStore.getters.getNodeTypes;
1288
- // Get the new control
1289
- const newControl = nodeTypes.flatMap(nodeType => {
1290
- return nodeType.items?.filter(item => item.type === typeToReplaceWith);
1291
- }).filter(Boolean);
1292
- // If the new control is found, emit event to server to replace node
1293
- if (newControl.length === 1) {
1294
- window.ProcessMaker.EventBus.$emit('multiplayer-replaceNode', { nodeData, newControl: newControl[0].type });
1295
- }
1296
- } else {
1297
- await this.replaceNodeProcedure(nodeData, true);
1298
- }
1317
+ await this.replaceNodeProcedure(nodeData);
1299
1318
  });
1300
1319
  });
1301
1320
  },
1302
1321
  async replaceNodeProcedure(data, isReplaced = false) {
1303
- if (isReplaced) {
1304
- // Get the clientX and clientY from the node that will be replaced
1305
- const { x: clientX, y: clientY } = this.paper.localToClientPoint(data.nodeThatWillBeReplaced.diagram.bounds);
1306
- data.clientX = clientX;
1307
- data.clientY = clientY;
1308
- }
1322
+ // Get the clientX and clientY from the node that will be replaced
1323
+ const { x: clientX, y: clientY } = this.paper.localToClientPoint(data.nodeThatWillBeReplaced.diagram.bounds);
1324
+ data.clientX = clientX;
1325
+ data.clientY = clientY;
1309
1326
 
1310
1327
  const newNode = await this.handleDrop(data);
1311
1328
 
1312
1329
  await this.removeNode(data.nodeThatWillBeReplaced, { removeRelationships: false, isReplaced });
1313
1330
  this.highlightNode(newNode);
1314
1331
  this.selectNewNode(newNode);
1332
+
1333
+ if (this.isMultiplayer && !isReplaced) {
1334
+ // Get all node types
1335
+ const nodeTypes = nodeTypesStore.getters.getNodeTypes;
1336
+ // Get the new control
1337
+ const newControl = nodeTypes.flatMap(nodeType => {
1338
+ return nodeType.items?.filter(item => item.type === data.typeToReplaceWith);
1339
+ }).filter(Boolean);
1340
+ // If the new control is found, emit event to server to replace node
1341
+ if (newControl.length === 1) {
1342
+ window.ProcessMaker.EventBus.$emit('multiplayer-replaceNode', { data, newControl: newControl[0].type });
1343
+ }
1344
+ }
1315
1345
  },
1316
1346
  replaceAiNode({ node, typeToReplaceWith, assetId, assetName, redirectTo }) {
1317
1347
  this.performSingleUndoRedoTransaction(async() => {
@@ -1728,6 +1758,7 @@ export default {
1728
1758
  try {
1729
1759
  const multiplayer = new Multiplayer(this);
1730
1760
  multiplayer.init();
1761
+ this.multiplayer = multiplayer;
1731
1762
  } catch (error) {
1732
1763
  console.warn('Could not initialize multiplayer', error);
1733
1764
  }
@@ -35,6 +35,12 @@ import { id as associationId } from '@/components/nodes/association/associationC
35
35
  import { id as messageFlowId } from '@/components/nodes/messageFlow/config';
36
36
  import { id as dataOutputAssociationFlowId } from '@/components/nodes/dataOutputAssociation/config';
37
37
  import { id as dataInputAssociationFlowId } from '@/components/nodes/dataInputAssociation/config';
38
+ import { id as boundaryErrorEventId } from '@/components/nodes/boundaryErrorEvent';
39
+ import { id as boundaryConditionalEventId } from '@/components/nodes/boundaryConditionalEvent';
40
+ import { id as boundaryEscalationEventId } from '@/components/nodes/boundaryEscalationEvent';
41
+ import { id as boundaryMessageEventId } from '@/components/nodes/boundaryMessageEvent';
42
+ import { id as boundarySignalEventId } from '@/components/nodes/boundarySignalEvent';
43
+ import { id as boundaryTimerEventId } from '@/components/nodes/boundaryTimerEvent';
38
44
  import { labelWidth, poolPadding } from '../nodes/pool/poolSizes';
39
45
  import { invalidNodeColor, poolColor } from '@/components/nodeColors';
40
46
 
@@ -587,7 +593,6 @@ export default {
587
593
  const shapesToNotTranslate = [
588
594
  'PoolLane',
589
595
  'standard.Link',
590
- 'processmaker.components.nodes.boundaryEvent.Shape',
591
596
  ];
592
597
 
593
598
  shapes.filter(shape => !shapesToNotTranslate.includes(shape.model.get('type')))
@@ -604,6 +609,7 @@ export default {
604
609
  y: shape.model.get('position').y,
605
610
  height: shape.model.get('size').height,
606
611
  width: shape.model.get('size').width,
612
+ attachedToRefId: shape.model.component.node.definition.get('attachedToRef')?.id ?? null,
607
613
  color: shape.model.get('color'),
608
614
  },
609
615
  };
@@ -612,9 +618,43 @@ export default {
612
618
  }
613
619
  changed.push(defaultData);
614
620
  }
621
+ const boundariesChanges = this.getBoundariesChangesForShape(shape);
622
+ changed = changed.concat(boundariesChanges);
615
623
  });
624
+
616
625
  return changed;
617
626
  },
627
+ /**
628
+ * Get properties for each boundary inside a shape
629
+ */
630
+ getBoundariesChangesForShape(shape) {
631
+ let boundariesChanged = [];
632
+ const boundaryEventTypes = [
633
+ boundaryErrorEventId,
634
+ boundaryConditionalEventId,
635
+ boundaryEscalationEventId,
636
+ boundaryMessageEventId,
637
+ boundarySignalEventId,
638
+ boundaryTimerEventId,
639
+ ];
640
+ const boundaryNodes = store.getters.nodes.filter(node => boundaryEventTypes.includes(node.type));
641
+ boundaryNodes.forEach(boundaryNode => {
642
+ if (boundaryNode.definition.attachedToRef.id === shape.model.component.node.definition.id) {
643
+ boundariesChanged.push({
644
+ id: boundaryNode.definition.id,
645
+ properties: {
646
+ x: boundaryNode.diagram.bounds.x,
647
+ y: boundaryNode.diagram.bounds.y,
648
+ height: boundaryNode.diagram.bounds.height,
649
+ width: boundaryNode.diagram.bounds.width,
650
+ attachedToRefId: boundaryNode.definition.get('attachedToRef')?.id ?? null,
651
+ color: boundaryNode.definition.get('color') ?? null,
652
+ },
653
+ });
654
+ }
655
+ });
656
+ return boundariesChanged;
657
+ },
618
658
  getContainerProperties(children) {
619
659
  const changed = [];
620
660
  children.forEach(model => {
@@ -202,6 +202,26 @@ export default {
202
202
 
203
203
  this.invalidTargetElement = targetElement;
204
204
  },
205
+ addMultiplayerBoundaryEvent() {
206
+ const control = {
207
+ bpmnType: this.node.diagram.$type,
208
+ id: this.node.diagram.id,
209
+ type: this.node.type,
210
+ attachedToRef: this.node.definition.get('attachedToRef'),
211
+ };
212
+
213
+ window.ProcessMaker.EventBus.$emit('multiplayer-addBoundaryEvent', {
214
+ x: this.node.diagram.bounds.x,
215
+ y: this.node.diagram.bounds.y,
216
+ height: this.node.diagram.bounds.height,
217
+ width: this.node.diagram.bounds.width,
218
+ attachedToRefId: this.node.definition.get('attachedToRef')?.id,
219
+ control,
220
+ type: this.node.type,
221
+ id: this.node.definition.id,
222
+ color: this.node.definition.get('color'),
223
+ });
224
+ },
205
225
  },
206
226
  async mounted() {
207
227
  this.shape = new EventShape();
@@ -214,6 +234,10 @@ export default {
214
234
  const task = this.getTaskUnderShape();
215
235
  this.attachBoundaryEventToTask(task);
216
236
  this.updateShapePosition(task);
237
+
238
+ if (this.node.fromCrown) {
239
+ this.addMultiplayerBoundaryEvent();
240
+ }
217
241
  },
218
242
  };
219
243
  </script>
@@ -66,6 +66,26 @@ export default class Multiplayer {
66
66
  this.modeler.enableMultiplayer(payload.isMultiplayer);
67
67
  });
68
68
 
69
+ this.clientIO.on('requestProcess', (payload) => {
70
+ const { firstClient, clientId } = payload;
71
+
72
+ // Check if the current client is the first client
73
+ if (firstClient.id === this.clientIO.id) {
74
+ // Get the process definition
75
+ const nodes = this.modeler.nodes.map((node) => this.modeler.multiplayerHook(node, false, true));
76
+
77
+ nodes.forEach((node) => {
78
+ const yMapNested = new Y.Map();
79
+ this.doTransact(yMapNested, node);
80
+ this.yArray.push([yMapNested]);
81
+ // Encode the state as an update and send it to the server
82
+ const stateUpdate = Y.encodeStateAsUpdate(this.yDoc);
83
+ // Send the update to the web socket server
84
+ this.clientIO.emit('createElement', { updateDoc: stateUpdate, clientId });
85
+ });
86
+ }
87
+ });
88
+
69
89
  // Listen for updates when a new element is added
70
90
  this.clientIO.on('createElement', async(payload) => {
71
91
  // Create the new element in the process
@@ -74,6 +94,16 @@ export default class Multiplayer {
74
94
  Y.applyUpdate(this.yDoc, new Uint8Array(payload.updateDoc));
75
95
  });
76
96
 
97
+ // Listen for updates when a new element is requested
98
+ this.clientIO.on('createRequestedElement', async(payload) => {
99
+ if (payload.clientId === this.clientIO.id) {
100
+ // Create the new element in the process
101
+ await this.createRemoteShape(payload.changes);
102
+ // Add the new element to the shared array
103
+ Y.applyUpdate(this.yDoc, new Uint8Array(payload.updateDoc));
104
+ }
105
+ });
106
+
77
107
  // Listen for updates when an element is removed
78
108
  this.clientIO.on('removeElement', (payload) => {
79
109
  payload.deletedNodes.forEach(nodeId => {
@@ -120,7 +150,11 @@ export default class Multiplayer {
120
150
  });
121
151
 
122
152
  window.ProcessMaker.EventBus.$on('multiplayer-addFlow', ( data ) => {
123
- this.addFlow(data);
153
+ this.addCommonElement(data);
154
+ });
155
+
156
+ window.ProcessMaker.EventBus.$on('multiplayer-addBoundaryEvent', ( data ) => {
157
+ this.addCommonElement(data);
124
158
  });
125
159
 
126
160
  window.ProcessMaker.EventBus.$on('multiplayer-addLanes', ( lanes ) => {
@@ -135,7 +169,7 @@ export default class Multiplayer {
135
169
  // Encode the state as an update and send it to the server
136
170
  const stateUpdate = Y.encodeStateAsUpdate(this.yDoc);
137
171
  // Send the update to the web socket server
138
- this.clientIO.emit('createElement', stateUpdate);
172
+ this.clientIO.emit('createElement', { updateDoc: stateUpdate });
139
173
  }
140
174
  createShape(value){
141
175
  if (this.modeler.nodeRegistry[value.type] && this.modeler.nodeRegistry[value.type].multiplayerClient) {
@@ -216,7 +250,6 @@ export default class Multiplayer {
216
250
 
217
251
  // Encode the state as an update and send it to the server
218
252
  const stateUpdate = Y.encodeStateAsUpdate(this.yDoc);
219
-
220
253
  this.clientIO.emit('updateElement', { updateDoc: stateUpdate, isReplaced: true });
221
254
  }
222
255
  replaceShape(updatedNode) {
@@ -297,6 +330,11 @@ export default class Multiplayer {
297
330
  const node = this.getNodeById(data.id);
298
331
  store.commit('updateNodeProp', { node, key: 'color', value: data.color });
299
332
 
333
+ // boundary type
334
+ if (element.component.node.definition.$type === 'bpmn:BoundaryEvent') {
335
+ this.attachBoundaryEventToNode(element, data);
336
+ }
337
+
300
338
  // Trigger a rendering of the element on the paper
301
339
  await paper.findViewByModel(element).update();
302
340
  // validate if the parent pool was updated
@@ -307,18 +345,36 @@ export default class Multiplayer {
307
345
  }
308
346
  }
309
347
  }
348
+ attachBoundaryEventToNode(element, data) {
349
+ const node = this.getNodeById(data.attachedToRefId);
350
+
351
+ // Find previous attached task
352
+ const previousAttachedTask = element.getParentCell();
353
+
354
+ // Find new attached task
355
+ const newAttachedTask = this.modeler.getElementByNodeId(data.attachedToRefId);
356
+
357
+ if (previousAttachedTask) {
358
+ previousAttachedTask.unembed(element);
359
+ }
360
+
361
+ if (newAttachedTask) {
362
+ newAttachedTask.embed(element);
363
+ }
310
364
 
311
- addFlow(data) {
365
+ element.component.node.definition.set('attachedToRef', node.definition);
366
+ }
367
+ addCommonElement(data) {
368
+ // Add a new flow / boundary event to the shared array
312
369
  const yMapNested = new Y.Map();
313
370
  this.doTransact(yMapNested, data);
314
371
  this.yArray.push([yMapNested]);
315
372
  // Encode the state as an update and send it to the server
316
373
  const stateUpdate = Y.encodeStateAsUpdate(this.yDoc);
317
374
  // Send the update to the web socket server
318
- this.clientIO.emit('createElement', stateUpdate);
375
+ this.clientIO.emit('createElement', { updateDoc: stateUpdate });
319
376
  this.#nodeIdGenerator.updateCounters();
320
377
  }
321
-
322
378
  addLaneNodes(lanes) {
323
379
  const pool = this.getPool(lanes);
324
380
  window.ProcessMaker.EventBus.$emit('multiplayer-updateNodes', [{
@@ -338,7 +394,7 @@ export default class Multiplayer {
338
394
  this.doTransact(yMapNested, data);
339
395
  this.yArray.push([yMapNested]);
340
396
  const stateUpdate = Y.encodeStateAsUpdate(this.yDoc);
341
- this.clientIO.emit('createElement', stateUpdate);
397
+ this.clientIO.emit('createElement', { updateDoc: stateUpdate });
342
398
  });
343
399
  });
344
400
  }