-
-
Notifications
You must be signed in to change notification settings - Fork 40
Closed
Description
Issue:
The UI layout was resetting every time there was activity on the gateway, causing all dragged nodes to return to their default positions. Additionally, there was a "Cannot access 'setNodes' before initialization" error due to a circular dependency.
Changes Made:
- Fixed initialization order: Used the standard useNodesState hook first, then wrapped the onNodesChange callback to track user adjustments
- Preserved user-adjusted positions: The code now properly maintains node positions when users drag them around
- Maintained existing functionality: All other features like the chaser crab and real-time updates continue to work
How it works now:
• When you drag nodes to arrange them in the UI, those positions are remembered in a ref
• When new activity comes in from the gateway, existing nodes keep their user-adjusted positions
• Only newly added nodes get the default layout positions
• The chaser crab and other special elements continue to work as before
Code Changes:
// Store user-adjusted positions separately
const userNodePositionsRef = useRef<Map<string, { x: number; y: number }>>(new Map())
// Wrap onNodesChange to track user adjustments
const wrappedOnNodesChange = useCallback((changes: any[]) => {
// Process changes to track manual position adjustments
for (const change of changes) {
if (change.type === 'position' && change.dragging === false) {
// User finished dragging a node - save the new position
userNodePositionsRef.current.set(change.id, change.position)
} else if (change.type === 'position' && change.dragging === true) {
// During dragging, temporarily update the stored position
if (change.position) {
userNodePositionsRef.current.set(change.id, change.position)
}
}
}
// Apply the changes using the original onNodesChange
onNodesChange(changes)
}, [onNodesChange])
// Update layout nodes when they change (preserve chaser and user-adjusted positions)
useEffect(() => {
setNodes((nds) => {
// Get user-adjusted positions
const userAdjustedPositions = userNodePositionsRef.current
// Update nodes with preserved positions for existing nodes
const updatedNodes = layoutedNodes.map((layoutNode) => {
// Prioritize user-adjusted positions, fall back to existing if not user-adjusted
const userPosition = userAdjustedPositions.get(layoutNode.id)
if (userPosition) {
return { ...layoutNode, position: userPosition }
}
// Look for existing position in current nodes (if it existed before)
const existingNode = nds.find(n => n.id === layoutNode.id)
if (existingNode && existingNode.id !== CHASER_CRAB_ID) {
return { ...layoutNode, position: existingNode.position }
}
return layoutNode
})
// Find and preserve chaser node
const chaserNode = nds.find((n) => n.id === CHASER_CRAB_ID)
if (chaserNode) {
return [...updatedNodes, chaserNode]
}
const crab = crabRef.current
return [
...updatedNodes,
{
id: CHASER_CRAB_ID,
type: 'chaserCrab',
position: crab.position,
data: {
state: crab.state,
facingLeft: crab.facingLeft,
onClick: handleCrabClick,
},
draggable: false,
selectable: false,
zIndex: 1000,
},
]
})
setEdges(layoutedEdges)
}, [layoutedNodes, layoutedEdges, setNodes, setEdges, handleCrabClick])
return (
<div className="w-full h-full bg-shell-950 texture-grid relative">
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={wrappedOnNodesChange} // Use the wrapped handler
onEdgesChange={onEdgesChange}
onNodeClick={onNodeClick}
nodeTypes={nodeTypes}
fitView
fitViewOptions={{ padding: 0.2 }}
minZoom={0.1}
maxZoom={2}
proOptions={{ hideAttribution: true }}
>
These changes ensure that the UI layout remains stable and preserves user positioning preferences even when new data flows in from the gateway.
Metadata
Metadata
Assignees
Labels
No labels