@@ -2191,7 +2191,7 @@ function NodeCanvas() {
21912191 storeActions.updateNodeInstance(activeGraphId, instanceId, draft => {
21922192 draft.x = newX;
21932193 draft.y = newY;
2194- }, { isDragging: true, phase: 'move' });
2194+ }, { isDragging: true, phase: 'move', type: 'node_position' });
21952195 }
21962196 }, [activeGraphId, nodeById, gridMode, gridSize, storeActions]);
21972197
@@ -5061,7 +5061,7 @@ function NodeCanvas() {
50615061 const mouseCanvasX = (clientX - rect.left - panOffset.x) / zoomLevel + canvasSize.offsetX;
50625062 const mouseCanvasY = (clientY - rect.top - panOffset.y) / zoomLevel + canvasSize.offsetY;
50635063 const offset = { x: mouseCanvasX - nodeData.x, y: mouseCanvasY - nodeData.y };
5064- setDraggingNodeInfo({ instanceId, offset });
5064+ setDraggingNodeInfo({ instanceId, offset, initialPos: { x: nodeData.x, y: nodeData.y } });
50655065
50665066
50675067
@@ -6727,6 +6727,50 @@ function NodeCanvas() {
67276727
67286728 // Reset scale for dragged nodes
67296729 if (draggingNodeInfo) {
6730+ // --- Manual History Recording for Drag ---
6731+ const patches = [];
6732+ const inversePatches = [];
6733+ const movedNodeCount = 0;
6734+
6735+ // Helper to record patch if moved
6736+ const checkAndRecord = (id, initX, initY) => {
6737+ const node = nodes.find(n => n.id === id);
6738+ if (node && (Math.abs(node.x - initX) > 0.01 || Math.abs(node.y - initY) > 0.01)) {
6739+ patches.push({ op: 'replace', path: ['graphs', activeGraphId, 'instances', id, 'x'], value: node.x });
6740+ patches.push({ op: 'replace', path: ['graphs', activeGraphId, 'instances', id, 'y'], value: node.y });
6741+ inversePatches.push({ op: 'replace', path: ['graphs', activeGraphId, 'instances', id, 'x'], value: initX });
6742+ inversePatches.push({ op: 'replace', path: ['graphs', activeGraphId, 'instances', id, 'y'], value: initY });
6743+ return true;
6744+ }
6745+ return false;
6746+ };
6747+
6748+ if (draggingNodeInfo.relativeOffsets) {
6749+ // Multi-drag
6750+ checkAndRecord(draggingNodeInfo.primaryId, draggingNodeInfo.initialPrimaryPos.x, draggingNodeInfo.initialPrimaryPos.y);
6751+ Object.entries(draggingNodeInfo.relativeOffsets).forEach(([id, rel]) => {
6752+ checkAndRecord(id, draggingNodeInfo.initialPrimaryPos.x + rel.offsetX, draggingNodeInfo.initialPrimaryPos.y + rel.offsetY);
6753+ });
6754+ } else if (draggingNodeInfo.initialPos) { // Ensure we have initialPos (added in startDrag)
6755+ // Single drag
6756+ checkAndRecord(draggingNodeInfo.instanceId, draggingNodeInfo.initialPos.x, draggingNodeInfo.initialPos.y);
6757+ }
6758+ // Group member drag logic is complex and handled via memberOffsets - skipping exact history for grouped drag for now or assuming it relies on standard updates?
6759+ // Group member drag uses 'memberOffsets' in performDragUpdate. It updates positions.
6760+ // If we want to support that, we need initial positions there too.
6761+ // For now, focusing on standard node drag.
6762+
6763+ if (patches.length > 0) {
6764+ useHistoryStore.getState().pushAction({
6765+ domain: `graph-${activeGraphId}`,
6766+ actionType: 'node_position',
6767+ description: `Moved ${patches.length / 2} Node(s)`,
6768+ patches,
6769+ inversePatches
6770+ });
6771+ }
6772+ // -----------------------------------------
6773+
67306774 const instanceIdsToReset = new Set();
67316775 if (draggingNodeInfo.relativeOffsets) {
67326776 instanceIdsToReset.add(draggingNodeInfo.primaryId);
@@ -6751,7 +6795,7 @@ function NodeCanvas() {
67516795 activeGraphId,
67526796 id,
67536797 draft => { draft.scale = 1; },
6754- { phase: 'end', isDragging: false, finalize: shouldFinalize }
6798+ { phase: 'end', isDragging: false, finalize: shouldFinalize, ignore: true } // Ignore this scale update in history
67556799 );
67566800 if (shouldFinalize) finalizeSent = true;
67576801 }
0 commit comments