feat(settings): refine browser automation tab

This commit is contained in:
Tam Nhu Tran committed 2026-04-16 18:49:24 -04:00
1 parent 4e30c9b080
commit 06f6f5485f
6 files changed
+669 -391

No files matched your search

+10
View File
@@ -8,6 +8,7 @@
"@hookform/resolvers": "^5.2.2", "@hookform/resolvers": "^5.2.2",
"@nivo/core": "^0.99.0", "@nivo/core": "^0.99.0",
"@nivo/sankey": "^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-alert-dialog": "^1.1.15",
"@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-collapsible": "^1.1.12",
@@ -28,6 +29,7 @@
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"framer-motion": "^12.38.0",
"i18next": "^25.8.13", "i18next": "^25.8.13",
"lucide-react": "^0.556.0", "lucide-react": "^0.556.0",
"prism-react-renderer": "^2.4.1", "prism-react-renderer": "^2.4.1",
@@ -273,6 +275,8 @@
"@open-draft/until": ["@open-draft/until@2.1.0", "", {}, "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg=="], "@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/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=="], "@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=="], "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=="], "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=="], "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=="], "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=="], "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=="], "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", "@hookform/resolvers": "^5.2.2",
"@nivo/core": "^0.99.0", "@nivo/core": "^0.99.0",
"@nivo/sankey": "^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-alert-dialog": "^1.1.15",
"@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-collapsible": "^1.1.12",
@@ -42,6 +43,7 @@
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"framer-motion": "^12.38.0",
"i18next": "^25.8.13", "i18next": "^25.8.13",
"lucide-react": "^0.556.0", "lucide-react": "^0.556.0",
"prism-react-renderer": "^2.4.1", "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.', 'Configure Claude Browser Attach and Codex Browser Tools here, then use the guidance below to launch or verify each lane.',
readiness: 'Readiness', readiness: 'Readiness',
nextStep: 'Next step', nextStep: 'Next step',
technicalDetails: 'Technical Details',
diagnostics: 'Diagnostics',
actions: { actions: {
saveClaude: 'Save Claude settings', saveClaude: 'Save Claude settings',
saveCodex: 'Save Codex settings', saveCodex: 'Save Codex settings',
@@ -4846,6 +4848,8 @@ const resources = {
'在这里配置 Claude Browser Attach 和 Codex Browser Tools,然后按下方指引启动或验证每条路径。', '在这里配置 Claude Browser Attach 和 Codex Browser Tools,然后按下方指引启动或验证每条路径。',
readiness: '就绪状态', readiness: '就绪状态',
nextStep: '下一步', nextStep: '下一步',
technicalDetails: '技术细节',
diagnostics: '诊断信息',
actions: { actions: {
saveClaude: '保存 Claude 设置', saveClaude: '保存 Claude 设置',
saveCodex: '保存 Codex 设置', 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.', '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', readiness: 'Trạng thái sẵn sàng',
nextStep: 'Bước tiếp theo', nextStep: 'Bước tiếp theo',
technicalDetails: 'Chi tiết kỹ thuật',
diagnostics: 'Chẩn đoán',
actions: { actions: {
saveClaude: 'Lưu cấu hình Claude', saveClaude: 'Lưu cấu hình Claude',
saveCodex: 'Lưu cấu hình Codex', saveCodex: 'Lưu cấu hình Codex',
@@ -9783,6 +9789,8 @@ const resources = {
'ここで Claude Browser Attach と Codex Browser Tools を設定し、各レーンの起動や確認は下の案内を使ってください。', 'ここで Claude Browser Attach と Codex Browser Tools を設定し、各レーンの起動や確認は下の案内を使ってください。',
readiness: '準備状況', readiness: '準備状況',
nextStep: '次の手順', nextStep: '次の手順',
technicalDetails: '技術的な詳細',
diagnostics: '診断情報',
actions: { actions: {
saveClaude: 'Claude 設定を保存', saveClaude: 'Claude 設定を保存',
saveCodex: 'Codex 設定を保存', 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');
});
});