diff --git a/SHA256SUMS b/SHA256SUMS index 58ad67b..e7c4dfd 100644 --- a/SHA256SUMS +++ b/SHA256SUMS @@ -19,13 +19,13 @@ d6a342605426357da7d2e65daa435e99d7234549cffa52e1a9229ef5bc36f33c plugin/ui/conf c98f34119436e3020ef20b325f91617943aefe662119cf76738e0226c2e91cbb plugin/ui/device.js 89b9d7994e7477e18c3f43e6f0975e04d5106056ba581b2964db0f39183d6f8a plugin/ui/hardware.js af631694fcd7da21b77b554e6ee1bf2eaa93bd46a0b8b543e367f032d3236ecb plugin/ui/index.js -9c1a488c99a61f78c3a6abaea9ce84e53fc6b73f36dc92c7365136231dc70058 plugin/ui/overview.js +67f4d59e288f5390400c52af6a509e940b3ed17f8f520d6bf8bcf7bd345f9336 plugin/ui/overview.js 422e1f8323d29a4be757f39e8b60addd7764c436a1302673809e0c547fce5ff4 plugin/ui/schema.js 1bee0f9e5656a52bc97d9fafffbf5157dae062888f618046ad09470dc2685f3c plugin/ui/services.js 6806df689f62de56f7b61f8b3cf3a33c494a09931a14f51d9d71c26d2c1f61ee plugin/ui/storage.js 061f5011b78cedcd0c69a32aa5106889d38f6863f4c613ae326cc9d16f90e2dd plugin/ui/styles.css 0b79b9c5b5f23727164e05b127caca72255416309166ba200ccbd15a9667473c plugin/ui/translations.js d5b22366a2c7b375e6f3e35cefb9f95da0ea3b8390b3ec4d1000492f00128f6e plugin/worker.py -4efdd82aac730361cde262fc55677e965588259064e68bb1b01831d1ba5a157d tests/browser_alert_semantics.cjs +173d0a6fad2f7b3cc70c81162c882675b16d581b762a5f86441613fdd5ece74e tests/browser_alert_semantics.cjs 40c038aa7689c127c0d90ddf390674f534a2bdee8fd3c344d09f8fb6d4bb3964 tests/test_metrics.py 40d10555aef08f8132f576976b7205b3e1c16d330196a11c6cc1c5cbc167c670 tests/test_storage_metrics.py diff --git a/plugin/ui/overview.js b/plugin/ui/overview.js index 17e9c1a..08bcc9e 100644 --- a/plugin/ui/overview.js +++ b/plugin/ui/overview.js @@ -35,5 +35,5 @@ export function agentHostCard(entry) { const hardwareNames = hardware.map(p => p.name).filter(Boolean).join(" · "); const percent = n => Number.isFinite(n) ? `${n.toFixed(1)}%` : "--"; const progress = n => Number.isFinite(n) ? meter(n) : ""; - return `

${esc(m.name || h.name || m.id)}

${esc(formatUptime(s.uptime_seconds))}
ID ${esc(m.id || h.id)}${appState.LANG === "zh" ? "主机名" : "Hostname"} ${esc(m.hostname || v.hostname || "--")}${esc(v.manufacturer || "")} ${esc(v.model || "--")}${appState.LANG === "zh" ? "序列号" : "Serial"} ${esc(v.serial || "--")}${appState.LANG === "zh" ? "硬件版本" : "Revision"} ${esc(v.revision || "--")}${esc(v.os || "--")}${appState.LANG === "zh" ? "内核" : "Kernel"} ${esc(v.kernel || "--")}${esc(v.architecture || "--")} · CPU ${esc(v.cpu_count || "--")}${appState.LANG === "zh" ? "程序版本" : "Agent"} ${esc(s.version || "--")}
${tr("在线")}
${tr("处理器负载")}
${percent(y.cpu_percent)}
${progress(y.cpu_percent)}
${appState.LANG === "zh" ? "频率" : "Frequency"} ${esc(y.cpu_freq_mhz)} MHz · ${esc(y.temperature_c)}°C${fanMetric(s.plugins || {})}
${tr("内存占用")}
${percent(y.memory_percent)}
${progress(y.memory_percent)}
${bytes(memUsed)} / ${bytes(memTotal)} · ${appState.LANG === "zh" ? "可用" : "Available"} ${bytes(y.memory_available_bytes)}
${tr("主网络")}
↓ ${bytes(n.rx_bytes_per_second)}/s · ↑ ${bytes(n.tx_bytes_per_second)}/s
${esc(n.interface || "--")} · ${n.kind === "WIF" ? `${esc(n.metric)} dBm · ` : n.link_speed_mbps ? `${esc(n.link_speed_mbps)} Mbps · ` : ""}${esc(n.ip_label)} ${esc(n.ip)} · ${n.link === true ? (appState.LANG === "zh" ? "已连接" : "Connected") : n.link === false ? (appState.LANG === "zh" ? "已断开" : "Disconnected") : (appState.LANG === "zh" ? "状态未确认" : "Unconfirmed")}
${Array.isArray(y.storage_inventory) ? storageCards(y,entry.snapshot?.resources) : `
${tr("磁盘占用")}
${percent(y.disk_percent)}
${progress(y.disk_percent)}
${bytes(diskUsed)} / ${bytes(diskTotal)} · ${appState.LANG === "zh" ? "剩余" : "Free"} ${bytes(y.disk_free_bytes)}
`}
${appState.LANG === "zh" ? "主要告警" : "Primary alert"}${esc(hardwareLabel)}
${esc(displayText)}
${hardwareNames ? `
${esc(hardwareNames)}
` : ""}
${(d.alerts || []).length || !dataIsCurrent(entry) || !Array.isArray(d.alerts) ? `
${tr("当前告警")}
${(d.alerts || []).length}
${(d.alerts || []).map((a) => esc(ownerName(a.id))).join(" · ") || tr("无告警")}
` : ""}
${tr("服务与进程监控")}${summaryStatus(monitorHealth(s.watches, dataIsCurrent(entry)), appState.LANG)}
${(s.watches || []).map((w) => `
${esc(w.name)} · ${esc(w.target)}${runtimeStatus(w.up, appState.LANG)}
`).join("") || `
${tr("暂无数据")}
`}
`; + return `

${esc(m.name || h.name || m.id)}

${esc(formatUptime(s.uptime_seconds))}
ID ${esc(m.id || h.id)}${appState.LANG === "zh" ? "主机名" : "Hostname"} ${esc(m.hostname || v.hostname || "--")}${esc(v.manufacturer || "")} ${esc(v.model || "--")}${appState.LANG === "zh" ? "序列号" : "Serial"} ${esc(v.serial || "--")}${appState.LANG === "zh" ? "硬件版本" : "Revision"} ${esc(v.revision || "--")}${esc(v.os || "--")}${appState.LANG === "zh" ? "内核" : "Kernel"} ${esc(v.kernel || "--")}${esc(v.architecture || "--")} · CPU ${esc(v.cpu_count || "--")}${appState.LANG === "zh" ? "程序版本" : "Agent"} ${esc(s.version || "--")}
${tr("在线")}
${tr("处理器负载")}
${percent(y.cpu_percent)}
${progress(y.cpu_percent)}
${appState.LANG === "zh" ? "频率" : "Frequency"} ${esc(y.cpu_freq_mhz)} MHz · ${esc(y.temperature_c)}°C${fanMetric(s.plugins || {})}
${tr("内存占用")}
${percent(y.memory_percent)}
${progress(y.memory_percent)}
${bytes(memUsed)} / ${bytes(memTotal)} · ${appState.LANG === "zh" ? "可用" : "Available"} ${bytes(y.memory_available_bytes)}
${tr("主网络")}
↓ ${bytes(n.rx_bytes_per_second)}/s · ↑ ${bytes(n.tx_bytes_per_second)}/s
${esc(n.interface || "--")} · ${n.kind === "WIF" ? `${esc(n.metric)} dBm · ` : n.link_speed_mbps ? `${esc(n.link_speed_mbps)} Mbps · ` : ""}${esc(n.ip_label)} ${esc(n.ip)} · ${n.link === true ? (appState.LANG === "zh" ? "已连接" : "Connected") : n.link === false ? (appState.LANG === "zh" ? "已断开" : "Disconnected") : (appState.LANG === "zh" ? "状态未确认" : "Unconfirmed")}
${Array.isArray(y.storage_inventory) ? storageCards(y,entry.snapshot?.resources) : `
${tr("磁盘占用")}
${percent(y.disk_percent)}
${progress(y.disk_percent)}
${bytes(diskUsed)} / ${bytes(diskTotal)} · ${appState.LANG === "zh" ? "剩余" : "Free"} ${bytes(y.disk_free_bytes)}
`}
${appState.LANG === "zh" ? "主要告警" : "Primary alert"}${hardwareState === "online" ? "" : `${esc(hardwareLabel)}`}
${esc(displayText)}
${hardwareNames ? `
${esc(hardwareNames)}
` : ""}
${(d.alerts || []).length || !dataIsCurrent(entry) || !Array.isArray(d.alerts) ? `
${tr("当前告警")}
${(d.alerts || []).length}
${(d.alerts || []).map((a) => esc(ownerName(a.id))).join(" · ") || tr("无告警")}
` : ""}
${tr("服务与进程监控")}${summaryStatus(monitorHealth(s.watches, dataIsCurrent(entry)), appState.LANG)}
${(s.watches || []).map((w) => `
${esc(w.name)} · ${esc(w.target)}${runtimeStatus(w.up, appState.LANG)}
`).join("") || `
${tr("暂无数据")}
`}
`; } diff --git a/tests/browser_alert_semantics.cjs b/tests/browser_alert_semantics.cjs index 7c4100e..370ea60 100644 --- a/tests/browser_alert_semantics.cjs +++ b/tests/browser_alert_semantics.cjs @@ -20,18 +20,17 @@ for(const width of [1440,768,390]){ await page.evaluate(p=>render('zh',p),hardware); const primary=page.locator('[data-refresh-group="display"]'); if((await primary.locator('.value').innerText())!=='OLED 正常主页 · RGB 全灭')throw Error('Merged OLED/RGB text'); - if((await primary.locator('.pi-alert-heading .semantic-status').innerText())!=='正常')throw Error('Missing hardware normal status'); - if((await primary.locator('.pi-alert-heading .semantic-status').getAttribute('data-semantic'))!=='normal')throw Error('Hardware status must use normal blue'); + if(await primary.locator('.pi-alert-heading .semantic-status').count())throw Error('Healthy hardware must not show redundant status'); if(await page.locator('[data-manage-plugin-host]').count())throw Error('Overview must not expose plugin management'); if(await page.locator('.group.action-row').count())throw Error('Standalone hardware row remains'); if(!(await primary.innerText()).includes('Yahboom RGB Cooling HAT'))throw Error('Hardware name missing'); - if(!(await primary.locator('.pi-alert-heading').evaluate(n=>Math.abs(n.lastElementChild.getBoundingClientRect().right-n.getBoundingClientRect().right)<1)))throw Error('Hardware status is not right aligned'); if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth))throw Error('Merged display overflow'); await page.screenshot({path:output+'/merged-'+width+'.png',fullPage:true}); } hardware.hat.online=false; await page.evaluate(p=>render('zh',p),hardware); if((await page.locator('.pi-alert-heading .semantic-status').innerText())!=='离线')throw Error('Offline hardware shown online'); +if(!(await page.locator('.pi-alert-heading').evaluate(n=>Math.abs(n.lastElementChild.getBoundingClientRect().right-n.getBoundingClientRect().right)<1)))throw Error('Hardware issue status is not right aligned'); if((await page.locator('[data-refresh-group="display"] .value').innerText()).includes('RGB 全灭'))throw Error('Stale RGB shown as current'); await page.evaluate(()=>render('zh',{})); if((await page.locator('.pi-alert-heading .semantic-status').innerText())!=='未接入')throw Error('Absent hardware shown online');