@evenicanpm/admin-integrate 1.3.0 → 1.6.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.
Files changed (79) hide show
  1. package/documents/Endpoint/list.ts +8 -0
  2. package/documents/Process/get-process-details.ts +0 -1
  3. package/documents/ProcessConfig/fragments.ts +1 -1
  4. package/documents/ProcessExport/read.ts +108 -0
  5. package/documents/ProcessTask/fragments.ts +4 -1
  6. package/documents/ProcessTemplate/fragments.ts +6 -1
  7. package/package.json +2 -2
  8. package/src/api/configuration/queries/configuration-export.query.ts +48 -0
  9. package/src/api/configuration/queries/configuration-export.server.ts +9 -0
  10. package/src/api/configuration/queries/index.ts +1 -0
  11. package/src/api/process/mutations/copy-process.mutation.ts +2 -5
  12. package/src/api/process-config/mutation/process-config-import.mutation.ts +9 -0
  13. package/src/api/process-task/queries/get-process-task-by-id.query.ts +1 -0
  14. package/src/api/scheduler/mutation/create-process-schedule-group-details.mutation.ts +2 -2
  15. package/src/api/scheduler/mutation/update-process-schedule-group-details.mutation.ts +2 -2
  16. package/src/api/templates/queries/template-input-search.query.ts +5 -0
  17. package/src/api/templates/queries/template-input-search.server.ts +8 -1
  18. package/src/api/templates/queries/types.ts +9 -3
  19. package/src/components/breadcrumbs/breadcrumbs.tsx +1 -1
  20. package/src/components/core/date-time-popover.tsx +1 -1
  21. package/src/components/core/drawer-buttons.tsx +1 -1
  22. package/src/components/core/edited-typography.tsx +1 -1
  23. package/src/components/core/title-edit.tsx +13 -11
  24. package/src/components/dashboard-list/dashboard-list.tsx +1 -1
  25. package/src/components/data-table/table-header.tsx +1 -1
  26. package/src/components/data-table/table-skeleton.tsx +1 -1
  27. package/src/components/execution-history-drawer/execution-history-drawer.tsx +1 -2
  28. package/src/components/header/integration-details-header.tsx +4 -0
  29. package/src/components/integration-list/list/integration-list-row.tsx +2 -2
  30. package/src/components/integration-list/list/integration-list-table.tsx +3 -3
  31. package/src/components/integration-list/list/integration-list.tsx +3 -3
  32. package/src/components/integration-view/edges/default-edge.tsx +1 -5
  33. package/src/components/integration-view/flow-types.tsx +2 -0
  34. package/src/components/integration-view/integration-view.tsx +148 -577
  35. package/src/components/integration-view/nodes/add-node.tsx +20 -0
  36. package/src/components/integration-view/nodes/group-node.tsx +15 -1
  37. package/src/components/integration-view/nodes/task-node.tsx +38 -10
  38. package/src/components/integration-view/temp-data/initialElements.tsx +0 -2
  39. package/src/components/integration-view/utils/mapping.ts +404 -0
  40. package/src/components/layouts/main-layout.tsx +1 -1
  41. package/src/components/layouts/root-container.tsx +2 -5
  42. package/src/components/link-cards/link-card.tsx +1 -1
  43. package/src/components/list-filter/date-filter.tsx +3 -1
  44. package/src/components/list-filter/date-range-filter.tsx +4 -2
  45. package/src/components/list-filter/list-filter.tsx +1 -1
  46. package/src/components/list-filter/select-filter.tsx +10 -4
  47. package/src/components/scheduler/schedule-drawer/schedule-details-integrations.tsx +6 -8
  48. package/src/components/scheduler/schedule-drawer/schedule-details-main.tsx +1 -1
  49. package/src/components/scheduler/schedule-drawer/schedule-details-name.tsx +1 -1
  50. package/src/components/scheduler/schedule-drawer/schedule-details.tsx +1 -1
  51. package/src/components/scheduler/schedule-drawer/schedule-drawer-group.tsx +4 -8
  52. package/src/components/scheduler/schedule-drawer/schedule-drawer-legacy.tsx +1 -1
  53. package/src/components/scheduler/schedule-drawer/schedule-drawer.tsx +2 -2
  54. package/src/components/scheduler/schedule-drawer/sortable-integration-row.tsx +1 -1
  55. package/src/components/templates/inputs/index.tsx +162 -121
  56. package/src/components/templates/templates-list/templates-list-table.tsx +2 -2
  57. package/src/components/templates/templates-list/templates-list.tsx +1 -1
  58. package/src/components/templates/types.tsx +1 -0
  59. package/src/components/templates/wizard.tsx +98 -50
  60. package/src/pages/dashboard/dashboard-list-sections.tsx +2 -2
  61. package/src/pages/execution-details/execution-details.tsx +4 -3
  62. package/src/pages/execution-details/task-execution-details.tsx +1 -1
  63. package/src/pages/execution-details/task-execution-drawer.tsx +1 -1
  64. package/src/pages/executions/executions-list/executions-list-table.tsx +1 -1
  65. package/src/pages/integration-create/integration-create.tsx +87 -45
  66. package/src/pages/integration-create/pre-creation-step.tsx +77 -5
  67. package/src/pages/integration-create/select-step.tsx +1 -1
  68. package/src/pages/integration-create/wizard-step.tsx +2 -1
  69. package/src/pages/integration-details/import-process/copy-tasks-list.tsx +2 -2
  70. package/src/pages/integration-details/import-process/copy-tasks-row.tsx +1 -1
  71. package/src/pages/integration-details/import-process/import-confirm.tsx +1 -1
  72. package/src/pages/integration-details/import-process/import-drawer.tsx +1 -1
  73. package/src/pages/integration-details/import-process/import-process.tsx +1 -1
  74. package/src/pages/integration-details/integration-details.tsx +290 -43
  75. package/src/pages/integration-details/task-drawer/add-task.tsx +65 -13
  76. package/src/pages/integration-details/task-drawer/edit-task.tsx +69 -83
  77. package/src/pages/integration-details/task-drawer/task-drawer.tsx +22 -4
  78. package/src/pages/integration-details/task-drawer/task-reducer.ts +32 -2
  79. package/src/pages/scheduler/schedules-list/schedules-list-table.tsx +1 -1
@@ -15,50 +15,34 @@ import "@xyflow/react/dist/style.css";
15
15
  import {
16
16
  Background,
17
17
  Controls,
18
- type InternalNode,
19
18
  type Node,
20
19
  ReactFlow,
21
20
  ReactFlowProvider,
22
21
  useEdgesState,
23
22
  useNodesState,
24
23
  useReactFlow,
25
- useStoreApi,
26
24
  } from "@xyflow/react";
27
25
  import type {
28
- Process,
26
+ ConfigExport,
29
27
  ProcessExecutionDetails,
30
28
  ProcessTask,
31
29
  ProcessTaskExecution,
30
+ ProcessTaskExport,
32
31
  } from "../../../../admin-core/src/api/e4/graphqlRequestSdk";
33
32
  import { layoutOptions as elkOptions } from "./elk-layout-options";
34
- import type {
35
- ElkExtendedEdgeWithFlow,
36
- ElkNodeWithFlow,
37
- GroupNode,
38
- ProcessTaskExecutionNode,
39
- ProcessTaskNode,
40
- } from "./elk-types";
41
-
42
- // import {
43
- // exportIcon,
44
- // inputIcon,
45
- // markerEnd,
46
- // pullIcon,
47
- // pushIcon,
48
- // storageIcon,
49
- // } from "./icons";
50
-
51
- import { MarkerType } from "@xyflow/react";
33
+ import type { ElkExtendedEdgeWithFlow, ElkNodeWithFlow } from "./elk-types";
34
+
52
35
  import _ from "lodash";
53
36
  import { edgeTypes, nodeTypes } from "./flow-types";
54
37
 
55
- const elk = new ELK();
38
+ import {
39
+ mapToCamelCase,
40
+ mapEmptyNodesAndEdges,
41
+ mapProcessConfigToNodesAndEdges,
42
+ mapProcessTasksToNodesAndEdges,
43
+ } from "./utils/mapping";
56
44
 
57
- const markerEnd = {
58
- type: MarkerType.ArrowClosed,
59
- width: 20,
60
- height: 20,
61
- };
45
+ const elk = new ELK();
62
46
 
63
47
  const calculateMaxWidth = (
64
48
  processTasks: ProcessTask[] | ProcessTaskExecution[],
@@ -148,305 +132,29 @@ const calcYOffset = () => {
148
132
  interface Props {
149
133
  title?: string; // e.g. Executions
150
134
  section?: string; // e.g. e4Integrate
151
- data?: Process | ProcessExecutionDetails;
135
+ data?: ProcessExecutionDetails;
136
+ config?: ConfigExport;
152
137
  variant?: "process" | "process-execution";
153
138
  onTaskClick?:
154
139
  | ((id: string) => void)
155
140
  | ((processTaskExecution: ProcessTaskExecution) => void);
156
141
  drawerOpen?: boolean;
157
142
  processTaskId?: string;
143
+ onConfigChange?: (processConfig: ConfigExport) => void;
144
+ onAdd?: Function;
145
+ canEdit?: boolean;
158
146
  }
159
147
 
160
- const mapEmptyNodesAndEdges = (
161
- data: Process | ProcessExecutionDetails,
162
- nodeWidth: number,
163
- ) => {
164
- const nodes: ElkNodeWithFlow[] = [];
165
- const edges: ElkExtendedEdgeWithFlow[] = [];
166
-
167
- const entryPoint: ElkNodeWithFlow = {
168
- id: "entry-point",
169
- type: "entry-node",
170
- data: {
171
- isScheduled: false,
172
- isTriggered: false,
173
- },
174
- width: nodeWidth,
175
- height:
176
- (data as Process)?.isScheduled && (data as Process)?.isTriggered
177
- ? 104
178
- : 70,
179
- position: { x: 0, y: 0 },
180
- layoutOptions: {
181
- "org.eclipse.elk.priority": "1",
182
- },
183
- };
184
-
185
- nodes.push(entryPoint);
186
-
187
- const entryPointConnector: ElkNodeWithFlow = {
188
- id: "entry-point-connector",
189
- position: { x: 0, y: 0 },
190
- type: "connection-node",
191
- width: 1,
192
- height: 1,
193
- //extent: "parent",
194
- };
195
-
196
- nodes.push(entryPointConnector);
197
-
198
- const groupId = `group-1`;
199
-
200
- const emptyNode = {
201
- id: groupId,
202
- data: {
203
- label: `Group 1`,
204
- },
205
- position: { x: 0, y: 0 },
206
- type: "empty-node",
207
- children: [],
208
- layoutOptions: {
209
- "org.eclipse.elk.priority": groupId,
210
- },
211
- draggable: false,
212
- width: nodeWidth,
213
- height: 100,
214
- };
215
-
216
- nodes.push(emptyNode);
217
-
218
- edges.push({
219
- id: `entry-point-entry-point-connector`,
220
- sources: ["entry-point"],
221
- targets: ["entry-point-connector"],
222
- type: "default-edge",
223
- });
224
-
225
- edges.push({
226
- id: `entry-point-connector-${groupId}`,
227
- sources: ["entry-point-connector"],
228
- targets: [groupId],
229
- type: "default-edge",
230
- markerEnd: markerEnd,
231
- });
232
-
233
- return {
234
- nodes,
235
- edges,
236
- };
237
- };
238
-
239
- const mapProcessTasksToNodesAndEdges = (
240
- data: Process | ProcessExecutionDetails,
241
- nodeWidth: number,
242
- variant: "process" | "process-execution",
243
- ) => {
244
- const entryPoint: ElkNodeWithFlow = {
245
- id: "entry-point",
246
- type: "entry-node",
247
- data: {
248
- isScheduled:
249
- variant === "process" ? !!(data as Process)?.isScheduled : false,
250
- isTriggered:
251
- variant === "process" ? !!(data as Process)?.isTriggered : false,
252
- },
253
- width: nodeWidth,
254
- height:
255
- (data as Process)?.isScheduled && (data as Process)?.isTriggered
256
- ? 104
257
- : 70,
258
- position: { x: 0, y: 0 },
259
- layoutOptions: {
260
- "org.eclipse.elk.priority": "1",
261
- },
262
- };
263
-
264
- const entryPointConnector: ElkNodeWithFlow = {
265
- id: "entry-point-connector",
266
- position: { x: 0, y: 0 },
267
- type: "connection-node",
268
- width: 1,
269
- height: 1,
270
- //extent: "parent",
271
- };
272
-
273
- let groupLabels: number[];
274
-
275
- if (variant === "process") {
276
- groupLabels = _.uniq(
277
- _.map((data as Process)?.processTasks, "parallelProcessingGroup"),
278
- );
279
- } else {
280
- groupLabels = _.uniq(
281
- _.map(
282
- (data as ProcessExecutionDetails)?.processTaskExecutions,
283
- "parallelProcessingGroup",
284
- ),
285
- );
286
- }
287
-
288
- groupLabels = _.sortBy(groupLabels);
289
-
290
- const groups: GroupNode[] = groupLabels.map((groupLabel) => ({
291
- id: `group-${groupLabel}`,
292
- data: {
293
- label: `Group ${groupLabel}`,
294
- variant: variant,
295
- parallelProcessingGroup: groupLabel,
296
- },
297
- position: { x: 0, y: 0 },
298
- type: "group-node",
299
- children: [],
300
- layoutOptions: {
301
- "org.eclipse.elk.priority": `${groupLabel}`,
302
- },
303
- draggable: false,
304
- }));
305
-
306
- const edges = [];
307
-
308
- edges.push({
309
- id: `entry-point-entry-point-connector`,
310
- sources: ["entry-point"],
311
- targets: ["entry-point-connector"],
312
- type: "default-edge",
313
- });
314
-
315
- groups.forEach((group) => {
316
- edges.push({
317
- id: `entry-point-connector-${group.id}`,
318
- sources: ["entry-point-connector"],
319
- targets: [group.id],
320
- type: "default-edge",
321
- markerEnd: markerEnd,
322
- });
323
-
324
- const groupTasks = _.sortBy(
325
- (variant === "process"
326
- ? (data as Process)?.processTasks
327
- : (data as ProcessExecutionDetails)?.processTaskExecutions
328
- )?.filter(
329
- (task) =>
330
- task?.parallelProcessingGroup?.toString() === group.id.split("-")[1],
331
- ),
332
- ["sort", "name"],
333
- );
334
-
335
- var tasksPartitioned = _.values(_.groupBy(groupTasks, "sort"));
336
-
337
- const groupNodes: (
338
- | ProcessTaskNode
339
- | ProcessTaskExecutionNode
340
- | ElkNodeWithFlow
341
- )[] = [];
342
-
343
- tasksPartitioned.forEach((partition) => {
344
- partition.forEach((task, index) => {
345
- groupNodes.push({
346
- id: `task-${task?.id}`,
347
- data: {
348
- processTask:
349
- variant === "process" ? (task as ProcessTask) : undefined,
350
- processTaskExecution:
351
- variant === "process-execution"
352
- ? (task as ProcessTaskExecution)
353
- : undefined,
354
- //label: task?.name as string,
355
- /*icon: mapIntegrationIconByCode(
356
- task?.orchestrationType?.code as string,
357
- ),*/
358
- isLast: index === partition.length - 1,
359
- //executionStatus: variant === 'process' ? undefined : (task as ProcessTaskExecution)?.executionStatus.id,
360
- },
361
- position: { x: 0, y: 0 },
362
- type: variant === "process" ? "task-node" : "execution-task-node",
363
- width: nodeWidth + (index === partition.length - 1 ? 32 : 0), //hard coded for now
364
- height: 70, // hard coded for now
365
- //extent: "parent",
366
- parentId: group.id,
367
- //sort: task?.sort as number | undefined,
368
- });
369
- });
370
- });
371
-
372
- let prevConnectorId: string | null = null;
373
-
374
- tasksPartitioned.forEach((partition, tpIndex) => {
375
- _.sortBy(partition, [(task) => task?.name]);
376
-
377
- if (prevConnectorId) {
378
- partition.forEach((task) => {
379
- edges.push({
380
- id: `${prevConnectorId}-${task?.id}`,
381
- sources: [prevConnectorId],
382
- targets: [`task-${task?.id}`],
383
- type: "default-edge",
384
- markerEnd: markerEnd,
385
- });
386
- });
387
- }
388
-
389
- const connectorId = `group-${group.id}-connect-${tpIndex}`;
390
-
391
- prevConnectorId = connectorId;
392
-
393
- if (tpIndex !== tasksPartitioned.length - 1) {
394
- partition.forEach((task) => {
395
- edges.push({
396
- id: `task-${task?.id}-${connectorId}`,
397
- sources: [`task-${task?.id}`],
398
- targets: [connectorId],
399
- type: "default-edge",
400
- });
401
- });
402
- }
403
- if (prevConnectorId && tpIndex !== tasksPartitioned.length - 1) {
404
- groupNodes.push({
405
- id: prevConnectorId,
406
- position: { x: 0, y: 0 },
407
- type: "connection-node",
408
- width: 1,
409
- height: 1,
410
- extent: "parent",
411
- parentId: group.id,
412
- });
413
- }
414
- });
415
-
416
- // groupTasks.map((task) => ({
417
- // id: `task-${task.id}`,
418
- // data: {
419
- // label: task.name,
420
- // //icon: pullIcon(),
421
- // isLast: true,
422
- // },
423
- // position: { x: 0, y: 0 },
424
- // type: "task-node",
425
- // width: 450, //hard coded for now
426
- // height: 70, //hard coded for now
427
- // extent: "parent",
428
- // parentId: group.id,
429
- // sort: task.sort,
430
- // }));
431
-
432
- group.children = groupNodes;
433
- });
434
-
435
- return { nodes: [entryPoint, entryPointConnector, ...groups], edges };
436
- };
437
-
438
148
  function getOverlapY(rect1: any, rect2: any) {
439
149
  // Calculate intersection coordinates
440
150
  //const intersectX1 = Math.max(rect1.x, rect2.x);
441
151
  const intersectY1 = Math.max(rect1.y, rect2.y);
442
- //const intersectX2 = Math.min(rect1.x + rect1.width, rect2.x + rect2.width);
443
152
  const intersectY2 = Math.min(rect1.y + rect1.height, rect2.y + rect2.height);
444
153
 
445
154
  // Check for overlap and calculate area
446
155
  if (/*intersectX1 >= intersectX2 ||*/ intersectY1 >= intersectY2) {
447
156
  return 0; // No overlap
448
157
  } else {
449
- //const overlapWidth = intersectX2 - intersectX1;
450
158
  const overlapHeight = intersectY2 - intersectY1;
451
159
  return /*overlapWidth **/ overlapHeight;
452
160
  }
@@ -456,29 +164,32 @@ function getOverlapX(rect1: any, rect2: any) {
456
164
  // Calculate intersection coordinates
457
165
  //const intersectX1 = Math.max(rect1.x, rect2.x);
458
166
  const intersectX1 = Math.max(rect1.x, rect2.x);
459
- //const intersectX2 = Math.min(rect1.x + rect1.width, rect2.x + rect2.width);
460
167
  const intersectX2 = Math.min(rect1.x + rect1.width, rect2.x + rect2.width);
461
168
 
462
169
  // Check for overlap and calculate area
463
170
  if (intersectX1 >= intersectX2) {
464
171
  return 0; // No overlap
465
172
  } else {
466
- //const overlapWidth = intersectX2 - intersectX1;
467
173
  const overlapHeight = intersectX2 - intersectX1;
468
174
  return /*overlapWidth **/ overlapHeight;
469
175
  }
470
176
  }
471
177
 
472
178
  const IntegrationView: React.FC<Props> = ({
473
- data: processInput,
179
+ data: processExecutionInput,
474
180
  variant,
475
181
  onTaskClick,
476
182
  drawerOpen,
477
183
  processTaskId: selectedProcessTaskId,
184
+ config: configInput,
185
+ onConfigChange,
186
+ onAdd,
187
+ canEdit,
478
188
  }: Props) => {
479
- const [process, setProcess] = useState<
480
- Process | ProcessExecutionDetails | undefined
481
- >(processInput);
189
+ const [processExecutionDetails, _setProcess] = useState<
190
+ ProcessExecutionDetails | undefined
191
+ >(processExecutionInput);
192
+
482
193
  const [nodes, setNodes, onNodesChange] = useNodesState<any>([]);
483
194
  const [edges, setEdges, onEdgesChange] = useEdgesState<any>([]);
484
195
  const [zonesY, setZonesY] = useEdgesState<any>([]);
@@ -489,24 +200,38 @@ const IntegrationView: React.FC<Props> = ({
489
200
  const onConnect = useCallback(() => {}, []);
490
201
  const onLayout = useCallback(
491
202
  (processInput: any) => {
492
- const tasks = (process as Process)?.processTasks;
203
+ let tasks;
204
+
205
+ if (variant == "process") {
206
+ tasks = processInput?.Processes[0]?.ProcessTasks?.map(
207
+ (processTask: ProcessTaskExport) => mapToCamelCase(processTask),
208
+ );
209
+ } else {
210
+ tasks = (processInput ?? processExecutionDetails)
211
+ ?.processTaskExecutions;
212
+ }
213
+
493
214
  if (
494
215
  (tasks && tasks.length > 0) ||
495
216
  (processInput && processInput?.processTasks?.length > 0)
496
217
  ) {
497
218
  const width = calculateMaxWidth(
498
- variant === "process"
499
- ? ((processInput ?? (process as Process))
500
- ?.processTasks as ProcessTask[])
501
- : ((processInput ?? (process as ProcessExecutionDetails))
502
- ?.processTaskExecutions as ProcessTaskExecution[]),
219
+ tasks as ProcessTask[] | ProcessTaskExecution[],
503
220
  );
504
221
 
505
- const mapped = mapProcessTasksToNodesAndEdges(
506
- processInput ?? process,
507
- width,
508
- variant as "process" | "process-execution",
509
- );
222
+ const mapped =
223
+ variant == "process"
224
+ ? mapProcessConfigToNodesAndEdges(
225
+ processInput,
226
+ width,
227
+ variant,
228
+ onAdd,
229
+ )
230
+ : mapProcessTasksToNodesAndEdges(
231
+ processInput ?? process,
232
+ width,
233
+ variant as "process" | "process-execution",
234
+ );
510
235
 
511
236
  const opts = { ...elkOptions };
512
237
  const ns = mapped.nodes;
@@ -517,7 +242,7 @@ const IntegrationView: React.FC<Props> = ({
517
242
  setNodes(layoutedNodes);
518
243
  setEdges(layoutedEdges);
519
244
 
520
- var zonesY = _.uniqBy(
245
+ const zonesY = _.uniqBy(
521
246
  layoutedNodes.filter((n: any) => n.type === "task-node"),
522
247
  "data.processTask.sort",
523
248
  ).map((n: any) => ({
@@ -528,7 +253,7 @@ const IntegrationView: React.FC<Props> = ({
528
253
 
529
254
  setZonesY(zonesY);
530
255
 
531
- var zonesX = _.uniqBy(
256
+ const zonesX = _.uniqBy(
532
257
  layoutedNodes.filter((n: any) => n.type === "group-node"),
533
258
  "data.parallelProcessingGroup",
534
259
  ).map((n: any) => ({
@@ -543,7 +268,7 @@ const IntegrationView: React.FC<Props> = ({
543
268
  },
544
269
  );
545
270
  } else if (
546
- (tasks && tasks.length === 0) ||
271
+ tasks?.length === 0 ||
547
272
  (processInput && processInput?.processTasks?.length === 0)
548
273
  ) {
549
274
  const mapped = mapEmptyNodesAndEdges(processInput ?? process, 400);
@@ -577,14 +302,14 @@ const IntegrationView: React.FC<Props> = ({
577
302
  ) => {
578
303
  if (!drawerOpen) {
579
304
  if (onTaskClick) {
580
- if (variant === "process") onTaskClick(node.data.processTask.id);
305
+ if (variant === "process") onTaskClick(node.data.processTask);
581
306
  else if (variant === "process-execution")
582
307
  onTaskClick(node.data.processTaskExecution);
583
308
  }
584
309
 
585
310
  setTimeout(() => {
586
- var parentx = 0;
587
- var parenty = 0;
311
+ let parentx = 0;
312
+ let parenty = 0;
588
313
 
589
314
  if (node.parentId) {
590
315
  const parentNode = nodes.find((n) => n.id === node.parentId);
@@ -604,162 +329,11 @@ const IntegrationView: React.FC<Props> = ({
604
329
 
605
330
  // Calculate the initial layout on mount.
606
331
  useLayoutEffect(() => {
607
- onLayout(process);
608
- }, []);
609
-
610
- // ----- Proximity Connect Logic -----
611
- const store = useStoreApi();
612
- const { getInternalNode } = useReactFlow();
613
- const MIN_DISTANCE_LOCAL = 150;
614
-
615
- const getClosestEdge = useCallback(
616
- (node: Node, isTemp = true) => {
617
- const { nodeLookup } = store.getState();
618
- const internalNode = getInternalNode(node.id);
619
- if (!internalNode) return null;
620
-
621
- // drag vector
622
- const dragDx =
623
- (node.position?.x ?? internalNode.internals.positionAbsolute.x) -
624
- internalNode.internals.positionAbsolute.x;
625
- const dragDy =
626
- (node.position?.y ?? internalNode.internals.positionAbsolute.y) -
627
- internalNode.internals.positionAbsolute.y;
628
-
629
- const isVerticalDrag = Math.abs(dragDy) > Math.abs(dragDx);
630
- const dragSignX = Math.sign(dragDx);
631
- const dragSignY = Math.sign(dragDy);
632
-
633
- type Candidate = {
634
- distance: number;
635
- node: InternalNode<Node> | null;
636
- dx: number;
637
- dy: number;
638
- };
639
-
640
- const absolutePosWithParent = (n: InternalNode<Node>) => {
641
- const abs = n.internals.positionAbsolute;
642
-
643
- const parentNode = n.parentId ? getInternalNode(n.parentId) : null;
644
- const parentAbs = parentNode?.internals.positionAbsolute ?? {
645
- x: 0,
646
- y: 0,
647
- };
648
-
649
- return { x: abs.x + parentAbs.x, y: abs.y + parentAbs.y };
650
- };
651
-
652
- const myPos = absolutePosWithParent(internalNode);
653
-
654
- // Only siblings
655
- const siblings = Array.from(nodeLookup.values()).filter(
656
- (n) => n.parentId === internalNode.parentId,
657
- );
658
-
659
- const directionalCandidate = siblings.reduce<Candidate>(
660
- (res, n) => {
661
- if (n.id === internalNode.id) return res;
662
- const np = absolutePosWithParent(n);
663
- const dx = np.x - myPos.x;
664
- const dy = np.y - myPos.y;
665
- const d = Math.sqrt(dx * dx + dy * dy);
666
- if (d >= MIN_DISTANCE_LOCAL) return res;
667
-
668
- let directionMatches = true;
669
- if (isVerticalDrag) {
670
- if (dragSignY !== 0) directionMatches = Math.sign(dy) === dragSignY;
671
- } else {
672
- if (dragSignX !== 0) directionMatches = Math.sign(dx) === dragSignX;
673
- }
674
-
675
- if (!directionMatches) return res;
676
- if (d < res.distance) return { distance: d, node: n, dx, dy };
677
- return res;
678
- },
679
- { distance: Number.MAX_VALUE, node: null, dx: 0, dy: 0 },
680
- );
681
-
682
- let chosen = directionalCandidate;
683
- if (!chosen.node) {
684
- chosen = siblings.reduce(
685
- (res, n) => {
686
- if (n.id === internalNode.id) return res;
687
- const np = absolutePosWithParent(n);
688
- const dx = np.x - myPos.x;
689
- const dy = np.y - myPos.y;
690
- const d = Math.sqrt(dx * dx + dy * dy);
691
- if (d < res.distance && d < MIN_DISTANCE_LOCAL)
692
- return { distance: d, node: n, dx, dy };
693
- return res;
694
- },
695
- { distance: Number.MAX_VALUE, node: null, dx: 0, dy: 0 } as Candidate,
696
- );
697
- }
698
-
699
- if (!chosen.node) return null;
700
-
701
- const chosenPos = absolutePosWithParent(chosen.node);
702
- const chosenAbove = chosenPos.y < myPos.y;
703
-
704
- // Default handle selection by ReactFlow:
705
- // chosenAbove => chosen -> dragged
706
- // chosenBelow => dragged -> chosen
707
- const sourceId = chosenAbove ? chosen.node.id : internalNode.id;
708
- const targetId = chosenAbove ? internalNode.id : chosen.node.id;
709
-
710
- return {
711
- id: `${sourceId}-${targetId}${isTemp ? "-temp" : "-final"}`,
712
- source: sourceId,
713
- target: targetId,
714
- className: isTemp ? "temp" : "final",
715
- };
716
- },
717
- [store, getInternalNode],
718
- );
719
-
720
- const onNodeDrag = useCallback(
721
- (_: any, node: Node) => {
722
- const closeEdge = getClosestEdge(node, true);
723
- setEdges((es) => {
724
- const nextEdges = es.filter((e) => e.className !== "temp");
725
- if (
726
- closeEdge &&
727
- !nextEdges.some(
728
- (ne) =>
729
- ne.source === closeEdge.source && ne.target === closeEdge.target,
730
- )
731
- ) {
732
- nextEdges.push(closeEdge);
733
- }
734
- return nextEdges;
735
- });
736
- },
737
- [getClosestEdge, setEdges],
738
- );
739
-
740
- // const onNodeDragStop = useCallback(
741
- // (_: any, node: Node) => {
742
- // const closeEdge = getClosestEdge(node, false);
743
- // setEdges((es) => {
744
- // const nextEdges = es.filter((e) => e.className !== "temp");
745
- // if (
746
- // closeEdge &&
747
- // !nextEdges.some(
748
- // (ne) =>
749
- // ne.source === closeEdge.source && ne.target === closeEdge.target,
750
- // )
751
- // ) {
752
- // nextEdges.push(closeEdge);
753
- // }
754
- // return nextEdges;
755
- // });
756
- // },
757
- // [getClosestEdge],
758
- // );
759
- // ----- End Proximity Connect Logic -----
332
+ onLayout(configInput ?? processExecutionInput);
333
+ }, [configInput, processExecutionInput]);
760
334
 
761
335
  useLayoutEffect(() => {
762
- let data = JSON.parse(JSON.stringify(nodes));
336
+ let data = globalThis.structuredClone(nodes);
763
337
 
764
338
  data = data.map((node: any) => {
765
339
  return {
@@ -777,53 +351,31 @@ const IntegrationView: React.FC<Props> = ({
777
351
  setNodes(data);
778
352
  }, [drawerOpen, selectedProcessTaskId]);
779
353
 
780
- // const handleNodeDragStart = (_: MouseEvent, node: Node): any => {
781
- // let edgesFiltered = edges.filter((edge: any) => !(edge.source === node.id || edge.target === node.id));
782
-
783
- // let edgesRemoved = edges.filter((edge: any) => (edge.source === node.id || edge.target === node.id));
784
-
785
- // let source;
786
-
787
- // let target;
788
-
789
- // edgesRemoved.forEach((edge: any) => {
790
- // if(edge.source === node.id) {
791
- // target = edge.target;
792
- // }
793
- // if(edge.target === node.id) {
794
- // source = edge.source;
795
- // }
796
- // });
797
-
798
- // edgesFiltered.push({
799
- // id: `${source}-${target}-temp`,
800
- // sources: [source],
801
- // targets: [target],
802
- // source,
803
- // target,
804
- // type: "default-edge",
805
- // //markerEnd: markerEnd,
806
- // })
807
-
808
- // setEdges(edgesFiltered);
809
- // };
810
-
811
354
  const handleNodeDragStart = (_e: ReactMouseEvent, node: Node): any => {
812
355
  let edgesFiltered = [];
813
356
 
814
357
  const edgeList: any[] = [];
815
358
 
359
+ let nodeIds: any[] = [];
360
+
816
361
  edges.forEach((edge: any) => {
362
+ if (edge.source === node.id) {
363
+ nodeIds.push(edge.target);
364
+ }
365
+ if (edge.target === node.id) {
366
+ nodeIds.push(edge.source);
367
+ }
817
368
  if (edge.source === node.id || edge.target === node.id) {
818
369
  edgeList.push(edge);
819
370
  }
820
371
  });
821
372
 
373
+ nodeIds = _.uniq(nodeIds);
374
+
822
375
  let edgeIds: any[] = [];
823
376
 
824
377
  edgeList.forEach((edge: any) => {
825
- edgeIds.push(edge.source);
826
- edgeIds.push(edge.target);
378
+ edgeIds.push(edge.source, edge.target);
827
379
  });
828
380
 
829
381
  edgeIds = _.uniq(edgeIds);
@@ -837,25 +389,16 @@ const IntegrationView: React.FC<Props> = ({
837
389
 
838
390
  edgesFiltered = edgesFiltered.filter(
839
391
  (edge: any) =>
840
- edge.id.includes((node?.data?.processTask as ProcessTask)?.id) ===
841
- false,
392
+ !edge.id.includes((node?.data?.processTask as ProcessTask)?.id),
842
393
  );
843
394
 
844
- edgeIds = edgeIds.filter((id: any) => id !== node.id);
845
-
846
- if (edgeIds.length === 2) {
847
- edgesFiltered.push({
848
- id: `${edgeIds[0]}-${edgeIds[1]}-temp`,
849
- sources: [edgeIds[0]],
850
- targets: [edgeIds[1]],
851
- source: edgeIds[0],
852
- target: edgeIds[1],
853
- type: "default-edge",
854
- markerEnd: markerEnd,
855
- });
856
- }
395
+ let nodesFiltered = nodes.filter(
396
+ (node: any) => !nodeIds.includes(node?.id),
397
+ );
857
398
 
858
399
  setEdges(edgesFiltered);
400
+
401
+ setNodes(nodesFiltered);
859
402
  };
860
403
 
861
404
  const handleNodeDragEnd = (_e: ReactMouseEvent, node: Node): any => {
@@ -967,24 +510,45 @@ const IntegrationView: React.FC<Props> = ({
967
510
  return;
968
511
  }
969
512
 
970
- const modifiedProcess = JSON.parse(JSON.stringify(process));
513
+ if (!configInput) {
514
+ throw new Error("configInput is required");
515
+ }
971
516
 
972
- let updatedTasks = modifiedProcess?.processTasks?.map((task: any) => {
973
- if (zoneX && task.id === (node?.data?.processTask as ProcessTask)?.id) {
974
- return {
975
- ...task,
976
- parallelProcessingGroup: zoneX.parallelProcessingGroup,
977
- };
978
- }
979
- return task;
980
- });
517
+ const modifiedProcess: ConfigExport =
518
+ globalThis.structuredClone(configInput);
981
519
 
982
- updatedTasks = updatedTasks.map((task: any) => {
983
- if (zoneX && task.id === (node?.data?.processTask as ProcessTask)?.id) {
984
- return {
985
- ...task,
986
- sort: zoneY.sort,
987
- };
520
+ let updatedTasks = modifiedProcess.Processes?.[0]?.ProcessTasks?.map(
521
+ (task) => {
522
+ if (task) {
523
+ if (
524
+ zoneX && (node?.data?.processTask as ProcessTask)?.id
525
+ ? task.ProcessTaskId ===
526
+ (node?.data?.processTask as ProcessTask)?.id
527
+ : task.Name === (node?.data?.processTask as ProcessTask)?.name
528
+ ) {
529
+ return {
530
+ ...task,
531
+ ParallelProcessingGroup: zoneX.parallelProcessingGroup,
532
+ };
533
+ }
534
+ }
535
+ return task;
536
+ },
537
+ );
538
+
539
+ updatedTasks = updatedTasks?.map((task) => {
540
+ if (task) {
541
+ if (
542
+ zoneY && (node?.data?.processTask as ProcessTask)?.id
543
+ ? task.ProcessTaskId ===
544
+ (node?.data?.processTask as ProcessTask)?.id
545
+ : task.Name === (node?.data?.processTask as ProcessTask)?.name
546
+ ) {
547
+ return {
548
+ ...task,
549
+ Sort: zoneY.sort,
550
+ };
551
+ }
988
552
  }
989
553
  return task;
990
554
  });
@@ -993,37 +557,41 @@ const IntegrationView: React.FC<Props> = ({
993
557
  let index = 0;
994
558
 
995
559
  updatedTasks = _.sortBy(updatedTasks, [
996
- "parallelProcessingGroup",
997
- "sort",
998
- ]).map((task: any) => {
999
- if (task.parallelProcessingGroup !== prevParallelProcessingGroup) {
1000
- prevParallelProcessingGroup = task.parallelProcessingGroup;
1001
- index++;
1002
- }
560
+ "ParallelProcessingGroup",
561
+ "Sort",
562
+ ])?.map((task) => {
563
+ if (task) {
564
+ if (task.ParallelProcessingGroup !== prevParallelProcessingGroup) {
565
+ prevParallelProcessingGroup = task.ParallelProcessingGroup;
566
+ index++;
567
+ }
1003
568
 
1004
- task.parallelProcessingGroup = index;
569
+ task.ParallelProcessingGroup = index;
570
+ }
1005
571
 
1006
572
  return task;
1007
573
  });
1008
574
 
1009
- var partitionedTasks = _.values(
1010
- _.groupBy(updatedTasks, "parallelProcessingGroup"),
575
+ const partitionedTasks = _.values(
576
+ _.groupBy(updatedTasks, "ParallelProcessingGroup"),
1011
577
  );
1012
578
 
1013
579
  let processTaskValue: any[] = [];
1014
580
 
1015
- partitionedTasks.forEach((partition: any) => {
581
+ partitionedTasks.forEach((partition) => {
1016
582
  index = 0;
1017
583
  let prevSort: any = null;
1018
584
 
1019
- const sortedPartition = _.sortBy(partition, ["sort", "name"]).map(
1020
- (task: any) => {
1021
- if (task.sort !== prevSort) {
1022
- prevSort = task.sort;
1023
- index++;
1024
- }
585
+ const sortedPartition = _.sortBy(partition, ["Sort", "Name"]).map(
586
+ (task) => {
587
+ if (task) {
588
+ if (task.Sort !== prevSort) {
589
+ prevSort = task.Sort;
590
+ index++;
591
+ }
1025
592
 
1026
- task.sort = index;
593
+ task.Sort = index;
594
+ }
1027
595
 
1028
596
  return task;
1029
597
  },
@@ -1032,11 +600,10 @@ const IntegrationView: React.FC<Props> = ({
1032
600
  processTaskValue = processTaskValue.concat(sortedPartition);
1033
601
  });
1034
602
 
1035
- modifiedProcess.processTasks = processTaskValue;
603
+ if (modifiedProcess?.Processes?.[0])
604
+ modifiedProcess.Processes[0].ProcessTasks = processTaskValue;
1036
605
 
1037
- setProcess(modifiedProcess);
1038
-
1039
- onLayout(modifiedProcess);
606
+ if (onConfigChange) onConfigChange(modifiedProcess);
1040
607
  };
1041
608
 
1042
609
  return (
@@ -1055,8 +622,6 @@ const IntegrationView: React.FC<Props> = ({
1055
622
  onNodeClick={handleNodeClick}
1056
623
  onNodeDragStart={handleNodeDragStart}
1057
624
  onNodeDragStop={handleNodeDragEnd}
1058
- onNodeDrag={onNodeDrag}
1059
- //onNodeDragStop={onNodeDragStop}
1060
625
  fitView={true} // Fits the view on initial load
1061
626
  fitViewOptions={{
1062
627
  padding: 0.1,
@@ -1066,11 +631,11 @@ const IntegrationView: React.FC<Props> = ({
1066
631
  duration: 200,
1067
632
  nodes: nodes, // nodes to fit
1068
633
  }} // Optional options for initial fit
1069
- nodesDraggable={true}
634
+ nodesDraggable={canEdit}
1070
635
  minZoom={0.1} // Lock zoom to 1
1071
636
  maxZoom={2} // Lock zoom to 1
1072
- nodesConnectable={!drawerOpen}
1073
- elementsSelectable={!drawerOpen}
637
+ nodesConnectable={canEdit && !drawerOpen}
638
+ elementsSelectable={canEdit && !drawerOpen}
1074
639
  panOnDrag={!drawerOpen}
1075
640
  zoomOnScroll={!drawerOpen}
1076
641
  zoomOnDoubleClick={!drawerOpen}
@@ -1083,7 +648,7 @@ const IntegrationView: React.FC<Props> = ({
1083
648
  );
1084
649
  };
1085
650
 
1086
- export default (props: Props) => (
651
+ const IntegrationViewWrapper = (props: Props): React.JSX.Element => (
1087
652
  <ReactFlowProvider>
1088
653
  <IntegrationView
1089
654
  data={props.data}
@@ -1091,6 +656,12 @@ export default (props: Props) => (
1091
656
  onTaskClick={props.onTaskClick}
1092
657
  drawerOpen={props.drawerOpen}
1093
658
  processTaskId={props.processTaskId}
659
+ config={props.config}
660
+ onConfigChange={props.onConfigChange}
661
+ onAdd={props.onAdd}
662
+ canEdit={props.canEdit}
1094
663
  />
1095
664
  </ReactFlowProvider>
1096
665
  );
666
+
667
+ export default IntegrationViewWrapper;