返回 DeepSeek-Reasonix
chromeRegionBuilders.ts
根目录 / desktop / frontend / src / app-shell / chromeRegionBuilders.ts
1 import { defaultSidebarWidth, SIDEBAR_MAX_WIDTH } from "../store/layout";
2 import type { Translator } from "../lib/i18n";
3 import type { Meta, RemoteTabRefView, TabMeta } from "../lib/types";
4 import type { SidebarImTopicSource } from "../app-runtime/sidebarImProjection";
5 import type { useSessionBannerCommands } from "../app-runtime/useSessionBannerCommands";
6 import type { useProjectTopicCommands } from "../app-runtime/useProjectTopicCommands";
7 import type { useOnboardingCommands } from "../app-runtime/useOnboardingCommands";
8 import type { useShellGeometry } from "../app-runtime/useShellGeometry";
9 import type { useAppShellStores } from "../app-runtime/useAppShellStores";
10 import type { SessionStatusBannersProps } from "./SessionStatusBanners";
11 import type { SidebarRegionProps } from "./SidebarRegion";
12 import { sessionIdentityRoute } from "../lib/sessionIdentity";
13
14 type BannerCommands = ReturnType<typeof useSessionBannerCommands>;
15 type ShellStores = ReturnType<typeof useAppShellStores>;
16 type ProjectTopicCommands = ReturnType<typeof useProjectTopicCommands>;
17 type OnboardingCommands = ReturnType<typeof useOnboardingCommands>;
18
19 /** Pure prop assembly for the chrome regions (sidebar, app chrome, status
20 * banners); store and hook ownership stays with the caller. */
21
22 export function buildSidebarRegionProps(input: {
23 className: string;
24 shell: ShellStores;
25 t: Translator;
26 geometry: ReturnType<typeof useShellGeometry>;
27 projectTree: {
28 activeTab: TabMeta | undefined;
29 /** Owned by useActiveRemoteRef: this assembly must not rebuild it, because
30 * the project tree keys its tree walks on the object's identity. */
31 activeRemote: RemoteTabRefView | undefined;
32 activeScope?: string;
33 activeWorkspaceRoot?: string;
34 imTopicSources: Record<string, SidebarImTopicSource>;
35 refreshSignal: number;
36 searchExpanded: boolean;
37 searchFocusSignal: number;
38 showShortcutBadges: boolean;
39 shortcutPlatform: SidebarRegionProps["projectTree"]["shortcutPlatform"];
40 onVisibleTopicsChange: SidebarRegionProps["projectTree"]["onVisibleTopicsChange"];
41 draftSummaries: SidebarRegionProps["projectTree"]["draftSummaries"];
42 onOpenDraft: SidebarRegionProps["projectTree"]["onOpenDraft"];
43 };
44 topics: ProjectTopicCommands;
45 commands: {
46 onNewSession: () => void;
47 onOpenPalette: () => void;
48 onOpenTrash: () => void;
49 onOpenAutomation: () => void;
50 onOpenSettings: SidebarRegionProps["onOpenSettings"];
51 onOpenTopic: SidebarRegionProps["projectTree"]["onOpenTopic"];
52 };
53 paletteShortcut: string;
54 }): SidebarRegionProps {
55 const { geometry, topics, commands } = input;
56 const shell = input.shell;
57 return {
58 className: input.className,
59 collapsed: shell.sidebarCollapsed,
60 t: input.t,
61 onNewSession: commands.onNewSession,
62 onOpenPalette: commands.onOpenPalette,
63 paletteShortcut: input.paletteShortcut,
64 onOpenTrash: commands.onOpenTrash,
65 onOpenAutomation: commands.onOpenAutomation,
66 onOpenSettings: commands.onOpenSettings,
67 resize: {
68 min: geometry.sidebarResizeMinWidth, max: SIDEBAR_MAX_WIDTH, value: geometry.sidebarRenderWidth,
69 onPointerDown: geometry.startSidebarResize, onKeyDown: geometry.resizeSidebarWithKeyboard,
70 onReset: () => geometry.setExpandedSidebarWidth(defaultSidebarWidth()),
71 },
72 projectTree: {
73 activeScope: input.projectTree.activeScope ?? input.projectTree.activeTab?.scope,
74 activeWorkspaceRoot: input.projectTree.activeWorkspaceRoot ?? input.projectTree.activeTab?.workspaceRoot,
75 activeTopicId: input.projectTree.activeTab?.topicId, activeSessionPath: sessionIdentityRoute(input.projectTree.activeTab),
76 activeRemote: input.projectTree.activeRemote,
77 imTopicSources: input.projectTree.imTopicSources, onOpenTopic: commands.onOpenTopic,
78 onCreateTopic: topics.onCreateTopic, onCreateIsolatedWorktree: topics.onCreateIsolatedWorktree,
79 onTopicsChanged: topics.refreshProjectsAndTabs, onRenameTopic: topics.renameTopic, refreshSignal: input.projectTree.refreshSignal,
80 onAddProject: topics.onAddProject,
81 searchExpanded: input.projectTree.searchExpanded, searchFocusSignal: input.projectTree.searchFocusSignal,
82 showShortcutBadges: input.projectTree.showShortcutBadges, shortcutPlatform: input.projectTree.shortcutPlatform,
83 onVisibleTopicsChange: input.projectTree.onVisibleTopicsChange,
84 draftSummaries: input.projectTree.draftSummaries,
85 onOpenDraft: input.projectTree.onOpenDraft,
86 },
87 };
88 }
89
90 export function buildSessionStatusBannerProps(input: {
91 t: Translator;
92 activeTab: TabMeta | undefined;
93 leaseBlocked: SessionStatusBannersProps["leaseBlocked"];
94 meta: Meta | null | undefined;
95 configWarnings: SessionStatusBannersProps["configWarnings"];
96 dismissConfigWarnings: () => void;
97 updateChecksEnabled: boolean;
98 shell: ShellStores;
99 banners: BannerCommands;
100 onboarding: OnboardingCommands;
101 }): SessionStatusBannersProps {
102 const { banners, shell, onboarding } = input;
103 return {
104 t: input.t,
105 takenOver: Boolean(input.activeTab?.takenOver),
106 reclaimTabId: input.activeTab?.id ?? "",
107 reclaimBusyTabId: shell.reclaimBusyTab,
108 onReclaim: banners.reclaimSession,
109 leaseBlocked: input.leaseBlocked,
110 startupError: input.meta?.startupErr,
111 takeoverDialogTabId: shell.takeoverDialogTab,
112 onOpenTakeover: banners.openTakeoverDialog,
113 onCloseTakeover: banners.closeTakeoverDialog,
114 configWarnings: input.configWarnings,
115 onOpenConfigFile: banners.openConfigFile,
116 onReloadConfigFile: banners.reloadConfigFile,
117 onDismissConfigWarnings: input.dismissConfigWarnings,
118 providerSetupNeeded: shell.providerSetupNeeded,
119 needsOnboarding: shell.needsOnboarding,
120 onConfigureProvider: () => {
121 onboarding.chooseOnboardingProvider();
122 },
123 updateChecksEnabled: input.updateChecksEnabled,
124 onShowReleaseNotes: banners.showReleaseNotes,
125 };
126 }
127
128 /** The app/layout frame class lists; flags arrive from the caller's stores. */
129 export function buildAppShellClassNames(input: {
130 platform: string;
131 windowsFrameless: boolean;
132 browserPreview: boolean;
133 imDetailActive: boolean;
134 sidebarCollapsed: boolean;
135 sidebarResizing: boolean;
136 dockGridOpen: boolean;
137 dockOverlay: boolean;
138 terminalOpen: boolean;
139 terminalResizing: boolean;
140 dockOpen: boolean;
141 dockMaximized: boolean;
142 dockResizing: boolean;
143 }): { app: string; layout: string } {
144 return {
145 app: [
146 "app",
147 `app--${input.platform}`,
148 input.windowsFrameless ? "app--windows-frameless" : "",
149 input.browserPreview ? "app--browser-preview" : "",
150 "app--workbench",
151 ].filter(Boolean).join(" "),
152 layout: [
153 "layout",
154 "layout--workbench",
155 input.imDetailActive ? "layout--statusbar-hidden" : "",
156 input.sidebarCollapsed ? "layout--sidebar-collapsed" : "",
157 input.sidebarResizing ? "layout--resizing layout--sidebar-resizing" : "",
158 input.dockGridOpen ? "layout--workspace-open" : "",
159 input.dockOverlay ? "layout--workspace-overlay" : "",
160 "layout--terminal-drawer-open",
161 input.terminalOpen ? "layout--terminal-drawer-expanded" : "",
162 input.terminalResizing ? "layout--terminal-resizing" : "",
163 input.dockOpen && input.dockMaximized ? "layout--workspace-maximized" : "",
164 input.dockResizing ? "layout--resizing layout--workspace-resizing" : "",
165 ]
166 .filter(Boolean)
167 .join(" "),
168 };
169 }
170
170 lines TYPESCRIPT