This commit is contained in:
@@ -24,11 +24,11 @@ See [storage behavior](docs/STORAGE.md), [release notes](RELEASE_NOTES.md), and
|
||||
|
||||
## Build
|
||||
|
||||
Current adapter version: **1.6.12**.
|
||||
Current adapter version: **1.6.13**.
|
||||
|
||||
```sh
|
||||
mkdir -p dist
|
||||
python3 package.py plugin dist/pigway-agent-1.6.12.zip
|
||||
python3 package.py plugin dist/pigway-agent-1.6.13.zip
|
||||
```
|
||||
|
||||
[Documentation](docs/README.md)
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
|
||||
磁盘呈现统一版本已上线,需要 Console v2.7.0:默认按设备返回顺序,同组支持上移/下移、显示名称及隐藏,所有显示偏好保存到 Console,首页与配置页共用。Agent 的名称和隐藏定义继续作为设备默认值保留。扫描仍只由配置页按钮触发。
|
||||
|
||||
当前 v1.6.12 支持统一磁盘显示设置与手动扫描,需要 Console v2.7.0、Agent v3.11.1;新磁盘仅手动发现,已知磁盘容量继续刷新。见 [磁盘发现说明](docs/STORAGE.md)。
|
||||
当前 v1.6.13 支持统一磁盘显示设置与手动扫描,需要 Console v2.7.0、Agent v3.11.1;新磁盘仅手动发现,已知磁盘容量继续刷新。见 [磁盘发现说明](docs/STORAGE.md)。
|
||||
|
||||
独立维护的树莓派接入插件:连接现有 PIGWay Raspberry Pi Agent,不在树莓派安装新进程。设备 API、状态转换、配置字段、服务/进程监控、硬件界面及其翻译均由本仓库维护。
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
```sh
|
||||
mkdir -p dist
|
||||
python3 package.py plugin dist/pigway-agent-1.6.12.zip
|
||||
python3 package.py plugin dist/pigway-agent-1.6.13.zip
|
||||
```
|
||||
|
||||
在控制中心的机器管理页面安装 ZIP,再启用。开发时可用 `PIGWAY_ADAPTER_PATH=/absolute/path/pigway-console-adapter-raspberry-pi/plugin` 加载源码;Docker 推荐使用持久化数据卷中的安装包。
|
||||
|
||||
+2
-4
@@ -1,5 +1,3 @@
|
||||
# pigway-console-adapter-raspberry-pi v1.6.12
|
||||
# pigway-console-adapter-raspberry-pi v1.6.13
|
||||
|
||||
正式 PIGWAY Brand Production v1.1 图形标、项目头像与来源说明随项目交付;中英文项目介绍页使用统一品牌图。本版以品牌资源和项目文档交付为主。
|
||||
|
||||
软件业务逻辑和设备控制边界沿用上一版本。Logo 使用已发布的 v1.1 原文件,不重新生成或修改颜色、比例。源码包保留 LICENSE 及原有第三方许可说明;插件 ZIP 保留对应许可证。
|
||||
系统配置新增 Gateway 访问地址,首页名称旁显示管理入口按钮;留空隐藏。地址保存在 Console,不改变监控 API 或设备配置;仅允许无账号密码的 HTTP(S) 根地址。
|
||||
|
||||
+7
-7
@@ -2,9 +2,9 @@
|
||||
5b30f5e166b59ce8e59437ebdd753a417e0c6c6776b19bb073832aa2ccc72faa .gitignore
|
||||
79f34290cfa1a6f0928162909848e6597d46183d0de6b213bf52b12546f5fc33 CONTRIBUTING.md
|
||||
6eb7728e6e73f9568ca6fd5ad6383d13ffc638f2870fefa2d86f72f39685c0fc LICENSE
|
||||
b4f23e1f87dfe3cc19384b421918631965fc6e2165996f3db383029099241eff README.md
|
||||
2cda0b9dcfe65270735e2ec9bfbd2fadac6556b231405d4fb21fda36aa824cbc README.zh-CN.md
|
||||
2d6de988d39aa8edc398f24bbb3e9906941e28eaf9b1c702876189ddc20c3ff7 RELEASE_NOTES.md
|
||||
4449d96f0c183340974d5e76e7cc108fe943bb9f330b8e8d67f1898587ced55f README.md
|
||||
785ce40174a026719c77370156fbaf7f2ffcafa81d1ba6d6be7b6a1c56989079 README.zh-CN.md
|
||||
b1cea2332e0836efd3b363bfacad2cfcca853d19295c11c2bf171ab6527fd6f1 RELEASE_NOTES.md
|
||||
6cead6c1378cd840f655adc3d467e2cd6fd3ab368d7200a3afbfe85d9ed159be SECURITY.md
|
||||
1f4df7c43b0f6d138ac40c130511646d6ee9f7f1d9010505479acc7fee2f0e63 docs/README.md
|
||||
45b7bfb3d8f414e28d50c1f160aee2af8e4150dcd24b815569d48765b1eb413f docs/STORAGE.md
|
||||
@@ -14,18 +14,18 @@ da6734d8a23305f6254c0936dadff4ec34977b4c934f5067186423c8cfce3fc7 docs/brand/pig
|
||||
0fa494a3fbd456c754bbea3f7f050be139e32e3b42b09a1ed953094087437210 docs/brand/pigway-logo.svg
|
||||
d081c599d821149853368b1a8637c57a16995344406ff5ec9d7619b66e0479b3 package.py
|
||||
6eb7728e6e73f9568ca6fd5ad6383d13ffc638f2870fefa2d86f72f39685c0fc plugin/LICENSE
|
||||
0374334d71bc844b8c67c8aa5af7b75343148e86983eb64a09d6de0ff02544f5 plugin/manifest.json
|
||||
d6a342605426357da7d2e65daa435e99d7234549cffa52e1a9229ef5bc36f33c plugin/ui/config.js
|
||||
84c1656efee3cb615269043e68815943e78d6abce2d381e426fbd35c0979ee83 plugin/manifest.json
|
||||
48ea998f0dd3a9efabc0957035782119f6e6b5b4a84db777b9c9e089ce47b0e6 plugin/ui/config.js
|
||||
c98f34119436e3020ef20b325f91617943aefe662119cf76738e0226c2e91cbb plugin/ui/device.js
|
||||
89b9d7994e7477e18c3f43e6f0975e04d5106056ba581b2964db0f39183d6f8a plugin/ui/hardware.js
|
||||
af631694fcd7da21b77b554e6ee1bf2eaa93bd46a0b8b543e367f032d3236ecb plugin/ui/index.js
|
||||
67f4d59e288f5390400c52af6a509e940b3ed17f8f520d6bf8bcf7bd345f9336 plugin/ui/overview.js
|
||||
914087ba4441832ac51e268542dc6d27a30371fc9cb2250cd84233dc8d00f6d9 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
|
||||
494c90f6d154edc64aad3169653cc08c7f5fd4a6613341b4c0ff10dd7e0e1cb5 tests/browser_alert_semantics.cjs
|
||||
a6c66ba9df4758ac7362016efaec37ac17b1235244885bf270cea418371dcaad tests/browser_alert_semantics.cjs
|
||||
40c038aa7689c127c0d90ddf390674f534a2bdee8fd3c344d09f8fb6d4bb3964 tests/test_metrics.py
|
||||
40d10555aef08f8132f576976b7205b3e1c16d330196a11c6cc1c5cbc167c670 tests/test_storage_metrics.py
|
||||
|
||||
+10
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "pigway-agent",
|
||||
"name": "PIGWay Raspberry Pi Agent",
|
||||
"version": "1.6.12",
|
||||
"version": "1.6.13",
|
||||
"protocol_version": 1,
|
||||
"entrypoint": "worker.py",
|
||||
"runtime": "python3",
|
||||
@@ -33,6 +33,15 @@
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"secret": true
|
||||
},
|
||||
"management_url": {
|
||||
"label": {
|
||||
"zh": "访问地址",
|
||||
"en": "Access URL"
|
||||
},
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"format": "http-origin"
|
||||
}
|
||||
},
|
||||
"ui": {
|
||||
|
||||
+29
-1
@@ -311,7 +311,7 @@ export function renderConfig() {
|
||||
);
|
||||
$("mainSavebar").classList.toggle(
|
||||
"hidden",
|
||||
["bulk_sync", "plugins"].includes(b.dataset.configSection),
|
||||
["bulk_sync", "plugins", "access"].includes(b.dataset.configSection),
|
||||
);
|
||||
if (b.dataset.configSection === "services") loadServices();
|
||||
if (b.dataset.configSection === "processes") loadProcesses();
|
||||
@@ -348,6 +348,7 @@ export function renderConfig() {
|
||||
bindBulkSync();
|
||||
updateConditional();
|
||||
addStorageSettings();
|
||||
installAccessSettings();
|
||||
}
|
||||
export function markChanged() {
|
||||
let n = 0;
|
||||
@@ -365,3 +366,30 @@ export function markChanged() {
|
||||
: tr("尚未修改");
|
||||
$("saveState").className = n ? "" : "muted";
|
||||
}
|
||||
|
||||
function installAccessSettings() {
|
||||
const host = appState.fleetHosts.find(h => h.id === appState.currentConfigHost);
|
||||
if (!host) return;
|
||||
$("configMenu").insertAdjacentHTML("beforeend", `<button data-config-section="access">${pluginText("访问地址", "Access URL")}</button>`);
|
||||
$("configRows").insertAdjacentHTML("beforeend", `<section class="config-page" data-config-page="access"><h2>${pluginText("访问地址", "Access URL")}</h2><p class="muted">${pluginText("设置 Gateway 管理页面地址,首页显示链接按钮;留空隐藏入口。", "Set the Gateway management URL to show a link on the overview. Leave blank to hide it.")}</p><div class="field"><label>${pluginText("访问地址", "Access URL")}<input id="gatewayAccessUrl" type="url" value="${esc(host.connection?.management_url || "")}" placeholder="https://gateway.example.com"></label></div><div class="action-row"><button id="saveGatewayAccess">${pluginText("保存访问地址", "Save access URL")}</button><span id="gatewayAccessMessage" role="status"></span></div></section>`);
|
||||
$("saveGatewayAccess").onclick = async () => {
|
||||
const button = $("saveGatewayAccess"), message = $("gatewayAccessMessage");
|
||||
const value = $("gatewayAccessUrl").value.trim();
|
||||
if (value) {
|
||||
try {
|
||||
const url = new URL(value);
|
||||
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.pathname !== "/" || url.search || url.hash) throw Error();
|
||||
} catch {
|
||||
message.textContent = pluginText("请使用不含路径或账号密码的 HTTP(S) 根地址", "Use an HTTP(S) origin without paths or credentials");
|
||||
message.className = "error"; return;
|
||||
}
|
||||
}
|
||||
button.disabled = true;
|
||||
try {
|
||||
const result = await get("/api/v1/hosts", {method: "PUT", headers: {"Content-Type": "application/json"}, body: JSON.stringify({operation: "save", id: host.id, adapter_id: host.adapter_id, connection: {management_url: value}})});
|
||||
appState.fleetHosts = result.hosts;
|
||||
message.textContent = pluginText("已保存", "Saved"); message.className = "success";
|
||||
} catch (error) { message.textContent = error.message; message.className = "error"; }
|
||||
finally { button.disabled = false; }
|
||||
};
|
||||
}
|
||||
|
||||
+11
-2
@@ -8,10 +8,19 @@ import { bytes, formatUptime, meter } from "/assets/js/overview.js";
|
||||
import { fanMetric } from "./hardware.js";
|
||||
import { ownerName, rgbName } from "./schema.js";
|
||||
|
||||
function managementLink(host) {
|
||||
try {
|
||||
const url = new URL(host.connection?.management_url);
|
||||
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password) return "";
|
||||
const label = appState.LANG === "zh" ? "打开 Gateway 管理界面" : "Open Gateway management";
|
||||
return `<a class="docker-icon" style="margin-left: -7px" href="${esc(url.href)}" target="_blank" rel="noopener noreferrer" title="${esc(label)}" aria-label="${esc(label)}"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M14 4h6v6M20 4l-10 10M11 4H4v16h16v-7"/></svg></a>`;
|
||||
} catch { return ""; }
|
||||
}
|
||||
|
||||
export function agentHostCard(entry) {
|
||||
const h = entry.host;
|
||||
if (!entry.online)
|
||||
return `<article class="panel host-panel offline-card"><div class="host-head"><div><h2>${esc(h.name || h.id)}</h2><div class="device-details"><span>ID ${esc(h.id)}</span><span>${esc(h.url || tr("本机"))}</span></div></div><span class="badge semantic-status" data-semantic="error">${tr("离线")}</span></div><div class="error">${esc(entry.error || tr("连接失败"))}</div></article>`;
|
||||
return `<article class="panel host-panel offline-card"><div class="host-head"><div><div class="host-title"><h2>${esc(h.name || h.id)}</h2>${managementLink(h)}</div><div class="device-details"><span>ID ${esc(h.id)}</span><span>${esc(h.url || tr("本机"))}</span></div></div><span class="badge semantic-status" data-semantic="error">${tr("离线")}</span></div><div class="error">${esc(entry.error || tr("连接失败"))}</div></article>`;
|
||||
const s = entry.status,
|
||||
y = s.system || {},
|
||||
n = s.network || {},
|
||||
@@ -35,5 +44,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 `<article class="panel host-panel"><div class="host-head"><div><div class="host-title"><h2>${esc(m.name || h.name || m.id)}</h2><span class="uptime-badge">${esc(formatUptime(s.uptime_seconds))}</span></div><div class="device-details"><span>ID ${esc(m.id || h.id)}</span><span>${appState.LANG === "zh" ? "主机名" : "Hostname"} ${esc(m.hostname || v.hostname || "--")}</span><span>${esc(v.manufacturer || "")} ${esc(v.model || "--")}</span><span>${appState.LANG === "zh" ? "序列号" : "Serial"} ${esc(v.serial || "--")}</span><span>${appState.LANG === "zh" ? "硬件版本" : "Revision"} ${esc(v.revision || "--")}</span><span>${esc(v.os || "--")}</span><span>${appState.LANG === "zh" ? "内核" : "Kernel"} ${esc(v.kernel || "--")}</span><span>${esc(v.architecture || "--")} · CPU ${esc(v.cpu_count || "--")}</span><span>${appState.LANG === "zh" ? "程序版本" : "Agent"} ${esc(s.version || "--")}</span></div></div><span class="badge semantic-status" data-semantic="online">${tr("在线")}</span></div><div class="host-grid"><div class="metric" data-refresh-group="system"><div class="muted">${tr("处理器负载")}</div><div class="value">${percent(y.cpu_percent)}</div>${progress(y.cpu_percent)}<div class="muted">${appState.LANG === "zh" ? "频率" : "Frequency"} ${esc(y.cpu_freq_mhz)} MHz · ${esc(y.temperature_c)}°C${fanMetric(s.plugins || {})}</div></div><div class="metric" data-refresh-group="system"><div class="muted">${tr("内存占用")}</div><div class="value">${percent(y.memory_percent)}</div>${progress(y.memory_percent)}<div class="muted">${bytes(memUsed)} / ${bytes(memTotal)} · ${appState.LANG === "zh" ? "可用" : "Available"} ${bytes(y.memory_available_bytes)}</div></div><div class="metric" data-refresh-group="network"><div class="muted">${tr("主网络")}</div><div class="value">↓ ${bytes(n.rx_bytes_per_second)}/s · ↑ ${bytes(n.tx_bytes_per_second)}/s</div><div class="muted">${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")}</div></div>${Array.isArray(y.storage_inventory) ? storageCards(y,entry.snapshot?.resources) : `<div class="metric" data-refresh-group="storage"><div class="muted">${tr("磁盘占用")}</div><div class="value">${percent(y.disk_percent)}</div>${progress(y.disk_percent)}<div class="muted">${bytes(diskUsed)} / ${bytes(diskTotal)} · ${appState.LANG === "zh" ? "剩余" : "Free"} ${bytes(y.disk_free_bytes)}</div></div>`}<div class="metric" data-refresh-group="display"><div class="pi-alert-heading"><span class="muted">${appState.LANG === "zh" ? "主要告警" : "Primary alert"}</span>${hardwareState === "online" ? "" : `<span class="semantic-status" data-semantic="${hardwareState === 'offline' ? 'error' : 'unknown'}">${esc(hardwareLabel)}</span>`}</div><div class="value">${esc(displayText)}</div>${hardwareNames ? `<div class="muted">${esc(hardwareNames)}</div>` : ""}</div>${(d.alerts || []).length || !dataIsCurrent(entry) || !Array.isArray(d.alerts) ? `<div class="metric" data-refresh-group="alerts"><div class="muted">${tr("当前告警")}</div><div class="value">${(d.alerts || []).length}</div><div class="muted">${(d.alerts || []).map((a) => esc(ownerName(a.id))).join(" · ") || tr("无告警")}</div></div>` : ""}</div><details class="group" data-overview-details="services"><summary class="smart-summary"><strong class="smart-summary-title">${tr("服务与进程监控")}</strong>${summaryStatus(monitorHealth(s.watches, dataIsCurrent(entry)), appState.LANG)}</summary><div style="margin-top:12px"><div class="rows">${(s.watches || []).map((w) => `<div class="row"><span>${esc(w.name)} · ${esc(w.target)}</span>${runtimeStatus(w.up, appState.LANG)}</div>`).join("") || `<div class="muted">${tr("暂无数据")}</div>`}</div></div></details></article>`;
|
||||
return `<article class="panel host-panel"><div class="host-head"><div><div class="host-title"><h2>${esc(m.name || h.name || m.id)}</h2>${managementLink(h)}<span class="uptime-badge">${esc(formatUptime(s.uptime_seconds))}</span></div><div class="device-details"><span>ID ${esc(m.id || h.id)}</span><span>${appState.LANG === "zh" ? "主机名" : "Hostname"} ${esc(m.hostname || v.hostname || "--")}</span><span>${esc(v.manufacturer || "")} ${esc(v.model || "--")}</span><span>${appState.LANG === "zh" ? "序列号" : "Serial"} ${esc(v.serial || "--")}</span><span>${appState.LANG === "zh" ? "硬件版本" : "Revision"} ${esc(v.revision || "--")}</span><span>${esc(v.os || "--")}</span><span>${appState.LANG === "zh" ? "内核" : "Kernel"} ${esc(v.kernel || "--")}</span><span>${esc(v.architecture || "--")} · CPU ${esc(v.cpu_count || "--")}</span><span>${appState.LANG === "zh" ? "程序版本" : "Agent"} ${esc(s.version || "--")}</span></div></div><span class="badge semantic-status" data-semantic="online">${tr("在线")}</span></div><div class="host-grid"><div class="metric" data-refresh-group="system"><div class="muted">${tr("处理器负载")}</div><div class="value">${percent(y.cpu_percent)}</div>${progress(y.cpu_percent)}<div class="muted">${appState.LANG === "zh" ? "频率" : "Frequency"} ${esc(y.cpu_freq_mhz)} MHz · ${esc(y.temperature_c)}°C${fanMetric(s.plugins || {})}</div></div><div class="metric" data-refresh-group="system"><div class="muted">${tr("内存占用")}</div><div class="value">${percent(y.memory_percent)}</div>${progress(y.memory_percent)}<div class="muted">${bytes(memUsed)} / ${bytes(memTotal)} · ${appState.LANG === "zh" ? "可用" : "Available"} ${bytes(y.memory_available_bytes)}</div></div><div class="metric" data-refresh-group="network"><div class="muted">${tr("主网络")}</div><div class="value">↓ ${bytes(n.rx_bytes_per_second)}/s · ↑ ${bytes(n.tx_bytes_per_second)}/s</div><div class="muted">${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")}</div></div>${Array.isArray(y.storage_inventory) ? storageCards(y,entry.snapshot?.resources) : `<div class="metric" data-refresh-group="storage"><div class="muted">${tr("磁盘占用")}</div><div class="value">${percent(y.disk_percent)}</div>${progress(y.disk_percent)}<div class="muted">${bytes(diskUsed)} / ${bytes(diskTotal)} · ${appState.LANG === "zh" ? "剩余" : "Free"} ${bytes(y.disk_free_bytes)}</div></div>`}<div class="metric" data-refresh-group="display"><div class="pi-alert-heading"><span class="muted">${appState.LANG === "zh" ? "主要告警" : "Primary alert"}</span>${hardwareState === "online" ? "" : `<span class="semantic-status" data-semantic="${hardwareState === 'offline' ? 'error' : 'unknown'}">${esc(hardwareLabel)}</span>`}</div><div class="value">${esc(displayText)}</div>${hardwareNames ? `<div class="muted">${esc(hardwareNames)}</div>` : ""}</div>${(d.alerts || []).length || !dataIsCurrent(entry) || !Array.isArray(d.alerts) ? `<div class="metric" data-refresh-group="alerts"><div class="muted">${tr("当前告警")}</div><div class="value">${(d.alerts || []).length}</div><div class="muted">${(d.alerts || []).map((a) => esc(ownerName(a.id))).join(" · ") || tr("无告警")}</div></div>` : ""}</div><details class="group" data-overview-details="services"><summary class="smart-summary"><strong class="smart-summary-title">${tr("服务与进程监控")}</strong>${summaryStatus(monitorHealth(s.watches, dataIsCurrent(entry)), appState.LANG)}</summary><div style="margin-top:12px"><div class="rows">${(s.watches || []).map((w) => `<div class="row"><span>${esc(w.name)} · ${esc(w.target)}</span>${runtimeStatus(w.up, appState.LANG)}</div>`).join("") || `<div class="muted">${tr("暂无数据")}</div>`}</div></div></details></article>`;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ const web=process.env.PIGWAY_WEB_ROOT || path.resolve(adapter,'../pigway-device-
|
||||
const output=adapter+'/.data/audit-validation';fs.mkdirSync(output,{recursive:true});
|
||||
(async()=>{const browser=await chromium.launch({headless:true});const page=await browser.newPage();let errors=[];page.on('pageerror',e=>errors.push(e.message));
|
||||
await page.route('http://audit.local/**',async route=>{const u=new URL(route.request().url());let body,type='text/javascript';
|
||||
if(u.pathname==='/'){type='text/html';body=`<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="stylesheet" href="/assets/css/base.css"><link rel="stylesheet" href="/assets/css/layout.css"><link rel="stylesheet" href="/assets/css/controls.css"><link rel="stylesheet" href="/plugin/styles.css"><main id="cards"></main><script type="module">import {agentHostCard} from '/plugin/overview.js';import {state} from '/assets/js/state.js';window.render=(lang,plugins={})=>{state.LANG=lang;document.querySelector('#cards').innerHTML=agentHostCard({host:{id:'gateway',name:'Gateway'},online:true,status:{version:'3.11.2',machine:{id:'gateway',name:'家庭网关 100%',hostname:'gateway'},device:{model:'Raspberry Pi 4',os:'Debian 13',architecture:'aarch64',cpu_count:4},system:{cpu_percent:12,memory_percent:25,temperature_c:42,cpu_freq_mhz:1500,memory_used_bytes:1000000,memory_total_bytes:4000000,memory_available_bytes:3000000,storage_inventory:[]},network:{interface:'eth0',kind:'ETH',link_speed_mbps:1000,link:true,ip_label:'IP4',ip:'192.168.1.2',rx_bytes_per_second:10,tx_bytes_per_second:20},display:{owner:'DISK_CRITICAL',alerts:[{id:'DISK_CRITICAL'}]},plugins,watches:[]}})};render('zh');</script>`;}
|
||||
if(u.pathname==='/'){type='text/html';body=`<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="stylesheet" href="/assets/css/base.css"><link rel="stylesheet" href="/assets/css/layout.css"><link rel="stylesheet" href="/assets/css/controls.css"><link rel="stylesheet" href="/plugin/styles.css"><main id="cards"></main><script type="module">import {agentHostCard} from '/plugin/overview.js';import {state} from '/assets/js/state.js';window.render=(lang,plugins={})=>{state.LANG=lang;document.querySelector('#cards').innerHTML=agentHostCard({host:{id:'gateway',name:'Gateway',connection:{management_url:'http://192.168.89.14'}},online:true,status:{version:'3.11.2',machine:{id:'gateway',name:'家庭网关 100%',hostname:'gateway'},device:{model:'Raspberry Pi 4',os:'Debian 13',architecture:'aarch64',cpu_count:4},system:{cpu_percent:12,memory_percent:25,temperature_c:42,cpu_freq_mhz:1500,memory_used_bytes:1000000,memory_total_bytes:4000000,memory_available_bytes:3000000,storage_inventory:[]},network:{interface:'eth0',kind:'ETH',link_speed_mbps:1000,link:true,ip_label:'IP4',ip:'192.168.1.2',rx_bytes_per_second:10,tx_bytes_per_second:20},display:{owner:'DISK_CRITICAL',alerts:[{id:'DISK_CRITICAL'}]},plugins,watches:[]}})};render('zh');</script>`;}
|
||||
else if(u.pathname==='/assets/js/state.js')body='export const state={LANG:"zh"};';
|
||||
else if(u.pathname==='/assets/js/i18n.js')body='export const tr=x=>x;';
|
||||
else if(u.pathname==='/assets/js/overview.js'){let source=fs.readFileSync(web+'/js/overview.js','utf8');body='import {state as appState} from "/assets/js/state.js";\n'+source.slice(source.indexOf('export function bytes'),source.indexOf('export const connectionLabels')); }
|
||||
@@ -13,6 +13,7 @@ else if(u.pathname==='/plugin/hardware.js')body='export const fanMetric=()=>"";e
|
||||
else {let file=u.pathname.startsWith('/plugin/')?adapter+'/plugin/ui/'+u.pathname.slice(8):web+'/'+u.pathname.replace('/assets/','');if(!fs.existsSync(file))throw Error(file);body=fs.readFileSync(file);if(file.endsWith('.css'))type='text/css';}
|
||||
await route.fulfill({status:200,contentType:type,body});});
|
||||
await page.goto('http://audit.local/');await page.waitForFunction(()=>typeof window.render==='function');
|
||||
await page.locator('a[href="http://192.168.89.14/"]').waitFor();
|
||||
for(const [name,width,height] of [['desktop',1440,1000],['tablet',768,1024],['mobile',390,844]]){await page.setViewportSize({width,height});for(const lang of ['zh','en']){await page.evaluate(lang=>render(lang),lang);await page.waitForTimeout(100);const text=await page.locator('body').innerText();if(!text.includes(lang==='zh'?'主要告警':'Primary alert'))throw Error('Missing label');if(text.includes('显示状态'))throw Error('Old label');if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth))throw Error('Overflow '+name);await page.screenshot({path:output+'/'+name+'-'+lang+'.png',fullPage:true});}}
|
||||
const hardware={hat:{name:'Yahboom RGB Cooling HAT',online:true,capabilities:{display:true,rgb:true},status:{available:true,oled_page:'NORMAL_HOME',rgb_mode:'OFF'}}};
|
||||
for(const width of [1440,768,390]){
|
||||
|
||||
Reference in New Issue
Block a user