mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-07-11 00:45:42 +08:00
feat(browser-use): label Camoufox mode as co-browse
This commit is contained in:
@@ -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 }
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<MonitorPlay className="h-4 w-4 text-primary" />
|
||||
<h3 className="text-sm font-semibold text-foreground">Browser</h3>
|
||||
<h3 className="text-sm font-semibold text-foreground">{panelTitle}</h3>
|
||||
<Badge variant="outline" className={cn('text-[10px]', getRuntimeTone(status, isInstalling))}>
|
||||
{runtimeLabel}
|
||||
</Badge>
|
||||
@@ -499,7 +500,11 @@ export default function BrowserUsePanel({ isVisible, projectId, onShowSettings }
|
||||
{getEngineLabel(status?.backend)}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="mt-0.5 text-xs text-muted-foreground">Watch and manage browser sessions agents use to test real websites.</p>
|
||||
<p className="mt-0.5 text-xs text-muted-foreground">
|
||||
{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.'}
|
||||
</p>
|
||||
{isBackgroundRefreshing && (
|
||||
<div className="mt-1 flex items-center gap-1.5 text-xs text-muted-foreground">
|
||||
<RefreshCw className="h-3 w-3 animate-spin" />
|
||||
|
||||
@@ -66,6 +66,7 @@ export type MainContentHeaderProps = {
|
||||
selectedSession: ProjectSession | null;
|
||||
shouldShowTasksTab: boolean;
|
||||
shouldShowBrowserTab: boolean;
|
||||
shouldLabelBrowserTabAsCobrowse: boolean;
|
||||
isMobile: boolean;
|
||||
onMenuClick: () => void;
|
||||
};
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -61,6 +63,7 @@ export default function MainContentHeader({
|
||||
setActiveTab={setActiveTab}
|
||||
shouldShowTasksTab={shouldShowTasksTab}
|
||||
shouldShowBrowserTab={shouldShowBrowserTab}
|
||||
shouldLabelBrowserTabAsCobrowse={shouldLabelBrowserTabAsCobrowse}
|
||||
/>
|
||||
</div>
|
||||
{canScrollRight && (
|
||||
|
||||
@@ -12,6 +12,7 @@ type MainContentTabSwitcherProps = {
|
||||
setActiveTab: Dispatch<SetStateAction<AppTab>>;
|
||||
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({
|
||||
<PillBar>
|
||||
{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 (
|
||||
<Tooltip key={tab.id} content={displayLabel} position="bottom">
|
||||
|
||||
@@ -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({
|
||||
) : (
|
||||
<div className="min-w-0">
|
||||
<h2 className="text-sm font-semibold leading-tight text-foreground">
|
||||
{getTabTitle(activeTab, shouldShowTasksTab, t, pluginDisplayName)}
|
||||
{getTabTitle(activeTab, shouldShowTasksTab, shouldLabelBrowserTabAsCobrowse, t, coBrowseLabel, pluginDisplayName)}
|
||||
</h2>
|
||||
<div className="truncate text-[11px] leading-tight text-muted-foreground">{selectedProject.displayName}</div>
|
||||
</div>
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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() {
|
||||
<div className="space-y-4 px-4 py-4">
|
||||
<div className="flex flex-wrap gap-2 text-xs text-muted-foreground">
|
||||
<span className="rounded-md border border-border px-2 py-1">
|
||||
Backend: {effectiveBackend === 'camoufox-vnc' ? camoufoxLabel : 'Playwright'}
|
||||
Backend: {effectiveBackend === 'camoufox-vnc' ? `Co-browse (${camoufoxRuntimeLabel})` : 'Playwright'}
|
||||
</span>
|
||||
<span className="rounded-md border border-border px-2 py-1">
|
||||
Playwright: {runtimeLabel(status?.playwrightInstalled)}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"git": "Source Control",
|
||||
"tasks": "Tasks",
|
||||
"browser": "Browser",
|
||||
"coBrowse": "Co-browse",
|
||||
"computer": "Computer"
|
||||
},
|
||||
"status": {
|
||||
|
||||
Reference in New Issue
Block a user