From be4a0b292cd3677a3a7a3d693fbf70227b944164 Mon Sep 17 00:00:00 2001 From: SuperComboGamer Date: Sat, 13 Dec 2025 01:07:33 -0500 Subject: [PATCH] fix: split terminal inside current panel instead of at root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When clicking split on a terminal, the new terminal is now added as a sibling of that specific terminal rather than at the root of the layout tree. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../src/components/views/terminal-view.tsx | 9 ++-- apps/app/src/store/app-store.ts | 43 ++++++++++++++++--- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/apps/app/src/components/views/terminal-view.tsx b/apps/app/src/components/views/terminal-view.tsx index 038ae5cd..59410d7a 100644 --- a/apps/app/src/components/views/terminal-view.tsx +++ b/apps/app/src/components/views/terminal-view.tsx @@ -257,7 +257,8 @@ export function TerminalView() { }; // Create a new terminal session - const createTerminal = async (direction?: "horizontal" | "vertical") => { + // targetSessionId: the terminal to split (if splitting an existing terminal) + const createTerminal = async (direction?: "horizontal" | "vertical", targetSessionId?: string) => { try { const headers: Record = { "Content-Type": "application/json", @@ -278,7 +279,7 @@ export function TerminalView() { const data = await response.json(); if (data.success) { - addTerminalToLayout(data.data.id, direction); + addTerminalToLayout(data.data.id, direction, targetSessionId); } else { console.error("[Terminal] Failed to create session:", data.error); } @@ -358,8 +359,8 @@ export function TerminalView() { isActive={terminalState.activeSessionId === content.sessionId} onFocus={() => setActiveTerminalSession(content.sessionId)} onClose={() => killTerminal(content.sessionId)} - onSplitHorizontal={() => createTerminal("horizontal")} - onSplitVertical={() => createTerminal("vertical")} + onSplitHorizontal={() => createTerminal("horizontal", content.sessionId)} + onSplitVertical={() => createTerminal("vertical", content.sessionId)} isDragging={activeDragId === content.sessionId} isDropTarget={activeDragId !== null && activeDragId !== content.sessionId} fontSize={terminalFontSize} diff --git a/apps/app/src/store/app-store.ts b/apps/app/src/store/app-store.ts index 12547c6a..eed56d67 100644 --- a/apps/app/src/store/app-store.ts +++ b/apps/app/src/store/app-store.ts @@ -593,7 +593,7 @@ export interface AppActions { // Terminal actions setTerminalUnlocked: (unlocked: boolean, token?: string) => void; setActiveTerminalSession: (sessionId: string | null) => void; - addTerminalToLayout: (sessionId: string, direction?: "horizontal" | "vertical") => void; + addTerminalToLayout: (sessionId: string, direction?: "horizontal" | "vertical", targetSessionId?: string) => void; removeTerminalFromLayout: (sessionId: string) => void; swapTerminals: (sessionId1: string, sessionId2: string) => void; clearTerminalState: () => void; @@ -1534,7 +1534,7 @@ export const useAppStore = create()( }); }, - addTerminalToLayout: (sessionId, direction = "horizontal") => { + addTerminalToLayout: (sessionId, direction = "horizontal", targetSessionId) => { const current = get().terminalState; const newTerminal: TerminalPanelContent = { type: "terminal", sessionId, size: 50 }; @@ -1556,7 +1556,33 @@ export const useAppStore = create()( const activeTab = current.tabs.find(t => t.id === current.activeTabId); if (!activeTab) return; - const addToLayout = ( + // If targetSessionId is provided, find and split that specific terminal + const splitTargetTerminal = ( + node: TerminalPanelContent, + targetId: string, + targetDirection: "horizontal" | "vertical" + ): TerminalPanelContent => { + if (node.type === "terminal") { + if (node.sessionId === targetId) { + // Found the target - split it + return { + type: "split", + direction: targetDirection, + panels: [{ ...node, size: 50 }, newTerminal], + }; + } + // Not the target, return unchanged + return node; + } + // It's a split - recurse into panels + return { + ...node, + panels: node.panels.map(p => splitTargetTerminal(p, targetId, targetDirection)), + }; + }; + + // Legacy behavior: add to root layout (when no targetSessionId) + const addToRootLayout = ( node: TerminalPanelContent, targetDirection: "horizontal" | "vertical" ): TerminalPanelContent => { @@ -1583,9 +1609,14 @@ export const useAppStore = create()( }; }; - const newLayout = activeTab.layout - ? addToLayout(activeTab.layout, direction) - : { type: "terminal" as const, sessionId, size: 100 }; + let newLayout: TerminalPanelContent; + if (!activeTab.layout) { + newLayout = { type: "terminal", sessionId, size: 100 }; + } else if (targetSessionId) { + newLayout = splitTargetTerminal(activeTab.layout, targetSessionId, direction); + } else { + newLayout = addToRootLayout(activeTab.layout, direction); + } const newTabs = current.tabs.map(t => t.id === current.activeTabId ? { ...t, layout: newLayout } : t