@principal-ai/principal-view-react 0.13.7 → 0.13.9
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/components/GraphRenderer.d.ts +1 -15
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +115 -269
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/NodeInfoPanel.d.ts.map +1 -1
- package/dist/components/NodeInfoPanel.js.map +1 -1
- package/dist/edges/CustomEdge.d.ts +2 -2
- package/dist/edges/CustomEdge.d.ts.map +1 -1
- package/dist/edges/CustomEdge.js +5 -4
- package/dist/edges/CustomEdge.js.map +1 -1
- package/dist/hooks/usePathBasedEvents.d.ts.map +1 -1
- package/dist/hooks/usePathBasedEvents.js +2 -1
- package/dist/hooks/usePathBasedEvents.js.map +1 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/nodes/CustomNode.d.ts +2 -2
- package/dist/nodes/CustomNode.d.ts.map +1 -1
- package/dist/nodes/CustomNode.js +41 -10
- package/dist/nodes/CustomNode.js.map +1 -1
- package/package.json +1 -1
- package/src/components/GraphRenderer.tsx +132 -352
- package/src/edges/CustomEdge.tsx +8 -7
- package/src/hooks/usePathBasedEvents.ts +2 -1
- package/src/index.ts +0 -6
- package/src/nodes/CustomNode.tsx +50 -13
- package/src/stories/ColorPriority.stories.tsx +2 -0
- package/src/stories/EventDrivenAnimations.stories.tsx +332 -326
- package/src/stories/GraphRenderer.stories.tsx +2 -2
- package/src/stories/NodeDefinitionComparison.stories.tsx +1 -1
- package/src/stories/NodeDimensionsTesting.stories.tsx +2 -2
- package/src/stories/OtelComponents.stories.tsx +0 -47
- package/src/stories/data/graph-converter-test-execution.json +244 -26
- package/src/stories/data/graph-converter-validated-execution.json +6 -6
- package/src/components/EdgeInfoPanel.tsx +0 -247
- package/src/components/NodeInfoPanel.tsx +0 -724
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import '@xyflow/react/dist/style.css';
|
|
3
|
-
import type { Violation, GraphEvent, ExtendedCanvas, ComponentLibrary
|
|
3
|
+
import type { Violation, GraphEvent, ExtendedCanvas, ComponentLibrary } from '@principal-ai/principal-view-core';
|
|
4
4
|
/** Position change event for tracking node movements */
|
|
5
5
|
export interface NodePositionChange {
|
|
6
6
|
nodeId: string;
|
|
@@ -138,20 +138,6 @@ interface GraphRendererBaseProps {
|
|
|
138
138
|
* Receives the node ID and the click event. If provided, overrides default node selection behavior.
|
|
139
139
|
*/
|
|
140
140
|
onNodeClick?: (nodeId: string, event: React.MouseEvent) => void;
|
|
141
|
-
/**
|
|
142
|
-
* Whether to show the node detail panel when nodes are clicked.
|
|
143
|
-
* Defaults to undefined (auto), which shows panel only when onNodeClick is not provided.
|
|
144
|
-
* Set to true to force showing panel even with custom onNodeClick handler.
|
|
145
|
-
* Set to false to hide panel completely.
|
|
146
|
-
*/
|
|
147
|
-
showNodeDetailPanel?: boolean;
|
|
148
|
-
/**
|
|
149
|
-
* Optional callback to resolve event references to full event schemas.
|
|
150
|
-
* When a node has an eventRef (string reference like "order.completed"),
|
|
151
|
-
* this function is called to retrieve the full event definition.
|
|
152
|
-
* Return undefined if the event reference cannot be resolved.
|
|
153
|
-
*/
|
|
154
|
-
resolveEventRef?: (eventRef: string) => PVEventSchema | undefined;
|
|
155
141
|
/**
|
|
156
142
|
* When set, fits the viewport to show these specific nodes.
|
|
157
143
|
* Useful for focusing on a subset of the graph (e.g., scenario nodes).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GraphRenderer.d.ts","sourceRoot":"","sources":["../../src/components/GraphRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"GraphRenderer.d.ts","sourceRoot":"","sources":["../../src/components/GraphRenderer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo, useState, useEffect, useCallback, useRef, useImperativeHandle, forwardRef, } from 'react';
|
|
2
|
+
import { useMemo, useState, useEffect, useLayoutEffect, useCallback, useRef, useImperativeHandle, forwardRef, } from 'react';
|
|
3
3
|
import { ReactFlow, Background, BackgroundVariant, Controls, MiniMap, ReactFlowProvider, useReactFlow, useUpdateNodeInternals, useViewport, applyNodeChanges, applyEdgeChanges, } from '@xyflow/react';
|
|
4
4
|
import '@xyflow/react/dist/style.css';
|
|
5
5
|
import { CanvasConverter } from '@principal-ai/principal-view-core';
|
|
@@ -7,16 +7,14 @@ import { useTheme } from '@principal-ade/industry-theme';
|
|
|
7
7
|
import { CustomNode } from '../nodes/CustomNode';
|
|
8
8
|
import { CustomEdge } from '../edges/CustomEdge';
|
|
9
9
|
import { convertToXYFlowNodes, convertToXYFlowEdges, } from '../utils/graphConverter';
|
|
10
|
-
import { EdgeInfoPanel } from './EdgeInfoPanel';
|
|
11
|
-
import { NodeInfoPanel } from './NodeInfoPanel';
|
|
12
10
|
// Define custom node types
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
};
|
|
11
|
+
// Type assertion needed because ReactFlow's NodeTypes expects generic components
|
|
12
|
+
// but CustomNode is properly typed with CustomNodeData for type safety internally
|
|
13
|
+
const nodeTypes = { custom: CustomNode };
|
|
16
14
|
// Define custom edge types
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
};
|
|
15
|
+
// Type assertion needed because ReactFlow's EdgeTypes expects generic components
|
|
16
|
+
// but CustomEdge is properly typed with CustomEdgeData for type safety internally
|
|
17
|
+
const edgeTypes = { custom: CustomEdge };
|
|
20
18
|
const createEmptyEditState = () => ({
|
|
21
19
|
positionChanges: new Map(),
|
|
22
20
|
dimensionChanges: new Map(),
|
|
@@ -80,7 +78,7 @@ const CenterIndicator = ({ color }) => {
|
|
|
80
78
|
/**
|
|
81
79
|
* Inner component that uses ReactFlow hooks
|
|
82
80
|
*/
|
|
83
|
-
const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges, violations = [], configName: _configName, showMinimap = false, showControls = true, showBackground = true, backgroundVariant = 'lines', backgroundGap, showCenterIndicator = false, showTooltips = true, fitViewDuration = 200, highlightedNodeId, activeNodeIds, events = [], onEventProcessed, editable = false, onPendingChangesChange, onEditStateChange, editStateRef, onNodeClick: onNodeClickProp,
|
|
81
|
+
const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges, violations = [], configName: _configName, showMinimap = false, showControls = true, showBackground = true, backgroundVariant = 'lines', backgroundGap, showCenterIndicator = false, showTooltips = true, fitViewDuration = 200, highlightedNodeId, activeNodeIds, events = [], onEventProcessed, editable = false, onPendingChangesChange, onEditStateChange, editStateRef, onNodeClick: onNodeClickProp, fitViewToNodeIds, fitViewPadding = 0.2, }) => {
|
|
84
82
|
const { fitView, fitBounds, getNodes } = useReactFlow();
|
|
85
83
|
const updateNodeInternals = useUpdateNodeInternals();
|
|
86
84
|
const { theme } = useTheme();
|
|
@@ -118,21 +116,16 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
118
116
|
const [selectedEdgeIds, setSelectedEdgeIds] = useState(new Set());
|
|
119
117
|
// Track selected nodes for info panel (supports multi-select)
|
|
120
118
|
const [selectedNodeIds, setSelectedNodeIds] = useState(new Set());
|
|
121
|
-
// Track whether panel should be shown (only on explicit clicks, not after dragging)
|
|
122
|
-
const [showNodePanel, setShowNodePanel] = useState(false);
|
|
123
|
-
const [showEdgePanel, setShowEdgePanel] = useState(false);
|
|
124
119
|
// Track hidden nodes (shift-click to toggle)
|
|
125
120
|
const [hiddenNodeIds, setHiddenNodeIds] = useState(new Set());
|
|
126
121
|
// Track pending connection for edge type picker
|
|
127
122
|
const [pendingConnection, setPendingConnection] = useState(null);
|
|
128
|
-
// Sync highlightedNodeId to selection state
|
|
123
|
+
// Sync highlightedNodeId to selection state
|
|
129
124
|
useEffect(() => {
|
|
130
125
|
if (highlightedNodeId) {
|
|
131
126
|
setSelectedNodeIds(new Set([highlightedNodeId]));
|
|
132
|
-
setShowNodePanel(true);
|
|
133
127
|
// Clear edge selection when highlighting a node
|
|
134
128
|
setSelectedEdgeIds(new Set());
|
|
135
|
-
setShowEdgePanel(false);
|
|
136
129
|
}
|
|
137
130
|
}, [highlightedNodeId]);
|
|
138
131
|
// ============================================
|
|
@@ -289,21 +282,17 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
289
282
|
}
|
|
290
283
|
return next;
|
|
291
284
|
});
|
|
292
|
-
setShowEdgePanel(true);
|
|
293
285
|
}
|
|
294
286
|
else {
|
|
295
287
|
// Regular click: single select (replace selection)
|
|
296
288
|
const shouldDeselect = selectedEdgeIds.size === 1 && selectedEdgeIds.has(edge.id);
|
|
297
289
|
if (shouldDeselect) {
|
|
298
290
|
setSelectedEdgeIds(new Set());
|
|
299
|
-
setShowEdgePanel(false);
|
|
300
291
|
}
|
|
301
292
|
else {
|
|
302
293
|
setSelectedEdgeIds(new Set([edge.id]));
|
|
303
|
-
setShowEdgePanel(true);
|
|
304
294
|
}
|
|
305
295
|
setSelectedNodeIds(new Set());
|
|
306
|
-
setShowNodePanel(false);
|
|
307
296
|
}
|
|
308
297
|
}, [editable, selectedEdgeIds]);
|
|
309
298
|
// Handle node click (toggle selection, supports Cmd/Ctrl for hide/dim)
|
|
@@ -342,33 +331,24 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
342
331
|
else {
|
|
343
332
|
next.add(node.id);
|
|
344
333
|
}
|
|
345
|
-
//
|
|
334
|
+
// Update local nodes selection state immediately for edit mode
|
|
346
335
|
if (editable) {
|
|
347
336
|
setXyflowLocalNodes((nodes) => nodes.map((n) => ({
|
|
348
337
|
...n,
|
|
349
|
-
selected:
|
|
338
|
+
selected: next.has(n.id),
|
|
350
339
|
})));
|
|
351
340
|
}
|
|
352
341
|
return next;
|
|
353
342
|
});
|
|
354
343
|
return;
|
|
355
344
|
}
|
|
356
|
-
// Determine if we should show the panel based on showNodeDetailPanel prop
|
|
357
|
-
const shouldShowPanel = showNodeDetailPanel !== false && (showNodeDetailPanel === true || !onNodeClickProp);
|
|
358
|
-
// If custom node click handler is provided, call it
|
|
359
|
-
if (onNodeClickProp) {
|
|
360
|
-
onNodeClickProp(node.id, event);
|
|
361
|
-
// If showNodeDetailPanel is not explicitly true, return early (old behavior)
|
|
362
|
-
if (showNodeDetailPanel !== true) {
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
345
|
// Regular click: single select (replace selection)
|
|
346
|
+
event.preventDefault();
|
|
347
|
+
event.stopPropagation();
|
|
367
348
|
const shouldDeselect = selectedNodeIds.size === 1 && selectedNodeIds.has(node.id);
|
|
368
349
|
if (shouldDeselect) {
|
|
369
350
|
setSelectedNodeIds(new Set());
|
|
370
|
-
|
|
371
|
-
// Also update local nodes selection state immediately
|
|
351
|
+
// Update local nodes selection state immediately for edit mode
|
|
372
352
|
if (editable) {
|
|
373
353
|
setXyflowLocalNodes((nodes) => nodes.map((n) => ({
|
|
374
354
|
...n,
|
|
@@ -378,10 +358,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
378
358
|
}
|
|
379
359
|
else {
|
|
380
360
|
setSelectedNodeIds(new Set([node.id]));
|
|
381
|
-
|
|
382
|
-
setShowNodePanel(true);
|
|
383
|
-
}
|
|
384
|
-
// Also update local nodes selection state immediately
|
|
361
|
+
// Update local nodes selection state immediately for edit mode
|
|
385
362
|
if (editable) {
|
|
386
363
|
setXyflowLocalNodes((nodes) => nodes.map((n) => ({
|
|
387
364
|
...n,
|
|
@@ -390,152 +367,85 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
390
367
|
}
|
|
391
368
|
}
|
|
392
369
|
setSelectedEdgeIds(new Set());
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
370
|
+
// If custom node click handler is provided, call it after selection is updated
|
|
371
|
+
if (onNodeClickProp) {
|
|
372
|
+
onNodeClickProp(node.id, event);
|
|
373
|
+
}
|
|
374
|
+
}, [selectedNodeIds, onNodeClickProp, editable]);
|
|
375
|
+
// Handle double-click on node in non-edit mode to fit/focus around it
|
|
376
|
+
const onNodeDoubleClick = useCallback((_event, node) => {
|
|
377
|
+
// Only fit to node in non-edit mode
|
|
378
|
+
if (editable)
|
|
379
|
+
return;
|
|
380
|
+
// Get the node's dimensions (use measured dimensions if available)
|
|
381
|
+
const width = node.measured?.width ?? node.width ?? 200;
|
|
382
|
+
const height = node.measured?.height ?? node.height ?? 100;
|
|
383
|
+
// Calculate bounds for the node with some padding
|
|
384
|
+
const bounds = {
|
|
385
|
+
x: node.position.x,
|
|
386
|
+
y: node.position.y,
|
|
387
|
+
width,
|
|
388
|
+
height,
|
|
389
|
+
};
|
|
390
|
+
// Fit the view to the node's bounds
|
|
391
|
+
fitBounds(bounds, {
|
|
392
|
+
padding: 0.5,
|
|
393
|
+
duration: fitViewDuration,
|
|
394
|
+
});
|
|
395
|
+
}, [editable, fitBounds, fitViewDuration]);
|
|
418
396
|
// Handle pane click (clear selection when clicking empty space)
|
|
419
397
|
const onPaneClick = useCallback(() => {
|
|
420
398
|
setSelectedNodeIds(new Set());
|
|
421
399
|
setSelectedEdgeIds(new Set());
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
400
|
+
// In edit mode, also update local nodes selection state
|
|
401
|
+
if (editable) {
|
|
402
|
+
setXyflowLocalNodes((nodes) => nodes.map((n) => ({
|
|
403
|
+
...n,
|
|
404
|
+
selected: false,
|
|
405
|
+
})));
|
|
406
|
+
}
|
|
407
|
+
}, [editable]);
|
|
425
408
|
// Handle selection change from ReactFlow (box selection and clicks)
|
|
426
409
|
const handleSelectionChange = useCallback(({ nodes: selectedNodes, edges: selectedEdges }) => {
|
|
427
410
|
// Ignore selection changes when we're hiding a node
|
|
428
411
|
if (hidingNodeRef.current) {
|
|
429
412
|
return;
|
|
430
413
|
}
|
|
431
|
-
//
|
|
432
|
-
|
|
433
|
-
setSelectedEdgeIds(new Set(selectedEdges.map((e) => e.id)));
|
|
434
|
-
// Only show panels in edit mode or when explicitly enabled
|
|
414
|
+
// In edit mode, we manage selection ourselves via onNodeClick
|
|
415
|
+
// Skip handleSelectionChange to avoid ReactFlow overwriting our selection state
|
|
435
416
|
if (editable) {
|
|
436
|
-
|
|
437
|
-
if (selectedNodes.length > 0) {
|
|
438
|
-
setShowNodePanel(true);
|
|
439
|
-
}
|
|
440
|
-
if (selectedEdges.length > 0) {
|
|
441
|
-
setShowEdgePanel(true);
|
|
442
|
-
}
|
|
417
|
+
return;
|
|
443
418
|
}
|
|
419
|
+
const newSelectedNodeIds = new Set(selectedNodes.map((n) => n.id));
|
|
420
|
+
// Update selection state for read-only mode (for visual feedback)
|
|
421
|
+
setSelectedNodeIds(newSelectedNodeIds);
|
|
422
|
+
setSelectedEdgeIds(new Set(selectedEdges.map((e) => e.id)));
|
|
444
423
|
}, [editable]);
|
|
445
|
-
//
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
updateEditState((prev) => {
|
|
462
|
-
const newUpdates = new Map(prev.nodeUpdates);
|
|
463
|
-
const existing = newUpdates.get(nodeId) || {};
|
|
464
|
-
newUpdates.set(nodeId, {
|
|
465
|
-
type: updates.type ?? existing.type,
|
|
466
|
-
data: updates.data ? { ...existing.data, ...updates.data } : existing.data,
|
|
467
|
-
});
|
|
468
|
-
return { ...prev, nodeUpdates: newUpdates };
|
|
469
|
-
});
|
|
470
|
-
}, [editable, updateEditState]);
|
|
471
|
-
// Handle node delete (internal)
|
|
472
|
-
const handleNodeDelete = useCallback((nodeId) => {
|
|
473
|
-
if (!editable)
|
|
474
|
-
return;
|
|
475
|
-
// Remove from local state
|
|
476
|
-
setLocalNodes((prev) => prev.filter((n) => n.id !== nodeId));
|
|
477
|
-
setLocalEdges((prev) => prev.filter((e) => e.from !== nodeId && e.to !== nodeId));
|
|
478
|
-
// Track the change
|
|
479
|
-
updateEditState((prev) => {
|
|
480
|
-
const newDeletedNodes = new Set(prev.deletedNodeIds);
|
|
481
|
-
newDeletedNodes.add(nodeId);
|
|
482
|
-
// Remove any pending updates for this node
|
|
483
|
-
const newUpdates = new Map(prev.nodeUpdates);
|
|
484
|
-
newUpdates.delete(nodeId);
|
|
485
|
-
// Remove any position changes for this node
|
|
486
|
-
const newPositions = new Map(prev.positionChanges);
|
|
487
|
-
newPositions.delete(nodeId);
|
|
488
|
-
// Remove any dimension changes for this node
|
|
489
|
-
const newDimensions = new Map(prev.dimensionChanges);
|
|
490
|
-
newDimensions.delete(nodeId);
|
|
491
|
-
// Remove created edges that involve this node
|
|
492
|
-
const newCreatedEdges = prev.createdEdges.filter((e) => e.from !== nodeId && e.to !== nodeId);
|
|
493
|
-
return {
|
|
494
|
-
...prev,
|
|
495
|
-
deletedNodeIds: newDeletedNodes,
|
|
496
|
-
nodeUpdates: newUpdates,
|
|
497
|
-
positionChanges: newPositions,
|
|
498
|
-
dimensionChanges: newDimensions,
|
|
499
|
-
createdEdges: newCreatedEdges,
|
|
500
|
-
};
|
|
501
|
-
});
|
|
502
|
-
setSelectedNodeIds(new Set());
|
|
503
|
-
}, [editable, updateEditState]);
|
|
504
|
-
// Handle edge delete (internal)
|
|
505
|
-
const handleEdgeDelete = useCallback((edgeId) => {
|
|
506
|
-
if (!editable)
|
|
507
|
-
return;
|
|
508
|
-
// Find the edge before removing it so we can track its full info
|
|
509
|
-
const edgeToDelete = localEdges.find((e) => e.id === edgeId);
|
|
510
|
-
// Remove from local state
|
|
511
|
-
setLocalEdges((prev) => prev.filter((e) => e.id !== edgeId));
|
|
424
|
+
// Create edge helper
|
|
425
|
+
const createEdge = useCallback((from, to, type, sourceHandle, targetHandle) => {
|
|
426
|
+
const edgeId = `${from}-${to}-${type}-${Date.now()}`;
|
|
427
|
+
// Add to local state with handle information
|
|
428
|
+
const newEdge = {
|
|
429
|
+
id: edgeId,
|
|
430
|
+
type,
|
|
431
|
+
from,
|
|
432
|
+
to,
|
|
433
|
+
data: {},
|
|
434
|
+
createdAt: Date.now(),
|
|
435
|
+
updatedAt: Date.now(),
|
|
436
|
+
sourceHandle,
|
|
437
|
+
targetHandle,
|
|
438
|
+
};
|
|
439
|
+
setLocalEdges((prev) => [...prev, newEdge]);
|
|
512
440
|
// Track the change
|
|
513
|
-
updateEditState((prev) => {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
}
|
|
522
|
-
// Otherwise mark as deleted with full edge info
|
|
523
|
-
if (edgeToDelete) {
|
|
524
|
-
const newDeletedEdges = [
|
|
525
|
-
...prev.deletedEdges,
|
|
526
|
-
{
|
|
527
|
-
id: edgeId,
|
|
528
|
-
from: edgeToDelete.from,
|
|
529
|
-
to: edgeToDelete.to,
|
|
530
|
-
type: edgeToDelete.type,
|
|
531
|
-
},
|
|
532
|
-
];
|
|
533
|
-
return { ...prev, deletedEdges: newDeletedEdges };
|
|
534
|
-
}
|
|
535
|
-
return prev;
|
|
536
|
-
});
|
|
537
|
-
setSelectedEdgeIds(new Set());
|
|
538
|
-
}, [editable, updateEditState, localEdges]);
|
|
441
|
+
updateEditState((prev) => ({
|
|
442
|
+
...prev,
|
|
443
|
+
createdEdges: [
|
|
444
|
+
...prev.createdEdges,
|
|
445
|
+
{ id: edgeId, from, to, type, sourceHandle, targetHandle },
|
|
446
|
+
],
|
|
447
|
+
}));
|
|
448
|
+
}, [updateEditState]);
|
|
539
449
|
// Handle new connection from drag
|
|
540
450
|
const handleConnect = useCallback((connection) => {
|
|
541
451
|
if (!editable || !connection.source || !connection.target)
|
|
@@ -568,32 +478,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
568
478
|
validTypes: uniqueTypes,
|
|
569
479
|
});
|
|
570
480
|
}
|
|
571
|
-
}, [editable, nodes, configuration.allowedConnections]);
|
|
572
|
-
// Create edge helper
|
|
573
|
-
const createEdge = useCallback((from, to, type, sourceHandle, targetHandle) => {
|
|
574
|
-
const edgeId = `${from}-${to}-${type}-${Date.now()}`;
|
|
575
|
-
// Add to local state with handle information
|
|
576
|
-
const newEdge = {
|
|
577
|
-
id: edgeId,
|
|
578
|
-
type,
|
|
579
|
-
from,
|
|
580
|
-
to,
|
|
581
|
-
data: {},
|
|
582
|
-
createdAt: Date.now(),
|
|
583
|
-
updatedAt: Date.now(),
|
|
584
|
-
sourceHandle,
|
|
585
|
-
targetHandle,
|
|
586
|
-
};
|
|
587
|
-
setLocalEdges((prev) => [...prev, newEdge]);
|
|
588
|
-
// Track the change
|
|
589
|
-
updateEditState((prev) => ({
|
|
590
|
-
...prev,
|
|
591
|
-
createdEdges: [
|
|
592
|
-
...prev.createdEdges,
|
|
593
|
-
{ id: edgeId, from, to, type, sourceHandle, targetHandle },
|
|
594
|
-
],
|
|
595
|
-
}));
|
|
596
|
-
}, [updateEditState]);
|
|
481
|
+
}, [editable, nodes, configuration.allowedConnections, createEdge]);
|
|
597
482
|
// Handle edge type selection from picker
|
|
598
483
|
const handleEdgeTypeSelect = useCallback((type) => {
|
|
599
484
|
if (!pendingConnection)
|
|
@@ -731,37 +616,6 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
731
616
|
// SELECTED ITEMS
|
|
732
617
|
// ============================================
|
|
733
618
|
// Get first selected edge (for single-selection info panel)
|
|
734
|
-
const selectedEdgeId = useMemo(() => {
|
|
735
|
-
if (selectedEdgeIds.size === 0)
|
|
736
|
-
return null;
|
|
737
|
-
return selectedEdgeIds.values().next().value;
|
|
738
|
-
}, [selectedEdgeIds]);
|
|
739
|
-
const selectedEdge = useMemo(() => {
|
|
740
|
-
if (!selectedEdgeId)
|
|
741
|
-
return null;
|
|
742
|
-
return edges.find((e) => e.id === selectedEdgeId);
|
|
743
|
-
}, [selectedEdgeId, edges]);
|
|
744
|
-
const selectedEdgeTypeDefinition = useMemo(() => {
|
|
745
|
-
if (!selectedEdge)
|
|
746
|
-
return null;
|
|
747
|
-
return configuration.edgeTypes[selectedEdge.type];
|
|
748
|
-
}, [selectedEdge, configuration.edgeTypes]);
|
|
749
|
-
// Get first selected node (for single-selection info panel)
|
|
750
|
-
const selectedNodeId = useMemo(() => {
|
|
751
|
-
if (selectedNodeIds.size === 0)
|
|
752
|
-
return null;
|
|
753
|
-
return selectedNodeIds.values().next().value;
|
|
754
|
-
}, [selectedNodeIds]);
|
|
755
|
-
const selectedNode = useMemo(() => {
|
|
756
|
-
if (!selectedNodeId)
|
|
757
|
-
return null;
|
|
758
|
-
return nodes.find((n) => n.id === selectedNodeId);
|
|
759
|
-
}, [selectedNodeId, nodes]);
|
|
760
|
-
const selectedNodeTypeDefinition = useMemo(() => {
|
|
761
|
-
if (!selectedNode)
|
|
762
|
-
return null;
|
|
763
|
-
return configuration.nodeTypes[selectedNode.type];
|
|
764
|
-
}, [selectedNode, configuration.nodeTypes]);
|
|
765
619
|
// ============================================
|
|
766
620
|
// ANIMATIONS
|
|
767
621
|
// ============================================
|
|
@@ -902,7 +756,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
902
756
|
}, [edges]);
|
|
903
757
|
// Local xyflow nodes state for dragging
|
|
904
758
|
const [xyflowLocalNodes, setXyflowLocalNodes] = useState(xyflowNodesBase);
|
|
905
|
-
// Sync when base
|
|
759
|
+
// Sync when base node IDs change
|
|
906
760
|
const prevBaseNodesKeyRef = useRef(baseNodesKey);
|
|
907
761
|
useEffect(() => {
|
|
908
762
|
if (prevBaseNodesKeyRef.current !== baseNodesKey) {
|
|
@@ -910,6 +764,20 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
910
764
|
setXyflowLocalNodes(xyflowNodesBase);
|
|
911
765
|
}
|
|
912
766
|
}, [baseNodesKey, xyflowNodesBase]);
|
|
767
|
+
// Sync selection state to local nodes when selectedNodeIds changes (edit mode only)
|
|
768
|
+
// Use useLayoutEffect to ensure sync happens before paint (prevents flash)
|
|
769
|
+
const prevSelectedNodeIdsRef = useRef(selectedNodeIds);
|
|
770
|
+
useLayoutEffect(() => {
|
|
771
|
+
if (!editable)
|
|
772
|
+
return;
|
|
773
|
+
if (prevSelectedNodeIdsRef.current === selectedNodeIds)
|
|
774
|
+
return;
|
|
775
|
+
prevSelectedNodeIdsRef.current = selectedNodeIds;
|
|
776
|
+
setXyflowLocalNodes((localNodes) => localNodes.map((localNode) => ({
|
|
777
|
+
...localNode,
|
|
778
|
+
selected: selectedNodeIds.has(localNode.id),
|
|
779
|
+
})));
|
|
780
|
+
}, [editable, selectedNodeIds]);
|
|
913
781
|
// Also sync when entering edit mode or when base nodes change content
|
|
914
782
|
const prevEditableRef = useRef(editable);
|
|
915
783
|
useEffect(() => {
|
|
@@ -942,14 +810,19 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
942
810
|
const handleNodesChange = useCallback((changes) => {
|
|
943
811
|
if (!editable)
|
|
944
812
|
return;
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
813
|
+
// Filter out selection changes - we manage selection ourselves via selectedNodeIds
|
|
814
|
+
const nonSelectionChanges = changes.filter((change) => change.type !== 'select');
|
|
815
|
+
// Only apply changes if there are non-selection changes to apply
|
|
816
|
+
if (nonSelectionChanges.length > 0) {
|
|
817
|
+
setXyflowLocalNodes((nds) => {
|
|
818
|
+
// Apply changes but preserve our selection state
|
|
819
|
+
const updated = applyNodeChanges(nonSelectionChanges, nds);
|
|
820
|
+
// Restore selection state from our managed selectedNodeIds
|
|
821
|
+
return updated.map((node) => ({
|
|
822
|
+
...node,
|
|
823
|
+
selected: selectedNodeIds.has(node.id),
|
|
824
|
+
}));
|
|
825
|
+
});
|
|
953
826
|
}
|
|
954
827
|
// Track position changes on drag end
|
|
955
828
|
const positionChanges = changes.filter((change) => change.type === 'position' &&
|
|
@@ -963,22 +836,6 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
963
836
|
change.dimensions !== undefined &&
|
|
964
837
|
'resizing' in change &&
|
|
965
838
|
change.resizing === false);
|
|
966
|
-
// Debug logging for dimension changes
|
|
967
|
-
if (process.env.NODE_ENV === 'development') {
|
|
968
|
-
const allDimensionChanges = changes.filter(c => c.type === 'dimensions');
|
|
969
|
-
if (allDimensionChanges.length > 0) {
|
|
970
|
-
console.log('[GraphRenderer] Dimension changes detected:', allDimensionChanges.map(c => ({
|
|
971
|
-
// @ts-expect-error - accessing properties for debug
|
|
972
|
-
id: c.id,
|
|
973
|
-
// @ts-expect-error - accessing properties for debug
|
|
974
|
-
dimensions: c.dimensions,
|
|
975
|
-
// @ts-expect-error - accessing properties for debug
|
|
976
|
-
resizing: c.resizing,
|
|
977
|
-
// @ts-expect-error - accessing properties for debug
|
|
978
|
-
isGroup: nodes.find(n => n.id === c.id)?.data?.canvasType === 'group'
|
|
979
|
-
})));
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
839
|
if (dimensionChanges.length > 0) {
|
|
983
840
|
updateEditState((prev) => {
|
|
984
841
|
const newDimensions = new Map(prev.dimensionChanges);
|
|
@@ -1005,7 +862,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
1005
862
|
return { ...prev, positionChanges: newPositions };
|
|
1006
863
|
});
|
|
1007
864
|
}
|
|
1008
|
-
}, [editable, updateEditState]);
|
|
865
|
+
}, [editable, updateEditState, selectedNodeIds]);
|
|
1009
866
|
const xyflowEdgesBase = useMemo(() => {
|
|
1010
867
|
const converted = convertToXYFlowEdges(edges, configuration, violations);
|
|
1011
868
|
// Filter out edges connected to inactive or hidden nodes
|
|
@@ -1024,17 +881,6 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
1024
881
|
}
|
|
1025
882
|
return true;
|
|
1026
883
|
});
|
|
1027
|
-
// Debug: Log edge counts to help diagnose disappearing edges
|
|
1028
|
-
if (process.env.NODE_ENV === 'development') {
|
|
1029
|
-
console.log('[GraphRenderer] xyflowEdges computed:', {
|
|
1030
|
-
inputEdges: edges.length,
|
|
1031
|
-
convertedEdges: converted.length,
|
|
1032
|
-
filteredEdges: filtered.length,
|
|
1033
|
-
editable,
|
|
1034
|
-
propEdgesCount: propEdges.length,
|
|
1035
|
-
localEdgesCount: localEdges.length,
|
|
1036
|
-
});
|
|
1037
|
-
}
|
|
1038
884
|
const mappedEdges = filtered.map((edge) => {
|
|
1039
885
|
const animation = animationState.edgeAnimations[edge.id];
|
|
1040
886
|
const isSelected = selectedEdgeIds.has(edge.id);
|
|
@@ -1139,18 +985,18 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
|
|
|
1139
985
|
}
|
|
1140
986
|
}, 150);
|
|
1141
987
|
return () => clearTimeout(timeoutId);
|
|
1142
|
-
}, [fitViewToNodeIdsKey, fitViewToNodeIds, fitViewPadding, fitView, fitViewDuration, getNodes]);
|
|
988
|
+
}, [fitViewToNodeIdsKey, fitViewToNodeIds, fitViewPadding, fitView, fitViewDuration, getNodes, fitBounds]);
|
|
1143
989
|
// ============================================
|
|
1144
990
|
// RENDER
|
|
1145
991
|
// ============================================
|
|
1146
|
-
return (_jsxs(_Fragment, { children: [_jsxs(ReactFlow, { nodes: xyflowNodes, edges: xyflowEdges, nodeTypes: nodeTypes, edgeTypes: edgeTypes, minZoom: 0.1, maxZoom: 4, defaultEdgeOptions: { type: 'custom' }, onEdgeClick: onEdgeClick, onNodeClick: onNodeClick, onNodeDrag: handleNodeDrag, onNodeDragStop: handleNodeDragStop, proOptions: { hideAttribution: true }, nodesDraggable: editable, elementsSelectable:
|
|
992
|
+
return (_jsxs(_Fragment, { children: [_jsxs(ReactFlow, { nodes: xyflowNodes, edges: xyflowEdges, nodeTypes: nodeTypes, edgeTypes: edgeTypes, minZoom: 0.1, maxZoom: 4, defaultEdgeOptions: { type: 'custom' }, onEdgeClick: onEdgeClick, onNodeClick: onNodeClick, onNodeDoubleClick: onNodeDoubleClick, onNodeDrag: handleNodeDrag, onNodeDragStop: handleNodeDragStop, proOptions: { hideAttribution: true }, nodesDraggable: editable, elementsSelectable: editable, selectNodesOnDrag: false, nodesConnectable: editable, edgesReconnectable: editable, reconnectRadius: 25, elevateEdgesOnSelect: true, onNodesChange: handleNodesChange, onEdgesChange: handleEdgesChange, onConnect: handleConnect, onReconnectStart: handleReconnectStart, onReconnect: handleReconnect, onReconnectEnd: handleReconnectEnd, onPaneClick: onPaneClick, onSelectionChange: handleSelectionChange, panOnDrag: !editable, panOnScroll: true, zoomOnScroll: false, zoomOnPinch: true, selectionOnDrag: false, selectionKeyCode: null, multiSelectionKeyCode: "Shift", children: [showBackground && (_jsx(Background, { color: backgroundVariant === 'dots' ? theme.colors.border : theme.colors.textMuted, gap: backgroundGap ?? (backgroundVariant === 'dots' ? 16 : 50), size: backgroundVariant === 'dots' ? 1 : 0.5, variant: backgroundVariant === 'dots'
|
|
1147
993
|
? BackgroundVariant.Dots
|
|
1148
994
|
: backgroundVariant === 'lines'
|
|
1149
995
|
? BackgroundVariant.Lines
|
|
1150
996
|
: BackgroundVariant.Cross })), showControls && _jsx(Controls, { showZoom: true, showFitView: true, showInteractive: true }), showMinimap && (_jsx(MiniMap, { nodeColor: (node) => {
|
|
1151
997
|
const nodeData = node.data;
|
|
1152
998
|
return nodeData?.typeDefinition?.color || theme.colors.secondary;
|
|
1153
|
-
}, nodeBorderRadius: 2, pannable: true, zoomable: true })), showCenterIndicator && _jsx(CenterIndicator, { color: theme.colors.textMuted }), editable && alignmentGuides.length > 0 && (_jsx(AlignmentGuidesOverlay, { guides: alignmentGuides, color: theme.colors.primary }))] }, `${baseNodesKey}-${baseEdgesKey}`),
|
|
999
|
+
}, nodeBorderRadius: 2, pannable: true, zoomable: true })), showCenterIndicator && _jsx(CenterIndicator, { color: theme.colors.textMuted }), editable && alignmentGuides.length > 0 && (_jsx(AlignmentGuidesOverlay, { guides: alignmentGuides, color: theme.colors.primary }))] }, `${baseNodesKey}-${baseEdgesKey}`), pendingConnection && (_jsxs("div", { style: {
|
|
1154
1000
|
position: 'absolute',
|
|
1155
1001
|
top: '50%',
|
|
1156
1002
|
left: '50%',
|
|
@@ -1423,8 +1269,8 @@ export const GraphRenderer = forwardRef((props, ref) => {
|
|
|
1423
1269
|
}
|
|
1424
1270
|
const { configuration, nodes, edges } = canvasData;
|
|
1425
1271
|
// Extract only the props that inner component needs
|
|
1426
|
-
const { violations, configName, showMinimap, showControls, showBackground, backgroundVariant, backgroundGap, showCenterIndicator, showTooltips, fitViewDuration, highlightedNodeId, activeNodeIds, events, onEventProcessed, editable, onPendingChangesChange, onNodeClick,
|
|
1427
|
-
return (_jsx("div", { className: className, style: { width, height, position: 'relative' }, children: _jsx(ReactFlowProvider, { children: _jsx(GraphRendererInner, { configuration: configuration, nodes: nodes, edges: edges, violations: violations, configName: configName, showMinimap: showMinimap, showControls: showControls, showBackground: showBackground, backgroundVariant: backgroundVariant, backgroundGap: backgroundGap, showCenterIndicator: showCenterIndicator, showTooltips: showTooltips, fitViewDuration: fitViewDuration, highlightedNodeId: highlightedNodeId, activeNodeIds: activeNodeIds, events: events, onEventProcessed: onEventProcessed, editable: editable, onPendingChangesChange: onPendingChangesChange, editStateRef: editStateRef, onNodeClick: onNodeClick,
|
|
1272
|
+
const { violations, configName, showMinimap, showControls, showBackground, backgroundVariant, backgroundGap, showCenterIndicator, showTooltips, fitViewDuration, highlightedNodeId, activeNodeIds, events, onEventProcessed, editable, onPendingChangesChange, onNodeClick, fitViewToNodeIds, fitViewPadding, } = props;
|
|
1273
|
+
return (_jsx("div", { className: className, style: { width, height, position: 'relative' }, children: _jsx(ReactFlowProvider, { children: _jsx(GraphRendererInner, { configuration: configuration, nodes: nodes, edges: edges, violations: violations, configName: configName, showMinimap: showMinimap, showControls: showControls, showBackground: showBackground, backgroundVariant: backgroundVariant, backgroundGap: backgroundGap, showCenterIndicator: showCenterIndicator, showTooltips: showTooltips, fitViewDuration: fitViewDuration, highlightedNodeId: highlightedNodeId, activeNodeIds: activeNodeIds, events: events, onEventProcessed: onEventProcessed, editable: editable, onPendingChangesChange: onPendingChangesChange, editStateRef: editStateRef, onNodeClick: onNodeClick, fitViewToNodeIds: fitViewToNodeIds, fitViewPadding: fitViewPadding }) }) }));
|
|
1428
1274
|
});
|
|
1429
1275
|
GraphRenderer.displayName = 'GraphRenderer';
|
|
1430
1276
|
//# sourceMappingURL=GraphRenderer.js.map
|