From 1701160b8a8a113e3e62fe36773f3c737427107b Mon Sep 17 00:00:00 2001 From: Andy <119136210+AndyMik90@users.noreply.github.com> Date: Mon, 12 Jan 2026 23:45:15 +0100 Subject: [PATCH] fix(terminal): add collision detection for terminal drag and drop reordering (#985) * fix(terminal): add collision detection for terminal drag and drop reordering Add closestCenter collision detection to DndContext to fix terminal drag and drop swapping not detecting valid drop targets. The default rectIntersection algorithm required too much overlap for grid layouts. Co-Authored-By: Claude Opus 4.5 * fix(terminal): handle file drops when closestCenter returns sortable ID Address PR review feedback: - Fix file drop handling to work when closestCenter collision detection returns the sortable ID instead of the droppable ID - Add terminals to useCallback dependency array to prevent stale state Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Opus 4.5 --- .../src/renderer/components/TerminalGrid.tsx | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/apps/frontend/src/renderer/components/TerminalGrid.tsx b/apps/frontend/src/renderer/components/TerminalGrid.tsx index 2c2d4390..5c8ce4c2 100644 --- a/apps/frontend/src/renderer/components/TerminalGrid.tsx +++ b/apps/frontend/src/renderer/components/TerminalGrid.tsx @@ -12,7 +12,8 @@ import { PointerSensor, KeyboardSensor, useSensor, - useSensors + useSensors, + closestCenter, } from '@dnd-kit/core'; import { SortableContext, @@ -292,17 +293,22 @@ export function TerminalGrid({ projectPath, onNewTaskClick, isActive = false }: // Handle file drop on terminal const overId = over.id.toString(); - if (overId.startsWith('terminal-')) { - const terminalId = overId.replace('terminal-', ''); + let terminalId: string | null = null; - if (activeData?.path) { - // Quote the path if it contains spaces - const quotedPath = activeData.path.includes(' ') ? `"${activeData.path}"` : activeData.path; - // Insert the file path into the terminal with a trailing space - window.electronAPI.sendTerminalInput(terminalId, quotedPath + ' '); - } + if (overId.startsWith('terminal-')) { + terminalId = overId.replace('terminal-', ''); + } else if (terminals.some(t => t.id === overId)) { + // closestCenter might return the sortable ID instead of droppable ID + terminalId = overId; } - }, [reorderTerminals]); + + if (terminalId && activeData?.path) { + // Quote the path if it contains spaces + const quotedPath = activeData.path.includes(' ') ? `"${activeData.path}"` : activeData.path; + // Insert the file path into the terminal with a trailing space + window.electronAPI.sendTerminalInput(terminalId, quotedPath + ' '); + } + }, [reorderTerminals, terminals]); // Calculate grid layout based on number of terminals const gridLayout = useMemo(() => { @@ -358,6 +364,7 @@ export function TerminalGrid({ projectPath, onNewTaskClick, isActive = false }: return (