feat(settings): refine browser automation tab

This commit is contained in:
Tam Nhu Tran
2026-04-16 18:49:24 -04:00
parent 4e30c9b080
commit 06f6f5485f
6 changed files with 669 additions and 391 deletions
+10
View File
@@ -8,6 +8,7 @@
"@hookform/resolvers": "^5.2.2",
"@nivo/core": "^0.99.0",
"@nivo/sankey": "^0.99.0",
"@phosphor-icons/react": "^2.1.10",
"@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.12",
@@ -28,6 +29,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
"framer-motion": "^12.38.0",
"i18next": "^25.8.13",
"lucide-react": "^0.556.0",
"prism-react-renderer": "^2.4.1",
@@ -273,6 +275,8 @@
"@open-draft/until": ["@open-draft/until@2.1.0", "", {}, "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg=="],
"@phosphor-icons/react": ["@phosphor-icons/react@2.1.10", "", { "peerDependencies": { "react": ">= 16.8", "react-dom": ">= 16.8" } }, "sha512-vt8Tvq8GLjheAZZYa+YG/pW7HDbov8El/MANW8pOAz4eGxrwhnbfrQZq0Cp4q8zBEu8NIhHdnr+r8thnfRSNYA=="],
"@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
@@ -735,6 +739,8 @@
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
"framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
@@ -877,6 +883,10 @@
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="],
"motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"msw": ["msw@2.12.4", "", { "dependencies": { "@inquirer/confirm": "^5.0.0", "@mswjs/interceptors": "^0.40.0", "@open-draft/deferred-promise": "^2.2.0", "@types/statuses": "^2.0.6", "cookie": "^1.0.2", "graphql": "^16.12.0", "headers-polyfill": "^4.0.2", "is-node-process": "^1.2.0", "outvariant": "^1.4.3", "path-to-regexp": "^6.3.0", "picocolors": "^1.1.1", "rettime": "^0.7.0", "statuses": "^2.0.2", "strict-event-emitter": "^0.5.1", "tough-cookie": "^6.0.0", "type-fest": "^5.2.0", "until-async": "^3.0.2", "yargs": "^17.7.2" }, "peerDependencies": { "typescript": ">= 4.8.x" }, "optionalPeers": ["typescript"], "bin": { "msw": "cli/index.js" } }, "sha512-rHNiVfTyKhzc0EjoXUBVGteNKBevdjOlVC6GlIRXpy+/3LHEIGRovnB5WPjcvmNODVQ1TNFnoa7wsGbd0V3epg=="],
+2
View File
@@ -22,6 +22,7 @@
"@hookform/resolvers": "^5.2.2",
"@nivo/core": "^0.99.0",
"@nivo/sankey": "^0.99.0",
"@phosphor-icons/react": "^2.1.10",
"@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.12",
@@ -42,6 +43,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
"framer-motion": "^12.38.0",
"i18next": "^25.8.13",
"lucide-react": "^0.556.0",
"prism-react-renderer": "^2.4.1",
+8
View File
@@ -2433,6 +2433,8 @@ const resources = {
'Configure Claude Browser Attach and Codex Browser Tools here, then use the guidance below to launch or verify each lane.',
readiness: 'Readiness',
nextStep: 'Next step',
technicalDetails: 'Technical Details',
diagnostics: 'Diagnostics',
actions: {
saveClaude: 'Save Claude settings',
saveCodex: 'Save Codex settings',
@@ -4846,6 +4848,8 @@ const resources = {
'在这里配置 Claude Browser Attach 和 Codex Browser Tools,然后按下方指引启动或验证每条路径。',
readiness: '就绪状态',
nextStep: '下一步',
technicalDetails: '技术细节',
diagnostics: '诊断信息',
actions: {
saveClaude: '保存 Claude 设置',
saveCodex: '保存 Codex 设置',
@@ -7361,6 +7365,8 @@ const resources = {
'Cấu hình Claude Browser Attach và Codex Browser Tools tại đây, rồi dùng hướng dẫn bên dưới để khởi chạy hoặc kiểm tra từng luồng.',
readiness: 'Trạng thái sẵn sàng',
nextStep: 'Bước tiếp theo',
technicalDetails: 'Chi tiết kỹ thuật',
diagnostics: 'Chẩn đoán',
actions: {
saveClaude: 'Lưu cấu hình Claude',
saveCodex: 'Lưu cấu hình Codex',
@@ -9783,6 +9789,8 @@ const resources = {
'ここで Claude Browser Attach と Codex Browser Tools を設定し、各レーンの起動や確認は下の案内を使ってください。',
readiness: '準備状況',
nextStep: '次の手順',
technicalDetails: '技術的な詳細',
diagnostics: '診断情報',
actions: {
saveClaude: 'Claude 設定を保存',
saveCodex: 'Codex 設定を保存',
+25
View File
@@ -0,0 +1,25 @@
export type ClientPlatformKey = 'darwin' | 'linux' | 'win32';
type NavigatorWithUserAgentData = Pick<Navigator, 'platform' | 'userAgent'> & {
userAgentData?: {
platform?: string | null;
};
};
function normalizeClientPlatform(value: string): ClientPlatformKey {
const platform = value.toLowerCase();
if (platform.includes('mac')) return 'darwin';
if (platform.includes('win')) return 'win32';
return 'linux';
}
export function getClientPlatformKey(
nav: NavigatorWithUserAgentData = navigator as NavigatorWithUserAgentData
): ClientPlatformKey {
const userAgentDataPlatform =
typeof nav.userAgentData?.platform === 'string' ? nav.userAgentData.platform : '';
const fallbackPlatform =
typeof nav.platform === 'string' && nav.platform.trim() ? nav.platform : nav.userAgent;
return normalizeClientPlatform(userAgentDataPlatform || fallbackPlatform || '');
}
File diff suppressed because it is too large Load Diff
+32
View File
@@ -0,0 +1,32 @@
import { describe, expect, it } from 'vitest';
import { getClientPlatformKey } from '@/lib/platform';
describe('getClientPlatformKey', () => {
it('prefers navigator.userAgentData.platform when available', () => {
expect(
getClientPlatformKey({
userAgentData: { platform: 'macOS' },
platform: 'Win32',
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
})
).toBe('darwin');
});
it('falls back to navigator.platform when userAgentData is unavailable', () => {
expect(
getClientPlatformKey({
platform: 'Win32',
userAgent: 'Mozilla/5.0 (X11; Linux x86_64)',
})
).toBe('win32');
});
it('falls back to user-agent parsing when platform is unavailable', () => {
expect(
getClientPlatformKey({
platform: '',
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
})
).toBe('win32');
});
});