From b389ecb24b64835b0b73f0222e9c02585580c749 Mon Sep 17 00:00:00 2001 From: Simos Mikelatos Date: Thu, 9 Jul 2026 20:23:31 +0000 Subject: [PATCH] feat(browser-use): label Camoufox mode as co-browse --- .../browser-use/view/BrowserUsePanel.tsx | 11 ++++++++--- src/components/main-content/types/types.ts | 1 + .../main-content/view/MainContent.tsx | 8 +++++++- .../view/subcomponents/MainContentHeader.tsx | 3 +++ .../subcomponents/MainContentTabSwitcher.tsx | 9 ++++++++- .../view/subcomponents/MainContentTitle.tsx | 17 +++++++++++++++-- src/components/settings/constants/constants.ts | 2 +- .../BrowserUseSettingsTab.tsx | 10 +++++----- src/i18n/locales/en/common.json | 1 + 9 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/components/browser-use/view/BrowserUsePanel.tsx b/src/components/browser-use/view/BrowserUsePanel.tsx index 799e7582..3450a212 100644 --- a/src/components/browser-use/view/BrowserUsePanel.tsx +++ b/src/components/browser-use/view/BrowserUsePanel.tsx @@ -161,7 +161,7 @@ function getStatusDot(status: BrowserUseSession['status']): string { } function getEngineLabel(backend?: BrowserUseStatus['backend'] | BrowserUseSession['backend']): string { - return backend === 'camoufox-vnc' ? 'Visible browser' : 'Playwright'; + return backend === 'camoufox-vnc' ? 'Co-browse' : 'Playwright'; } const PROMPTS = [ @@ -207,6 +207,7 @@ export default function BrowserUsePanel({ isVisible, projectId, onShowSettings } const isBackgroundRefreshing = isRefreshing && !isInitialLoading; const needsBrowserBinaries = Boolean(status?.enabled && !status.available); const usesLocalWindowViewer = status?.viewerMode === 'window'; + const panelTitle = status?.browserBackend === 'camoufox-vnc' ? 'Co-browse' : 'Browser'; const runtimeLabel = isInitialLoading ? 'Loading' : !status?.enabled @@ -491,7 +492,7 @@ export default function BrowserUsePanel({ isVisible, projectId, onShowSettings }
-

Browser

+

{panelTitle}

{runtimeLabel} @@ -499,7 +500,11 @@ export default function BrowserUsePanel({ isVisible, projectId, onShowSettings } {getEngineLabel(status?.backend)}
-

Watch and manage browser sessions agents use to test real websites.

+

+ {status?.browserBackend === 'camoufox-vnc' + ? 'Watch and manage co-browse sessions agents use to test real websites.' + : 'Watch and manage browser sessions agents use to test real websites.'} +

{isBackgroundRefreshing && (
diff --git a/src/components/main-content/types/types.ts b/src/components/main-content/types/types.ts index 6fd3ac7d..0c95ab8f 100644 --- a/src/components/main-content/types/types.ts +++ b/src/components/main-content/types/types.ts @@ -66,6 +66,7 @@ export type MainContentHeaderProps = { selectedSession: ProjectSession | null; shouldShowTasksTab: boolean; shouldShowBrowserTab: boolean; + shouldLabelBrowserTabAsCobrowse: boolean; isMobile: boolean; onMenuClick: () => void; }; diff --git a/src/components/main-content/view/MainContent.tsx b/src/components/main-content/view/MainContent.tsx index 6f683b95..dca07b37 100644 --- a/src/components/main-content/view/MainContent.tsx +++ b/src/components/main-content/view/MainContent.tsx @@ -59,6 +59,7 @@ function MainContent({ const { currentProject, setCurrentProject } = useTaskMaster() as TaskMasterContextValue; const { tasksEnabled, isTaskMasterInstalled } = useTasksSettings() as TasksSettingsContextValue; const [browserUseEnabled, setBrowserUseEnabled] = useState(false); + const [shouldLabelBrowserTabAsCobrowse, setShouldLabelBrowserTabAsCobrowse] = useState(false); const shouldShowTasksTab = Boolean(tasksEnabled && isTaskMasterInstalled); const shouldShowBrowserTab = browserUseEnabled; @@ -103,9 +104,13 @@ function MainContent({ try { const response = await authenticatedFetch('/api/browser-use/settings'); const data = await response.json(); - setBrowserUseEnabled(Boolean(response.ok && data?.success !== false && data?.data?.settings?.enabled)); + const settings = data?.data?.settings; + const enabled = Boolean(response.ok && data?.success !== false && settings?.enabled); + setBrowserUseEnabled(enabled); + setShouldLabelBrowserTabAsCobrowse(enabled && settings?.browserBackend === 'camoufox-vnc'); } catch { setBrowserUseEnabled(false); + setShouldLabelBrowserTabAsCobrowse(false); } }, []); @@ -149,6 +154,7 @@ function MainContent({ selectedSession={selectedSession} shouldShowTasksTab={shouldShowTasksTab} shouldShowBrowserTab={shouldShowBrowserTab} + shouldLabelBrowserTabAsCobrowse={shouldLabelBrowserTabAsCobrowse} isMobile={isMobile} onMenuClick={onMenuClick} /> diff --git a/src/components/main-content/view/subcomponents/MainContentHeader.tsx b/src/components/main-content/view/subcomponents/MainContentHeader.tsx index f75013ce..683abb70 100644 --- a/src/components/main-content/view/subcomponents/MainContentHeader.tsx +++ b/src/components/main-content/view/subcomponents/MainContentHeader.tsx @@ -11,6 +11,7 @@ export default function MainContentHeader({ selectedSession, shouldShowTasksTab, shouldShowBrowserTab, + shouldLabelBrowserTabAsCobrowse, isMobile, onMenuClick, }: MainContentHeaderProps) { @@ -44,6 +45,7 @@ export default function MainContentHeader({ selectedProject={selectedProject} selectedSession={selectedSession} shouldShowTasksTab={shouldShowTasksTab} + shouldLabelBrowserTabAsCobrowse={shouldLabelBrowserTabAsCobrowse} />
@@ -61,6 +63,7 @@ export default function MainContentHeader({ setActiveTab={setActiveTab} shouldShowTasksTab={shouldShowTasksTab} shouldShowBrowserTab={shouldShowBrowserTab} + shouldLabelBrowserTabAsCobrowse={shouldLabelBrowserTabAsCobrowse} />
{canScrollRight && ( diff --git a/src/components/main-content/view/subcomponents/MainContentTabSwitcher.tsx b/src/components/main-content/view/subcomponents/MainContentTabSwitcher.tsx index bffe39d6..6e312426 100644 --- a/src/components/main-content/view/subcomponents/MainContentTabSwitcher.tsx +++ b/src/components/main-content/view/subcomponents/MainContentTabSwitcher.tsx @@ -12,6 +12,7 @@ type MainContentTabSwitcherProps = { setActiveTab: Dispatch>; shouldShowTasksTab: boolean; shouldShowBrowserTab: boolean; + shouldLabelBrowserTabAsCobrowse: boolean; }; type BuiltInTab = { @@ -57,9 +58,11 @@ export default function MainContentTabSwitcher({ setActiveTab, shouldShowTasksTab, shouldShowBrowserTab, + shouldLabelBrowserTabAsCobrowse, }: MainContentTabSwitcherProps) { const { t } = useTranslation(); const { plugins } = usePlugins(); + const coBrowseLabel = t('tabs.coBrowse', { defaultValue: 'Co-browse' }); const builtInTabs: BuiltInTab[] = [ ...BASE_TABS, @@ -83,7 +86,11 @@ export default function MainContentTabSwitcher({ {tabs.map((tab) => { const isActive = tab.id === activeTab; - const displayLabel = tab.kind === 'builtin' ? t(tab.labelKey) : tab.label; + const displayLabel = tab.kind === 'plugin' + ? tab.label + : tab.id === 'browser' && shouldLabelBrowserTabAsCobrowse + ? coBrowseLabel + : t(tab.labelKey); return ( diff --git a/src/components/main-content/view/subcomponents/MainContentTitle.tsx b/src/components/main-content/view/subcomponents/MainContentTitle.tsx index 2e737680..f9c6044b 100644 --- a/src/components/main-content/view/subcomponents/MainContentTitle.tsx +++ b/src/components/main-content/view/subcomponents/MainContentTitle.tsx @@ -9,9 +9,17 @@ type MainContentTitleProps = { selectedProject: Project; selectedSession: ProjectSession | null; shouldShowTasksTab: boolean; + shouldLabelBrowserTabAsCobrowse: boolean; }; -function getTabTitle(activeTab: AppTab, shouldShowTasksTab: boolean, t: (key: string) => string, pluginDisplayName?: string) { +function getTabTitle( + activeTab: AppTab, + shouldShowTasksTab: boolean, + shouldLabelBrowserTabAsCobrowse: boolean, + t: (key: string) => string, + coBrowseLabel: string, + pluginDisplayName?: string, +) { if (activeTab.startsWith('plugin:') && pluginDisplayName) { return pluginDisplayName; } @@ -29,6 +37,9 @@ function getTabTitle(activeTab: AppTab, shouldShowTasksTab: boolean, t: (key: st } if (activeTab === 'browser') { + if (shouldLabelBrowserTabAsCobrowse) { + return coBrowseLabel; + } return t('tabs.browser'); } @@ -48,9 +59,11 @@ export default function MainContentTitle({ selectedProject, selectedSession, shouldShowTasksTab, + shouldLabelBrowserTabAsCobrowse, }: MainContentTitleProps) { const { t } = useTranslation(); const { plugins } = usePlugins(); + const coBrowseLabel = t('tabs.coBrowse', { defaultValue: 'Co-browse' }); const pluginDisplayName = activeTab.startsWith('plugin:') ? plugins.find((p) => p.name === activeTab.replace('plugin:', ''))?.displayName @@ -91,7 +104,7 @@ export default function MainContentTitle({ ) : (

- {getTabTitle(activeTab, shouldShowTasksTab, t, pluginDisplayName)} + {getTabTitle(activeTab, shouldShowTasksTab, shouldLabelBrowserTabAsCobrowse, t, coBrowseLabel, pluginDisplayName)}

{selectedProject.displayName}
diff --git a/src/components/settings/constants/constants.ts b/src/components/settings/constants/constants.ts index 366c5989..2e3b0a3f 100644 --- a/src/components/settings/constants/constants.ts +++ b/src/components/settings/constants/constants.ts @@ -33,7 +33,7 @@ export const SETTINGS_MAIN_TABS: SettingsMainTabMeta[] = [ { id: 'git', label: 'Git', keywords: 'git github commits', icon: GitBranch }, { id: 'api', label: 'API Tokens', keywords: 'api tokens auth keys', icon: KeyRound }, { id: 'tasks', label: 'Tasks', keywords: 'tasks taskmaster', icon: ListChecks }, - { id: 'browser', label: 'Browser', keywords: 'browser playwright chromium automation', icon: MonitorPlay }, + { id: 'browser', label: 'Browser', keywords: 'browser co-browse cobrowse playwright chromium camoufox automation', icon: MonitorPlay }, { id: 'notifications', label: 'Notifications', keywords: 'notifications alerts push', icon: Bell }, { id: 'plugins', label: 'Plugins', keywords: 'plugins extensions integrations', icon: Plug }, { id: 'about', label: 'About', keywords: 'about version info', icon: Info }, diff --git a/src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx b/src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx index 9402b5ed..75146d5f 100644 --- a/src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx +++ b/src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx @@ -133,7 +133,7 @@ export default function BrowserUseSettingsTab() { const selectedBackend = settings?.browserBackend || 'playwright'; const effectiveBackend = status?.backend || 'playwright'; const usesLocalWindowViewer = status?.viewerMode === 'window'; - const camoufoxLabel = usesLocalWindowViewer ? 'Camoufox (visible window)' : 'Camoufox + noVNC'; + const camoufoxRuntimeLabel = usesLocalWindowViewer ? 'Camoufox visible window' : 'Camoufox + noVNC'; const needsBrowserBinaries = Boolean(browserEnabled && status && !status.available); const runtimeLabel = (installed?: boolean) => { if (isStatusLoading && !status) { @@ -208,10 +208,10 @@ export default function BrowserUseSettingsTab() { }, { value: 'camoufox-vnc' as const, - label: camoufoxLabel, + label: 'Co-browse', description: usesLocalWindowViewer - ? 'Best when a person may need to log in or approve a step. The browser opens as a window on the machine running CloudCLI.' - : 'Best when a person may need to log in, approve a step, or watch the browser session live.', + ? 'Use Camoufox for co-browse sessions where a person may need to log in or approve a step on the machine running CloudCLI.' + : 'Use Camoufox for live co-browse sessions where a person may need to watch, log in, or approve a step.', icon: Eye, }, ]).map((option) => { @@ -293,7 +293,7 @@ export default function BrowserUseSettingsTab() {
- Backend: {effectiveBackend === 'camoufox-vnc' ? camoufoxLabel : 'Playwright'} + Backend: {effectiveBackend === 'camoufox-vnc' ? `Co-browse (${camoufoxRuntimeLabel})` : 'Playwright'} Playwright: {runtimeLabel(status?.playwrightInstalled)} diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index f8ab8444..e41209e1 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -24,6 +24,7 @@ "git": "Source Control", "tasks": "Tasks", "browser": "Browser", + "coBrowse": "Co-browse", "computer": "Computer" }, "status": {