diff --git a/backend/internal/web/dist/index.html b/backend/internal/web/dist/index.html index 4ef4a74..984f803 100644 --- a/backend/internal/web/dist/index.html +++ b/backend/internal/web/dist/index.html @@ -1,3 +1,3 @@ - - + +
diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 02dc729..34dbccc 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -18,6 +18,7 @@ "vite": "8.2.1" }, "devDependencies": { + "@playwright/test": "^1.62.1", "@types/react": "19.1.10", "@types/react-dom": "19.1.7", "vitest": "3.2.4" @@ -498,6 +499,22 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@playwright/test": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", + "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@reduxjs/toolkit": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.12.0.tgz", @@ -2417,6 +2434,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", + "integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { "version": "8.5.26", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", diff --git a/frontend/package.json b/frontend/package.json index 81e6a5f..0a54ffd 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1 +1 @@ -{"name":"codex-helper-ui","private":true,"version":"0.1.0","type":"module","scripts":{"dev":"vite","build":"tsc -b && vite build","test":"vitest run"},"dependencies":{"@vitejs/plugin-react":"latest","vite":"8.2.1","typescript":"7.0.2","react":"19.2.7","react-dom":"19.2.7","react-router-dom":"7.18.2","recharts":"3.1.2","lucide-react":"0.539.0"},"devDependencies":{"@types/react":"19.1.10","@types/react-dom":"19.1.7","vitest":"3.2.4"}} +{"name":"codex-helper-ui","private":true,"version":"0.1.0","type":"module","scripts":{"dev":"vite","build":"tsc -b && vite build","test":"vitest run --passWithNoTests --exclude 'tests/**'","test:e2e":"playwright test"},"dependencies":{"@vitejs/plugin-react":"latest","lucide-react":"0.539.0","react":"19.2.7","react-dom":"19.2.7","react-router-dom":"7.18.2","recharts":"3.1.2","typescript":"7.0.2","vite":"8.2.1"},"devDependencies":{"@playwright/test":"^1.62.1","@types/react":"19.1.10","@types/react-dom":"19.1.7","vitest":"3.2.4"}} diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts new file mode 100644 index 0000000..a90a387 --- /dev/null +++ b/frontend/playwright.config.ts @@ -0,0 +1,16 @@ +import { defineConfig, devices } from "@playwright/test"; + +export default defineConfig({ + testDir: "./tests", + fullyParallel: true, + use: { baseURL: "http://127.0.0.1:4173", trace: "retain-on-failure" }, + projects: [ + { name: "desktop", use: { ...devices["Desktop Chrome"] } }, + { name: "mobile", use: { ...devices["Pixel 7"] } }, + ], + webServer: { + command: "npm run dev -- --host 127.0.0.1 --port 4173", + url: "http://127.0.0.1:4173", + reuseExistingServer: true, + }, +}); diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 6c8b9ab..f1dea0c 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -492,51 +492,86 @@ const Chart = ({ data }: { data: Point[] }) => ( ); +type SettingsTab = "general" | "codex" | "telegram" | "smtp"; + +const settingsTabs: Array<{ + id: SettingsTab; + label: string; + icon: React.ReactNode; + content: React.ReactNode; +}> = [ + { id: "general", label: "通用", icon: