| ... | @@ -35,6 +35,7 @@ import { useRemoteOpenState, type RemoteOpenMode } from "../../remoteOpen"; | ... | @@ -35,6 +35,7 @@ import { useRemoteOpenState, type RemoteOpenMode } from "../../remoteOpen"; |
| 35 | import { usePrimaryEnvironmentId } from "../../state/environments"; | 35 | import { usePrimaryEnvironmentId } from "../../state/environments"; |
| 36 | import { useT3ProjectFileScripts } from "~/hooks/useT3ProjectFileScripts"; | 36 | import { useT3ProjectFileScripts } from "~/hooks/useT3ProjectFileScripts"; |
| 37 | import { useThreadActionMenu } from "~/hooks/useThreadActionMenu"; | 37 | import { useThreadActionMenu } from "~/hooks/useThreadActionMenu"; |
| | 38 | import { readLocalApi } from "~/localApi"; |
| 38 | import { threadEnvironment } from "../../state/threads"; | 39 | import { threadEnvironment } from "../../state/threads"; |
| 39 | import { useAtomCommand } from "../../state/use-atom-command"; | 40 | import { useAtomCommand } from "../../state/use-atom-command"; |
| 40 | import { observeResponsiveBreakpointFade, usePanelAnimationSettings } from "../../panelAnimations"; | 41 | import { observeResponsiveBreakpointFade, usePanelAnimationSettings } from "../../panelAnimations"; |
| ... | @@ -66,6 +67,7 @@ interface ChatHeaderProps { | ... | @@ -66,6 +67,7 @@ interface ChatHeaderProps { |
| 66 | gitCwd: string | null; | 67 | gitCwd: string | null; |
| 67 | readonly onOpenPullRequest?: ((number: number) => void) | undefined; | 68 | readonly onOpenPullRequest?: ((number: number) => void) | undefined; |
| 68 | onNewThreadInProject: () => void; | 69 | onNewThreadInProject: () => void; |
| | 70 | onOpenProjectSettings?: (() => void) | undefined; |
| 69 | onRunProjectScript: (script: ProjectScript) => void; | 71 | onRunProjectScript: (script: ProjectScript) => void; |
| 70 | onAddProjectScript: (input: NewProjectScriptInput) => Promise<ProjectScriptActionResult>; | 72 | onAddProjectScript: (input: NewProjectScriptInput) => Promise<ProjectScriptActionResult>; |
| 71 | onUpdateProjectScript: ( | 73 | onUpdateProjectScript: ( |
| ... | @@ -137,6 +139,7 @@ export const ChatHeader = memo(function ChatHeader({ | ... | @@ -137,6 +139,7 @@ export const ChatHeader = memo(function ChatHeader({ |
| 137 | gitCwd, | 139 | gitCwd, |
| 138 | onOpenPullRequest, | 140 | onOpenPullRequest, |
| 139 | onNewThreadInProject, | 141 | onNewThreadInProject, |
| | 142 | onOpenProjectSettings, |
| 140 | onRunProjectScript, | 143 | onRunProjectScript, |
| 141 | onAddProjectScript, | 144 | onAddProjectScript, |
| 142 | onUpdateProjectScript, | 145 | onUpdateProjectScript, |
| ... | @@ -275,15 +278,29 @@ export const ChatHeader = memo(function ChatHeader({ | ... | @@ -275,15 +278,29 @@ export const ChatHeader = memo(function ChatHeader({ |
| 275 | ); | 278 | ); |
| 276 | const handleHeaderContextMenu = useCallback( | 279 | const handleHeaderContextMenu = useCallback( |
| 277 | (event: ReactMouseEvent) => { | 280 | (event: ReactMouseEvent) => { |
| 278 | if (!isServerThread || renamingTitle !== null) return; | 281 | if (renamingTitle !== null) return; |
| 279 | // The right-side controls (git, scripts, open-in) keep their own | 282 | // The right-side controls (git, scripts, open-in) keep their own |
| 280 | // behavior; only the breadcrumb area opens the thread menu. | 283 | // behavior; only the breadcrumb area opens the thread menu. |
| 281 | if ((event.target as HTMLElement).closest("[data-chat-header-actions]")) return; | 284 | if ((event.target as HTMLElement).closest("[data-chat-header-actions]")) return; |
| | 285 | if (!isServerThread && onOpenProjectSettings === undefined) return; |
| 282 | cancelPendingTitleMenu(); | 286 | cancelPendingTitleMenu(); |
| 283 | event.preventDefault(); | 287 | event.preventDefault(); |
| | 288 | if (!isServerThread) { |
| | 289 | const api = readLocalApi(); |
| | 290 | if (!api) return; |
| | 291 | void api.contextMenu |
| | 292 | .show([{ id: "project-settings", label: "Project settings", icon: "settings" }], { |
| | 293 | x: event.clientX, |
| | 294 | y: event.clientY, |
| | 295 | }) |
| | 296 | .then((action) => { |
| | 297 | if (action === "project-settings") onOpenProjectSettings?.(); |
| | 298 | }); |
| | 299 | return; |
| | 300 | } |
| 284 | openMenu({ x: event.clientX, y: event.clientY }); | 301 | openMenu({ x: event.clientX, y: event.clientY }); |
| 285 | }, | 302 | }, |
| 286 | [cancelPendingTitleMenu, isServerThread, openMenu, renamingTitle], | 303 | [cancelPendingTitleMenu, isServerThread, onOpenProjectSettings, openMenu, renamingTitle], |
| 287 | ); | 304 | ); |
| 288 | const handleRenameKeyDown = useCallback( | 305 | const handleRenameKeyDown = useCallback( |
| 289 | (event: ReactKeyboardEvent<HTMLInputElement>) => { | 306 | (event: ReactKeyboardEvent<HTMLInputElement>) => { |