HH-749: fix 900px layout overflow

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
2026-08-27 23:17:48 +08:00
co-authored by multica-agent
parent 45853f4bce
commit 7462e1fb6e
7 changed files with 98 additions and 4 deletions
+1
View File
@@ -1,2 +1,3 @@
web/dist/
web/node_modules/
web/test-results/
+64
View File
@@ -22,6 +22,7 @@
"react-router-dom": "7.18.2"
},
"devDependencies": {
"@playwright/test": "1.62.1",
"@testing-library/dom": "10.4.1",
"@testing-library/react": "16.3.2",
"@vitejs/plugin-react": "6.1.0",
@@ -768,6 +769,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/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
@@ -2712,6 +2729,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",
+3 -1
View File
@@ -6,7 +6,8 @@
"scripts": {
"build": "vite build",
"dev": "vite",
"test": "vitest run"
"test": "vitest run",
"test:responsive": "playwright test"
},
"dependencies": {
"@emotion/react": "11.14.0",
@@ -23,6 +24,7 @@
"react-router-dom": "7.18.2"
},
"devDependencies": {
"@playwright/test": "1.62.1",
"@testing-library/dom": "10.4.1",
"@testing-library/react": "16.3.2",
"@vitejs/plugin-react": "6.1.0",
+12
View File
@@ -0,0 +1,12 @@
import { defineConfig } from '@playwright/test'
export default defineConfig({
testDir: './tests',
testMatch: '*.e2e.js',
use: { baseURL: 'http://127.0.0.1:4173', channel: 'chrome' },
webServer: {
command: 'npm run dev -- --host 127.0.0.1 --port 4173',
url: 'http://127.0.0.1:4173',
reuseExistingServer: true,
},
})
+2 -2
View File
@@ -116,7 +116,7 @@ export function BrowserList() {
<>
<Box component="header" sx={{ mb: 4 }}><Typography variant="h1">运行环境</Typography><Typography color="text.secondary" sx={{ mt: 1, fontSize: '1.05rem' }}>启动、停止并回收隔离的浏览器 Profile</Typography></Box>
<Paper component="form" onSubmit={createRuntime} variant="outlined" sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', md: 'minmax(220px, 1fr) minmax(220px, 1fr) 196px' }, gap: 3, alignItems: 'end', p: { xs: 2.5, md: 3 }, mb: 3.5 }}>
<Paper component="form" onSubmit={createRuntime} variant="outlined" sx={{ display: 'grid', gridTemplateColumns: { xs: 'minmax(0, 1fr)', md: 'repeat(2, minmax(0, 1fr))', lg: 'repeat(3, minmax(0, 1fr))' }, gap: 3, alignItems: 'end', p: { xs: 2.5, md: 3 }, mb: 3.5 }}>
<Stack spacing={1}>
<Typography component="label" htmlFor="runtime-name" variant="body2" fontWeight={650}>环境名称 <Box component="span" aria-hidden="true" color="error.main">*</Box></Typography>
<TextField id="runtime-name" required slotProps={{ htmlInput: { 'aria-label': '环境名称', pattern: '[a-z0-9](?:[a-z0-9]|-){0,31}' } }} value={name} onChange={event => setName(event.target.value)} placeholder="例如:account-a" />
@@ -125,7 +125,7 @@ export function BrowserList() {
<Typography component="label" htmlFor="runtime-seed" variant="body2" fontWeight={650}>Fingerprint Seed <Box component="span" aria-hidden="true" color="error.main">*</Box></Typography>
<TextField id="runtime-seed" required type="number" slotProps={{ htmlInput: { 'aria-label': 'Fingerprint Seed', min: 1, max: 2147483647 } }} value={seed} onChange={event => setSeed(event.target.value)} />
</Stack>
<Button type="submit" variant="contained" size="large" disabled={busy === 'create'} sx={{ minHeight: 56 }}>{busy === 'create' ? '创建中…' : '创建环境'}</Button>
<Button type="submit" variant="contained" size="large" disabled={busy === 'create'} sx={{ minHeight: 56, gridColumn: { md: '1 / -1', lg: 'auto' } }}>{busy === 'create' ? '创建中…' : '创建环境'}</Button>
</Paper>
{message ? <Alert severity="error" action={<Button color="inherit" size="small" onClick={() => { setLocalError(''); refetch() }}>重试</Button>} sx={{ mb: 2.5 }}>{message}</Alert> : null}
+1 -1
View File
@@ -66,7 +66,7 @@ export function CreatorHubLayout({ children }) {
{desktop ? <IconButton aria-label={collapsed ? '展开导航' : '收起导航'} onClick={() => setCollapsed(value => !value)} sx={{ position: 'absolute', right: 16, bottom: 24, color: '#a9b7cc', border: '1px solid #35506f' }}>{collapsed ? <ChevronRight /> : <ChevronLeft />}</IconButton> : null}
</Drawer>
<Box component="main" sx={{ width: desktop ? `calc(100% - ${width}px)` : '100%', mt: '70px', px: { xs: 2, sm: 3, lg: 4.5 }, py: { xs: 3, lg: 4.5 }, transition: theme.transitions.create('width') }}>
<Box component="main" sx={{ flex: 1, minWidth: 0, mt: '70px', px: { xs: 2, sm: 3, lg: 4.5 }, py: { xs: 3, lg: 4.5 }, transition: theme.transitions.create('width') }}>
<Box sx={{ width: '100%', maxWidth: 1280 }}>{children}</Box>
</Box>
</Box>
+15
View File
@@ -0,0 +1,15 @@
import { expect, test } from '@playwright/test'
test('keeps the create form inside a 900px viewport', async ({ page }) => {
await page.route('**/api/browsers', route => route.fulfill({ json: [] }))
await page.setViewportSize({ width: 900, height: 800 })
await page.goto('/')
await expect(page.getByRole('button', { name: '收起导航' }).first()).toBeVisible()
const createButton = page.getByRole('button', { name: '创建环境' })
await expect(createButton).toBeVisible()
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(900)
const box = await createButton.boundingBox()
expect(box).not.toBeNull()
expect(box.x + box.width).toBeLessThanOrEqual(900)
})