From efbee38ae1dbfabbb46b1a37cc671411e040d1a3 Mon Sep 17 00:00:00 2001 From: Code Queue Review Date: Sat, 23 May 2026 22:57:29 +0000 Subject: [PATCH] fix: widen M3 hardware status workspace --- scripts/src/dev-cloud-workbench-smoke-lib.mjs | 20 ++++----- web/hwlab-cloud-web/app.mjs | 41 +++++++++++++------ web/hwlab-cloud-web/index.html | 4 +- web/hwlab-cloud-web/scripts/check.mjs | 15 ++++--- web/hwlab-cloud-web/styles.css | 4 +- 5 files changed, 53 insertions(+), 31 deletions(-) diff --git a/scripts/src/dev-cloud-workbench-smoke-lib.mjs b/scripts/src/dev-cloud-workbench-smoke-lib.mjs index 9eec5b24..1c96d29f 100644 --- a/scripts/src/dev-cloud-workbench-smoke-lib.mjs +++ b/scripts/src/dev-cloud-workbench-smoke-lib.mjs @@ -579,7 +579,7 @@ function runStaticSmoke() { "aside#resource-explorer absent", "#explorer-resize absent", "resource tree / quick actions / capability cards absent", - "right side keeps a 560-760px M3 status workspace boundary through --right-width" + "right side keeps a 560-740px M3 status workspace boundary through --right-width" ] }); @@ -2313,19 +2313,19 @@ function hasResourceExplorerRemovalContract({ html, app, styles }) { /id=["']right-sidebar-resize["']/u.test(html) && /aria-label=["']拖拽调整右侧硬件状态栏宽度["']/u.test(html) && /aria-valuemin=["']560["']/u.test(html) && - /aria-valuemax=["']760["']/u.test(html) && - /aria-valuenow=["']620["']/u.test(html) && - /RIGHT_SIDEBAR_DEFAULT_WIDTH\s*=\s*620/u.test(app) && + /aria-valuemax=["']740["']/u.test(html) && + /aria-valuenow=["']728["']/u.test(html) && + /RIGHT_SIDEBAR_DEFAULT_WIDTH\s*=\s*728/u.test(app) && /RIGHT_SIDEBAR_MIN_WIDTH\s*=\s*560/u.test(app) && - /RIGHT_SIDEBAR_MAX_WIDTH\s*=\s*760/u.test(app) && + /RIGHT_SIDEBAR_MAX_WIDTH\s*=\s*740/u.test(app) && /function\s+initRightSidebarResize\s*\(/u.test(app) && /function\s+clampRightSidebarWidth\s*\(/u.test(app) && /function\s+rightSidebarResizeBounds\s*\(/u.test(app) && /setRightSidebarWidth\(drag\.startWidth \+ drag\.startX - event\.clientX/u.test(app) && /rightSidebarWidth:\s*state\.layout\.rightSidebarWidth/u.test(app) && - /--right-sidebar-width:\s*620px/u.test(styles) && + /--right-sidebar-width:\s*728px/u.test(styles) && /--right-sidebar-min-width:\s*560px/u.test(styles) && - /--right-sidebar-max-width:\s*760px/u.test(styles) && + /--right-sidebar-max-width:\s*740px/u.test(styles) && /--right-width:\s*clamp\(var\(--right-sidebar-min-width\),\s*var\(--right-sidebar-width\),\s*var\(--right-sidebar-max-width\)\)/u.test(styles) && /--right-width-expanded:\s*clamp\(var\(--right-sidebar-min-width\),\s*var\(--right-sidebar-width\),\s*var\(--right-sidebar-max-width\)\)/u.test(styles) && /\.right-sidebar-resize\s*\{[^}]*cursor:\s*col-resize;/su.test(styles) && @@ -4922,7 +4922,7 @@ export async function runM3StatusFixtureSmoke() { const desktop = await inspectM3StatusFixtureViewport(browser, server.url, { width: 1366, height: 768, - expectedRightWidthMin: 560 + expectedRightWidthMin: 720 }); const mobile = await inspectM3StatusFixtureViewport(browser, server.url, { width: 390, @@ -5978,7 +5978,7 @@ async function inspectM3StatusFixtureViewport(browser, url, viewport) { getComputedStyle(document.body).overflow === "hidden" && document.documentElement.scrollHeight <= document.documentElement.clientHeight + 2 && document.body.scrollHeight <= document.body.clientHeight + 2, - keysVisible: ["状态", "Gateway 在线", "BOX 在线", "DO1", "DI1", "runtime durable", "blocker"].every((term) => hardwareText.includes(term)), + keysVisible: ["状态", "Gateway 在线", "BOX 在线", "链路状态", "blocked", "DO1", "DI1", "runtime durable", "blocker"].every((term) => hardwareText.includes(term)), tabsVisible: ["总览", "Gateway-SIMU", "BOX-SIMU-1", "BOX-SIMU-2", "Patch Panel"].every((term) => tabLabels.includes(term)), blockedVisible: text.includes("runtime_durable_adapter_auth_blocked") && !text.includes("实况可信"), noHorizontalOverflow: @@ -7121,7 +7121,7 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) { const rightWidthTarget = isDesktop ? rightPanelStacked ? boxes.right?.width >= 560 && boxes.right?.width <= viewport.width - : boxes.right?.width >= (viewport.width >= 1500 ? 700 : 560) && boxes.right?.width <= 760 + : boxes.right?.width >= 720 && boxes.right?.width <= 740 : boxes.right?.width <= viewport.width && boxes.right?.width >= Math.max(0, viewport.width - 80); const rootAfterScrollAttempt = { windowScrollY: window.scrollY, diff --git a/web/hwlab-cloud-web/app.mjs b/web/hwlab-cloud-web/app.mjs index 328c6292..0e7db849 100644 --- a/web/hwlab-cloud-web/app.mjs +++ b/web/hwlab-cloud-web/app.mjs @@ -87,9 +87,9 @@ const LAYOUT_STORAGE_KEY = "hwlab.workbench.layout.v1"; const LEFT_SIDEBAR_DEFAULT_WIDTH = 92; const LEFT_SIDEBAR_MIN_WIDTH = 72; const LEFT_SIDEBAR_MAX_WIDTH = 180; -const RIGHT_SIDEBAR_DEFAULT_WIDTH = 620; +const RIGHT_SIDEBAR_DEFAULT_WIDTH = 728; const RIGHT_SIDEBAR_MIN_WIDTH = 560; -const RIGHT_SIDEBAR_MAX_WIDTH = 760; +const RIGHT_SIDEBAR_MAX_WIDTH = 740; const viewIds = new Set([...document.querySelectorAll("[data-view]")].map((view) => view.dataset.view)); let rpcSequence = 0; @@ -1455,10 +1455,11 @@ function hardwareOverviewGroups(status) { ["观测时间", status.observedAt ?? "未验证", "source"], ["Gateway 在线", `${onlineCount(status.gateways)} / ${status.gateways?.length ?? 0}`, onlineCount(status.gateways) === 2 ? "live" : "blocked"], ["BOX 在线", `${onlineCount(status.boxes)} / ${status.boxes?.length ?? 0}`, onlineCount(status.boxes) === 2 ? "live" : "blocked"], + ["链路状态", m3LinkStatus(status, patch), m3LinkTone(status, patch)], ["链路", `${M3_TRUSTED_ROUTE.fromResourceId}:${M3_TRUSTED_ROUTE.fromPort} -> ${M3_TRUSTED_ROUTE.patchPanelServiceId} -> ${M3_TRUSTED_ROUTE.toResourceId}:${M3_TRUSTED_ROUTE.toPort}`, patch.connectionActive ? "live" : "blocked"], ["DO1", valueLabel(do1), portTone(do1)], ["DI1", valueLabel(di1), portTone(di1)], - ["patchPanel connectionActive", String(Boolean(patch.connectionActive)), patch.connectionActive ? "live" : "blocked"], + ["接线盘连接", String(Boolean(patch.connectionActive)), patch.connectionActive ? "live" : "blocked"], ["runtime durable", trust.durableStatus ?? "blocked", trust.durableStatus === "green" ? "dev-live" : "blocked"], ["blocker", trust.blocker ?? status.blocker?.code ?? "none", trust.blocker || status.blocker ? "blocked" : "source"] ]), @@ -1474,11 +1475,11 @@ function hardwareOverviewGroups(status) { function hardwareGatewayGroups(status) { return (status.gateways ?? []).map((gateway) => hardwareKvGroup(`${gateway.id} / ${gateway.role}`, [ - ["online", String(Boolean(gateway.online)), gateway.online ? "live" : "blocked"], + ["在线", String(Boolean(gateway.online)), gateway.online ? "live" : "blocked"], ["sessionId", gateway.sessionId ?? "未验证", gateway.sessionId ? "source" : "blocked"], - ["lastSeenAt", gateway.lastSeenAt ?? status.observedAt ?? "未验证", gateway.online ? "live" : "source"], - ["source", gateway.sourceKind ?? "UNVERIFIED", sourceKindTone(gateway.sourceKind)], - ["lastError", gateway.lastError ?? "none", gateway.lastError ? "blocked" : "source"] + ["更新时间", gateway.lastSeenAt ?? status.observedAt ?? "未验证", gateway.online ? "live" : "source"], + ["来源", gateway.sourceKind ?? "UNVERIFIED", sourceKindTone(gateway.sourceKind)], + ["阻塞原因", gateway.lastError ?? "none", gateway.lastError ? "blocked" : "source"] ]) ); } @@ -1488,8 +1489,8 @@ function hardwareBoxGroups(status, resourceId) { const portEntries = Object.entries(box?.ports ?? {}); return [ hardwareKvGroup(box ? `${box.id} / ${box.resourceId}` : resourceId, [ - ["online", String(Boolean(box?.online)), box?.online ? "live" : "blocked"], - ["gateway", `${box?.gatewayId ?? "未验证"} / ${box?.gatewaySessionId ?? "未验证"}`, box?.gatewayId ? "source" : "blocked"], + ["在线", String(Boolean(box?.online)), box?.online ? "live" : "blocked"], + ["Gateway", `${box?.gatewayId ?? "未验证"} / ${box?.gatewaySessionId ?? "未验证"}`, box?.gatewayId ? "source" : "blocked"], ["更新时间", box?.observedAt ?? status.observedAt ?? "未验证", sourceKindTone(box?.sourceKind)], ["来源", box?.sourceKind ?? "UNVERIFIED", sourceKindTone(box?.sourceKind)], ...portEntries.map(([port, portState]) => [port, valueLabel(portState), portTone(portState)]), @@ -1505,16 +1506,32 @@ function hardwarePatchPanelGroups(status) { return [ hardwareKvGroup("hwlab-patch-panel", [ ["serviceId", patch.serviceId ?? M3_TRUSTED_ROUTE.patchPanelServiceId, "source"], - ["connectionActive", String(Boolean(patch.connectionActive)), patch.connectionActive ? "live" : "blocked"], + ["接线状态", m3LinkStatus(status, patch), m3LinkTone(status, patch)], + ["连接已激活", String(Boolean(patch.connectionActive)), patch.connectionActive ? "live" : "blocked"], ["connectionVersion", patch.connectionVersion ?? "未验证", patch.connectionVersion !== null && patch.connectionVersion !== undefined ? "source" : "blocked"], ["wiringConfigId", patch.wiringConfigId ?? "未验证", patch.wiringConfigId ? "source" : "blocked"], - ["lastSyncAt", patch.lastSyncAt ?? status.observedAt ?? "未验证", patch.connectionActive ? "live" : "source"], - ["lastError", patch.lastError ?? "none", patch.lastError ? "blocked" : "source"], + ["更新时间", patch.lastSyncAt ?? status.observedAt ?? "未验证", patch.connectionActive ? "live" : "source"], + ["阻塞原因", patch.lastError ?? "none", patch.lastError ? "blocked" : "source"], ["来源", patch.sourceKind ?? "UNVERIFIED", sourceKindTone(patch.sourceKind)] ]) ]; } +function m3LinkStatus(status, patch = status?.patchPanel ?? {}) { + if (status?.status === "error") return "error"; + if (status?.status === "unverified") return "unverified"; + if (status?.status === "live" && status?.trust?.durableStatus === "green" && patch.connectionActive === true) return "live"; + if (patch.connectionActive === true) return "blocked"; + return status?.status === "blocked" ? "blocked" : "unverified"; +} + +function m3LinkTone(status, patch) { + const linkStatus = m3LinkStatus(status, patch); + if (linkStatus === "live") return "live"; + if (linkStatus === "error" || linkStatus === "blocked") return "blocked"; + return "source"; +} + function hardwareKvGroup(title, rows) { const article = document.createElement("article"); article.className = "hardware-section hardware-kv-section"; diff --git a/web/hwlab-cloud-web/index.html b/web/hwlab-cloud-web/index.html index 306fbd77..8acfd9d6 100644 --- a/web/hwlab-cloud-web/index.html +++ b/web/hwlab-cloud-web/index.html @@ -235,8 +235,8 @@ aria-controls="hardware-sidebar" aria-orientation="vertical" aria-valuemin="560" - aria-valuemax="760" - aria-valuenow="620" + aria-valuemax="740" + aria-valuenow="728" title="拖拽调整右侧硬件状态栏宽度;用左右方向键微调,Home/End 到最小或最大。" >
diff --git a/web/hwlab-cloud-web/scripts/check.mjs b/web/hwlab-cloud-web/scripts/check.mjs index 659559fe..0a524da8 100644 --- a/web/hwlab-cloud-web/scripts/check.mjs +++ b/web/hwlab-cloud-web/scripts/check.mjs @@ -389,7 +389,8 @@ assert.match(functionBody(app, "fetchJson"), /timeoutMs\s*=\s*API_TIMEOUT_MS/); for (const hardwareTerm of [ "Gateway 在线", "BOX 在线", - "patchPanel connectionActive", + "链路状态", + "接线盘连接", "runtime durable", "DISABLED 后续能力", "SOURCE", @@ -475,8 +476,8 @@ assert.match(html, /aria-expanded="true"/); assert.match(html, /id="right-sidebar-resize"/); assert.match(html, /aria-label="拖拽调整右侧硬件状态栏宽度"/); assert.match(html, /aria-valuemin="560"/); -assert.match(html, /aria-valuemax="760"/); -assert.match(html, /aria-valuenow="620"/); +assert.match(html, /aria-valuemax="740"/); +assert.match(html, /aria-valuenow="728"/); assert.doesNotMatch(app, /setExplorerCollapsed|initExplorerResize|clampExplorerWidth|syncMobileExplorer|collapseExplorerAfterMobileAction/); assert.match(app, /LAYOUT_STORAGE_KEY\s*=\s*"hwlab\.workbench\.layout\.v1"/); assert.match(app, /leftSidebarCollapsed:\s*payload\.leftSidebarCollapsed === true/); @@ -497,9 +498,9 @@ assert.match(app, /ArrowRight/); assert.match(app, /event\.key === "Home"/); assert.match(app, /event\.key === "End"/); assert.doesNotMatch(styles, /--explorer-width|--explorer-min-width|--explorer-max-width|\.explorer|\.explorer-resize|\.quick-actions|\.resource-tree|\.tree-panel|\.tree-row|\.tree-label/); -assert.match(styles, /--right-sidebar-width:\s*620px/); +assert.match(styles, /--right-sidebar-width:\s*728px/); assert.match(styles, /--right-sidebar-min-width:\s*560px/); -assert.match(styles, /--right-sidebar-max-width:\s*760px/); +assert.match(styles, /--right-sidebar-max-width:\s*740px/); assert.match(styles, /--right-width:\s*clamp\(var\(--right-sidebar-min-width\),\s*var\(--right-sidebar-width\),\s*var\(--right-sidebar-max-width\)\)/); assert.match(styles, /--right-width-expanded:\s*clamp\(var\(--right-sidebar-min-width\),\s*var\(--right-sidebar-width\),\s*var\(--right-sidebar-max-width\)\)/); assert.match(styles, /--rail-collapsed-width:\s*44px/); @@ -701,7 +702,11 @@ assert.match(html, /data-hardware-tab="box2"[\s\S]*>BOX-SIMU-2<\/button>/); assert.match(html, /data-hardware-tab="patch"[\s\S]*>Patch Panel<\/button>/); assert.match(app, /function initHardwareTabs/); assert.match(app, /function hardwareKvGroup/); +assert.match(app, /function m3LinkStatus/); assert.match(app, /sourceFallbackM3Status/); +for (const hardwareLabel of ["链路状态", "接线盘连接", "在线", "更新时间", "阻塞原因", "接线状态", "连接已激活"]) { + assert.match(app, new RegExp(escapeRegExp(hardwareLabel)), `missing Chinese hardware label ${hardwareLabel}`); +} assert.match(styles, /\.hardware-status-tabs\s*\{/); assert.match(styles, /\.kv-list\s*\{/); assert.match(styles, /\.right-sidebar \.table-wrap\s*\{[^}]*overflow-x:\s*hidden;/s); diff --git a/web/hwlab-cloud-web/styles.css b/web/hwlab-cloud-web/styles.css index 435140c6..109b2bdc 100644 --- a/web/hwlab-cloud-web/styles.css +++ b/web/hwlab-cloud-web/styles.css @@ -21,9 +21,9 @@ --left-sidebar-min-width: 72px; --left-sidebar-max-width: 180px; --rail-width: 92px; - --right-sidebar-width: 620px; + --right-sidebar-width: 728px; --right-sidebar-min-width: 560px; - --right-sidebar-max-width: 760px; + --right-sidebar-max-width: 740px; --right-width: clamp(var(--right-sidebar-min-width), var(--right-sidebar-width), var(--right-sidebar-max-width)); --right-width-expanded: clamp(var(--right-sidebar-min-width), var(--right-sidebar-width), var(--right-sidebar-max-width)); --rail-collapsed-width: 44px;