diff --git a/packages/ui/src/features/browser-tabs/BrowserTabStrip.tsx b/packages/ui/src/features/browser-tabs/BrowserTabStrip.tsx index d9c0a55844..bd52aef08e 100644 --- a/packages/ui/src/features/browser-tabs/BrowserTabStrip.tsx +++ b/packages/ui/src/features/browser-tabs/BrowserTabStrip.tsx @@ -41,6 +41,7 @@ import { getLeafPanel } from "@posthog/ui/features/panels/panelStoreHelpers"; import { useSidebarStore } from "@posthog/ui/features/sidebar/sidebarStore"; import { taskDetailQuery } from "@posthog/ui/features/tasks/queries"; import { useTasks } from "@posthog/ui/features/tasks/useTasks"; +import { useIsWorkspaceCloudRun } from "@posthog/ui/features/workspace/useWorkspace"; import { useAppView } from "@posthog/ui/router/useAppView"; import { useMutation, useQuery } from "@tanstack/react-query"; import { @@ -197,6 +198,11 @@ export function BrowserTabStrip() { const channelsEnabled = useSidebarStore((s) => s.channelsEnabled) && bluebirdEnabled; + // A cloud run is read-only, so opening a new tab there makes no sense — hide + // the new-tab button and disable its Cmd/Ctrl+T shortcut. Off a task route + // params.taskId is undefined, so this is false and the button stays. + const isCloudRun = useIsWorkspaceCloudRun(params.taskId); + // The active channel sub-section (artifacts/history/context) is the // route segment after the channelId. Null when on the channel home or a // non-section route (canvas/task), so a channel-home tab labels by name. @@ -812,7 +818,11 @@ export function BrowserTabStrip() { e.preventDefault(); handleNewTab(); }, - { enableOnFormTags: true, enableOnContentEditable: true }, + { + enableOnFormTags: true, + enableOnContentEditable: true, + enabled: !isCloudRun, + }, ); // Cmd/Ctrl+W closes the active browser tab. Always preventDefault so Electron @@ -861,7 +871,7 @@ export function BrowserTabStrip() { onCloseOthers={handleCloseOthers} onCloseToRight={handleCloseToRight} onCloseToLeft={handleCloseToLeft} - onNewTab={handleNewTab} + onNewTab={isCloudRun ? undefined : handleNewTab} /> ); } diff --git a/packages/ui/src/features/browser-tabs/TabStrip.test.tsx b/packages/ui/src/features/browser-tabs/TabStrip.test.tsx index 7f54d2f152..30b2a1cf3a 100644 --- a/packages/ui/src/features/browser-tabs/TabStrip.test.tsx +++ b/packages/ui/src/features/browser-tabs/TabStrip.test.tsx @@ -72,6 +72,11 @@ describe("TabStrip", () => { expect(props.onNewTab).toHaveBeenCalledTimes(1); }); + it("hides the new-tab button when onNewTab is omitted", () => { + setup({ onNewTab: undefined }); + expect(screen.queryByLabelText("New tab")).toBeNull(); + }); + it("collapses a pinned tab to an icon-only pill without a close affordance", () => { setup({ tabs: [{ ...tabs[0], pinned: true }, tabs[1]], diff --git a/packages/ui/src/features/browser-tabs/TabStrip.tsx b/packages/ui/src/features/browser-tabs/TabStrip.tsx index 718ad8045c..1a89f5c3ce 100644 --- a/packages/ui/src/features/browser-tabs/TabStrip.tsx +++ b/packages/ui/src/features/browser-tabs/TabStrip.tsx @@ -42,7 +42,9 @@ export interface TabStripProps { activeTabId: string | null; onSelect: (tabId: string) => void; onClose: (tabId: string) => void; - onNewTab: () => void; + /** When omitted, the trailing new-tab button is hidden (e.g. on read-only + * cloud runs, where opening a tab makes no sense). */ + onNewTab?: () => void; onTogglePin: (tabId: string) => void; onCloseOthers: (tabId: string) => void; onCloseToRight: (tabId: string) => void; @@ -110,21 +112,23 @@ export function TabStrip({ onCloseToLeft={onCloseToLeft} /> ))} - - - - - } - /> - New tab - + {onNewTab && ( + + + + + } + /> + New tab + + )} );