@@ -39,6 +39,7 @@ import {
3939 useRef ,
4040 useState ,
4141} from "react" ;
42+ import { createPortal } from "react-dom" ;
4243import { useMutation , useQuery , useQueryClient } from "@tanstack/react-query" ;
4344import { useDebouncedValue } from "@tanstack/react-pacer" ;
4445import { useNavigate } from "@tanstack/react-router" ;
@@ -236,6 +237,7 @@ import { hasCustomThreadTitle, normalizeThreadTitle } from "~/threadTitle";
236237import { resolveLiveModelSelection } from "~/modelSelection" ;
237238import { getProviderModelOptionsByProvider } from "~/providerModels" ;
238239import { enhancePrompt , type PromptEnhancementId } from "../promptEnhancement" ;
240+ import { resolveTerminalDockPlacement } from "~/desktopShellLayout" ;
239241
240242function preloadThreadTerminalDrawer ( ) {
241243 return import ( "./ThreadTerminalDrawer" ) ;
@@ -398,6 +400,8 @@ function normalizeVisibleInteractionMode(
398400interface ChatViewProps {
399401 threadId : ThreadId ;
400402 onMinimize ?: ( ( ) => void ) | undefined ;
403+ rightPanelOpen : boolean ;
404+ rightPanelTerminalDock : HTMLDivElement | null ;
401405}
402406
403407interface RunProjectScriptOptions {
@@ -408,7 +412,12 @@ interface RunProjectScriptOptions {
408412 rememberAsLastInvoked ?: boolean ;
409413}
410414
411- export default function ChatView ( { threadId, onMinimize } : ChatViewProps ) {
415+ export default function ChatView ( {
416+ threadId,
417+ onMinimize,
418+ rightPanelOpen,
419+ rightPanelTerminalDock,
420+ } : ChatViewProps ) {
412421 const clientMode = useClientMode ( ) ;
413422 const transportState = useTransportState ( ) ;
414423 const threads = useStore ( ( store ) => store . threads ) ;
@@ -4842,6 +4851,45 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
48424851 return < ChatHomeEmptyState /> ;
48434852 }
48444853
4854+ const terminalDockPlacement = resolveTerminalDockPlacement ( {
4855+ clientMode,
4856+ rightPanelOpen,
4857+ hasRightPanelTerminalDock : rightPanelTerminalDock !== null ,
4858+ } ) ;
4859+ const terminalDrawer =
4860+ activeProject && shouldMountTerminalDrawer ? (
4861+ < div style = { { display : terminalState . terminalOpen ? undefined : "none" } } >
4862+ < Suspense
4863+ fallback = { < TerminalDrawerLoadingFallback height = { terminalState . terminalHeight } /> }
4864+ >
4865+ < ThreadTerminalDrawer
4866+ key = { activeThread . id }
4867+ threadId = { activeThread . id }
4868+ cwd = { gitCwd ?? activeProject . cwd }
4869+ runtimeEnv = { threadTerminalRuntimeEnv }
4870+ height = { terminalState . terminalHeight }
4871+ terminalIds = { terminalState . terminalIds }
4872+ activeTerminalId = { terminalState . activeTerminalId }
4873+ terminalGroups = { terminalState . terminalGroups }
4874+ activeTerminalGroupId = { terminalState . activeTerminalGroupId }
4875+ focusRequestId = { terminalFocusRequestId }
4876+ onSplitTerminal = { splitTerminal }
4877+ onNewTerminal = { createNewTerminal }
4878+ splitShortcutLabel = { splitTerminalShortcutLabel ?? undefined }
4879+ newShortcutLabel = { newTerminalShortcutLabel ?? undefined }
4880+ closeShortcutLabel = { closeTerminalShortcutLabel ?? undefined }
4881+ onActiveTerminalChange = { activateTerminal }
4882+ onCloseTerminal = { closeTerminal }
4883+ onCollapseTerminal = { toggleTerminalVisibility }
4884+ onHeightChange = { setTerminalHeight }
4885+ onAddTerminalContext = { addTerminalContextToDraft }
4886+ onSendTerminalContext = { sendSelectedTerminalContext }
4887+ onPreviewUrl = { onPreviewUrl }
4888+ />
4889+ </ Suspense >
4890+ </ div >
4891+ ) : null ;
4892+
48454893 return (
48464894 < div className = "flex min-h-0 min-w-0 flex-1 flex-col overflow-x-hidden bg-background" >
48474895 { /* Top bar */ }
@@ -5873,38 +5921,9 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
58735921 { /* Terminal drawer – once mounted, stay mounted to avoid the
58745922 unmount/remount flicker when toggling visibility or switching threads.
58755923 We hide it with display:none when collapsed so the DOM is retained. */ }
5876- { activeProject && shouldMountTerminalDrawer ? (
5877- < div style = { { display : terminalState . terminalOpen ? undefined : "none" } } >
5878- < Suspense
5879- fallback = { < TerminalDrawerLoadingFallback height = { terminalState . terminalHeight } /> }
5880- >
5881- < ThreadTerminalDrawer
5882- key = { activeThread . id }
5883- threadId = { activeThread . id }
5884- cwd = { gitCwd ?? activeProject . cwd }
5885- runtimeEnv = { threadTerminalRuntimeEnv }
5886- height = { terminalState . terminalHeight }
5887- terminalIds = { terminalState . terminalIds }
5888- activeTerminalId = { terminalState . activeTerminalId }
5889- terminalGroups = { terminalState . terminalGroups }
5890- activeTerminalGroupId = { terminalState . activeTerminalGroupId }
5891- focusRequestId = { terminalFocusRequestId }
5892- onSplitTerminal = { splitTerminal }
5893- onNewTerminal = { createNewTerminal }
5894- splitShortcutLabel = { splitTerminalShortcutLabel ?? undefined }
5895- newShortcutLabel = { newTerminalShortcutLabel ?? undefined }
5896- closeShortcutLabel = { closeTerminalShortcutLabel ?? undefined }
5897- onActiveTerminalChange = { activateTerminal }
5898- onCloseTerminal = { closeTerminal }
5899- onCollapseTerminal = { toggleTerminalVisibility }
5900- onHeightChange = { setTerminalHeight }
5901- onAddTerminalContext = { addTerminalContextToDraft }
5902- onSendTerminalContext = { sendSelectedTerminalContext }
5903- onPreviewUrl = { onPreviewUrl }
5904- />
5905- </ Suspense >
5906- </ div >
5907- ) : null }
5924+ { terminalDockPlacement === "right-panel" && rightPanelTerminalDock && terminalDrawer
5925+ ? createPortal ( terminalDrawer , rightPanelTerminalDock )
5926+ : terminalDrawer }
59085927
59095928 < Dialog
59105929 open = { pendingProjectScriptRun !== null }
0 commit comments