| 1 | import { workspacePanelAriaMinWidth } from "../lib/workspaceLayout"; |
| 2 | import type { Translator } from "../lib/i18n"; |
| 3 | import type { Meta, RemoteHostView, RemoteConnectionStatus, WireCompletionSummary } from "../lib/types"; |
| 4 | import type { projectConversation } from "../app-runtime/conversationProjection"; |
| 5 | import type { useShellGeometry } from "../app-runtime/useShellGeometry"; |
| 6 | import type { useWorkspacePanelCommands } from "../app-runtime/useWorkspacePanelCommands"; |
| 7 | import type { useComposerInsertCommands } from "../app-runtime/useComposerInsertCommands"; |
| 8 | import type { WorkspaceVerificationRevealRequest } from "../components/WorkspacePanel"; |
| 9 | import type { WorkspaceDockRegionProps } from "./WorkspaceDockRegion"; |
| 10 | import type { AppBottomRegionsProps } from "./AppBottomRegions"; |
| 11 | import type { RightDockMode } from "../store/layout"; |
| 12 | import { defaultRightDockTreeWidth, TERMINAL_DEFAULT_HEIGHT, TERMINAL_MIN_HEIGHT } from "../store/layout"; |
| 13 | |
| 14 | type ShellGeometry = ReturnType<typeof useShellGeometry>; |
| 15 | type WorkspacePanelApi = ReturnType<typeof useWorkspacePanelCommands>; |
| 16 | type InsertCommands = ReturnType<typeof useComposerInsertCommands>; |
| 17 | type ConversationView = ReturnType<typeof projectConversation>; |
| 18 | type StatusBarProps = NonNullable<AppBottomRegionsProps["status"]>; |
| 19 | |
| 20 | /** Pure prop assembly for the dock and bottom regions; all ownership and |
| 21 | * geometry stays in the caller's hooks, only the object literals moved. */ |
| 22 | |
| 23 | export function buildWorkspaceDockProps(input: { |
| 24 | surface: { renderable: boolean; overlay: boolean; gridOpen: boolean }; |
| 25 | showContext: boolean; |
| 26 | remote: boolean; |
| 27 | t: Translator; |
| 28 | context: ConversationView["context"]; |
| 29 | sessionTurns: number; |
| 30 | contextRefreshKey: number; |
| 31 | workspaceKey: string; |
| 32 | workspaceScopeKey: string; |
| 33 | mode: RightDockMode; |
| 34 | meta: Meta | null | undefined; |
| 35 | tabId: string | undefined; |
| 36 | completionSummary: WireCompletionSummary | undefined; |
| 37 | turnStartAt: number; |
| 38 | layout: { treeWidth: number; previewWidth: number; maximized: boolean }; |
| 39 | geometry: ShellGeometry; |
| 40 | panels: WorkspacePanelApi; |
| 41 | inserts: InsertCommands; |
| 42 | verification: { verificationRevealRequest: WorkspaceVerificationRevealRequest | null; closeTurnResult?: () => void }; |
| 43 | onFileTreeRefresh: () => void; |
| 44 | onSessionRevertCommitted: WorkspaceDockRegionProps["workspace"]["onSessionRevertCommitted"]; |
| 45 | onOpenInTerminal: WorkspaceDockRegionProps["workspace"]["onOpenInTerminal"]; |
| 46 | }): WorkspaceDockRegionProps { |
| 47 | const { surface, geometry, panels } = input; |
| 48 | const workspacePanelResetWidth = defaultRightDockTreeWidth(); |
| 49 | const workspacePanelResizeMinWidth = workspacePanelAriaMinWidth(geometry.workspacePanelMinWidth, geometry.workspacePanelRenderWidth); |
| 50 | return { |
| 51 | visible: surface.renderable, |
| 52 | overlay: surface.overlay, |
| 53 | mode: input.mode, |
| 54 | showContext: input.showContext, |
| 55 | t: input.t, |
| 56 | onPickEntry: panels.openDockEntry, |
| 57 | remote: { onClose: panels.closeWorkspacePanel }, |
| 58 | context: { |
| 59 | ...input.context, sessionTurns: input.sessionTurns, |
| 60 | refreshKey: input.contextRefreshKey, |
| 61 | }, |
| 62 | workspaceKey: input.workspaceKey, |
| 63 | workspace: { |
| 64 | open: surface.renderable, tabId: input.tabId, cwd: input.meta?.cwd, |
| 65 | workspaceScopeKey: input.workspaceScopeKey, workspaceMemoryKey: input.workspaceKey, |
| 66 | dockTreeWidth: input.layout.treeWidth, dockPreviewWidth: input.layout.previewWidth, |
| 67 | onRestoreDockWidths: panels.restoreWorkspaceDockWidths, maximized: input.layout.maximized, |
| 68 | panelWidth: geometry.workspacePanelRenderWidth, onClose: panels.closeWorkspacePanel, |
| 69 | onToggleMaximized: panels.toggleWorkspaceMaximized, |
| 70 | onPreviewModeChange: panels.handleWorkspacePreviewModeChange, onAddToChat: input.inserts.addWorkspaceTextToComposer, |
| 71 | onAddCodeToChat: input.inserts.addWorkspaceCodeToComposer, onRequestPanelWidth: geometry.ensureWorkspacePanelWidth, |
| 72 | onFileTreeRefresh: input.onFileTreeRefresh, onSessionRevertCommitted: input.onSessionRevertCommitted, |
| 73 | onOpenInTerminal: input.onOpenInTerminal, |
| 74 | initialViewMode: input.mode === "changed" ? "changed" : "files", |
| 75 | completionSummary: input.completionSummary, turnStartAt: input.turnStartAt, |
| 76 | sessionPath: input.meta?.sessionPath, onDismissTurnResult: input.verification.closeTurnResult, |
| 77 | verificationRevealRequest: input.verification.verificationRevealRequest, |
| 78 | showViewTabs: false, |
| 79 | }, |
| 80 | resizer: surface.gridOpen ? { |
| 81 | min: workspacePanelResizeMinWidth, |
| 82 | max: Math.max(geometry.workspacePanelAvailableWidth, geometry.workspacePanelRenderWidth), |
| 83 | value: geometry.workspacePanelRenderWidth, |
| 84 | onPointerDown: geometry.startWorkspacePanelResize, |
| 85 | onKeyDown: geometry.resizeWorkspacePanelWithKeyboard, |
| 86 | onReset: () => geometry.setSavedWorkspacePanelWidth(workspacePanelResetWidth), |
| 87 | } : undefined, |
| 88 | }; |
| 89 | } |
| 90 | |
| 91 | export function buildBottomRegionsProps(input: { |
| 92 | t: Translator; |
| 93 | chatSurfaceVisible: boolean; |
| 94 | surfaceOpen: boolean; |
| 95 | contentVisible: boolean; |
| 96 | remote: boolean; |
| 97 | readOnly: boolean; |
| 98 | tabId: string | undefined; |
| 99 | meta: Meta | null | undefined; |
| 100 | fitEnabled: boolean; |
| 101 | liveTerminalHeight: number | null; |
| 102 | geometry: ShellGeometry; |
| 103 | terminal: { |
| 104 | onClose: () => void; |
| 105 | onAddOutput: (sessionId: string) => void; |
| 106 | onAddToChat: (text: string) => void; |
| 107 | }; |
| 108 | status?: { |
| 109 | base: ConversationView["status"]; |
| 110 | rewindCommitting: boolean; |
| 111 | sessionTurns: number; |
| 112 | labelStyle: StatusBarProps["labelStyle"]; |
| 113 | items: StatusBarProps["items"]; |
| 114 | extensionStatuses: StatusBarProps["extensionStatuses"]; |
| 115 | remoteHosts: RemoteHostView[]; |
| 116 | remoteStatuses: Record<string, RemoteConnectionStatus>; |
| 117 | onCancelJob: StatusBarProps["onCancelJob"]; |
| 118 | onCancelRuntimeJob: StatusBarProps["onCancelRuntimeJob"]; |
| 119 | onRevealRuntime: StatusBarProps["onRevealRuntime"]; |
| 120 | onConnectRemote: StatusBarProps["onConnectRemote"]; |
| 121 | onDisconnectRemote: StatusBarProps["onDisconnectRemote"]; |
| 122 | onManageRemote: StatusBarProps["onManageRemote"]; |
| 123 | onOpenRemote: StatusBarProps["onOpenRemote"]; |
| 124 | onOpenRemoteWorkspace: StatusBarProps["onOpenRemoteWorkspace"]; |
| 125 | }; |
| 126 | }): AppBottomRegionsProps { |
| 127 | const { geometry, status } = input; |
| 128 | return { |
| 129 | terminal: { |
| 130 | surfaceVisible: input.chatSurfaceVisible, |
| 131 | open: input.surfaceOpen, contentVisible: input.contentVisible, |
| 132 | remoteSurface: input.remote, t: input.t, |
| 133 | panel: { |
| 134 | tabId: input.tabId ?? "", cwd: input.meta?.cwd, readOnly: input.readOnly, |
| 135 | open: input.surfaceOpen, fitEnabled: input.fitEnabled, |
| 136 | onClose: input.terminal.onClose, |
| 137 | onAddOutput: input.terminal.onAddOutput, |
| 138 | onAddToChat: input.terminal.onAddToChat, |
| 139 | }, |
| 140 | resizer: { |
| 141 | min: TERMINAL_MIN_HEIGHT, max: geometry.terminalResizeMaxHeight, |
| 142 | value: input.liveTerminalHeight ?? geometry.terminalRenderHeight, |
| 143 | onPointerDown: geometry.startTerminalResize, onKeyDown: geometry.resizeTerminalWithKeyboard, |
| 144 | onReset: () => geometry.setSavedTerminalHeight(TERMINAL_DEFAULT_HEIGHT), |
| 145 | }, |
| 146 | }, |
| 147 | status: status ? { |
| 148 | ...status.base, |
| 149 | running: status.base.running || (!input.remote && status.rewindCommitting), |
| 150 | onCancelJob: status.onCancelJob, |
| 151 | onCancelRuntimeJob: status.onCancelRuntimeJob, |
| 152 | onRevealRuntime: status.onRevealRuntime, |
| 153 | sessionTurns: status.sessionTurns, |
| 154 | labelStyle: status.labelStyle, |
| 155 | items: status.items, |
| 156 | extensionStatuses: status.extensionStatuses, |
| 157 | onConnectRemote: status.onConnectRemote, |
| 158 | onDisconnectRemote: status.onDisconnectRemote, |
| 159 | onManageRemote: status.onManageRemote, |
| 160 | onOpenRemote: status.onOpenRemote, |
| 161 | onOpenRemoteWorkspace: status.onOpenRemoteWorkspace, |
| 162 | remoteHosts: status.remoteHosts, |
| 163 | remoteStatuses: status.remoteStatuses, |
| 164 | } : undefined, |
| 165 | }; |
| 166 | } |
| 167 |