From 15f002361458aa5b505461b930fdfc0e772d417e Mon Sep 17 00:00:00 2001 From: justme Date: Wed, 21 Oct 2026 11:55:50 +0800 Subject: [PATCH] web: unify Agent management and add a draggable link board Replace Probe pages with directed Agent links, shared deployment controls and unified display data. Add node dragging, canvas pan and zoom, saved layouts, and per-direction link controls. --- web/README.md | 6 +- web/admin/src/App.tsx | 8 +- web/admin/src/BackendUpdateNotice.tsx | 2 +- web/admin/src/PasskeyNotice.tsx | 2 +- web/admin/src/Setup.tsx | 2 +- web/admin/src/admin.css | 290 ++++++++++++ web/admin/src/pages/AgentDetail.tsx | 42 +- web/admin/src/pages/Agents.tsx | 6 +- web/admin/src/pages/CapabilityPicker.tsx | 2 +- web/admin/src/pages/JoinTokenCreated.tsx | 21 +- web/admin/src/pages/LinkBoard.tsx | 250 +++++++++++ web/admin/src/pages/Links.tsx | 110 +++++ web/admin/src/pages/OwnerPicker.tsx | 2 +- web/admin/src/pages/ProbeDetail.tsx | 120 ----- web/admin/src/pages/Probes.tsx | 380 ---------------- web/admin/src/pages/System.tsx | 13 +- web/admin/src/pages/Tasks.tsx | 2 +- web/admin/src/pages/Tests.tsx | 27 +- web/admin/src/pages/Trust.tsx | 4 +- web/display/src/LineStrips.tsx | 4 +- web/display/src/display.css | 4 +- web/display/src/lib.tsx | 2 +- web/display/src/live.ts | 35 +- web/display/src/pages/Compare.tsx | 54 +-- web/display/src/pages/Host.tsx | 2 +- web/display/src/pages/Line.tsx | 18 +- web/display/src/pages/Overview.tsx | 56 +-- web/shared/api/schema.ts | 533 ++++++----------------- web/shared/api/types.ts | 5 +- web/shared/i18n.ts | 22 +- web/shared/nodes.tsx | 4 +- web/shared/ui/index.tsx | 2 +- 32 files changed, 937 insertions(+), 1093 deletions(-) create mode 100644 web/admin/src/pages/LinkBoard.tsx create mode 100644 web/admin/src/pages/Links.tsx delete mode 100644 web/admin/src/pages/ProbeDetail.tsx delete mode 100644 web/admin/src/pages/Probes.tsx diff --git a/web/README.md b/web/README.md index 8222dcd..3a8e643 100644 --- a/web/README.md +++ b/web/README.md @@ -5,7 +5,7 @@ | 目录 | 内容 | 访问 | | --- | --- | --- | | `display/` | 展示端:Agent 卡片总览(线路质量 + 主机资源占用,实时刷新)、线路详情(延迟、丢包、抖动、TCP、UDP、评分、历史)、线路对比 | `/`,匿名可看;站点没有公开时提示登录 | -| `admin/` | 管理端:Agent(添加、审批、启停、接管、删除、加入令牌)、Probe(创建、轮换密钥、吊销、删除、连接)、任务、按需测试、系统(设置、版本与更新、API 令牌、用户、事件、原始数据、分析) | `/admin/`,要登录 | +| `admin/` | 管理端:Agent(添加、审批、启停、接管、删除、加入令牌)、线路画板(节点拖动、画布平移缩放、有向连接状态、方向开关与重试)、任务、按需测试、系统(设置、版本与更新、API 令牌、用户、事件、原始数据、分析) | `/admin/`,要登录 | | `shared/` | `theme/`(「纸墨」主题令牌和基础样式)、`api/`(客户端、从 OpenAPI 生成的类型)、`charts/`(uPlot 封装)、`ui/`(通用组件) | | ```sh @@ -23,9 +23,11 @@ npm run lint:css # 颜色只能写在 shared/theme/tokens.css, 约定: - 总览、线路详情、对比和管理端按需测试均可切换 IPv4 / IPv6;查询和测试结果独立。管理端 Agent 编辑页分别配置 IPv4、IPv6 地址,IPv6 留空只采 IPv4。展示端只显示地址族,不显示 IP。 -- 展示端能拿到的主机数据只有汇总的数字(CPU、内存、磁盘占用,网卡累计流量与瞬时网速,运行时长),没有 CPU 型号、主机名、网卡名,也没有任何 IP——后端的公开接口不返回它们,Agent 也根本不采集。展示端不显示 Probe 的版本和来源地址(这些只在管理端)。 +- 展示端能拿到的主机数据只有汇总的数字(CPU、内存、磁盘占用,网卡累计流量与瞬时网速,运行时长),没有 CPU 型号、主机名、网卡名,也没有任何 IP——后端的公开接口不返回它们,Agent 也根本不采集。展示端不显示 节点的来源地址(这些只在管理端)。 - 线路详情页:先选哪一天(前一天 / 后一天 / 日期选择,URL 的 `day=YYYY-MM-DD`),下面是这一天的丢包缩略图,上面有可拖动的选区(拖空白处新建、拖两边调长短、拖中间平移;URL 的 `at=起_止`,单位是从选中那天 0 点算起的分钟,可以是负数或超过 1440)。缩略图的刻度缺省是 48 小时(连续两天,选区可以跨零点,比如晚高峰 20:00 到凌晨 02:00),也可以切成 24 小时(只看一天;URL 的 `span=24`,选区跨零点时自动用 48 小时)。刻度下方是选区长度:30 分钟、1 小时、3 小时、6 小时、12 小时、整天,点一下把选区设成这么长——今天且选区到现在为止的,继续看「最近一段」(实时刷新),否则保持选区的起点往后取。刻度上每小时一根短线,48 小时刻度每 3 小时标一个钟点(24 小时刻度每 2 小时),零点标日期;鼠标移到缩略图上会标出那个位置的时间;点一下空白处或者刻度下面的钟点:离那里近的端点(左端或右端)贴过去,另一个端点不动。鼠标停在轴上或刻度上时,会动的那个端点变色,它到目标位置之间染色:扩大是橙色,收缩是灰色。往日默认是整天;「整天」是本地时区的自然日。时间的文字不写「次日」,跨零点两头都写日期(2026年10月5日 21:06 – 2026年10月6日 02:31)。 - 图表上方有 EWMA 平滑开关(关、轻 α=0.3、中 α=0.1、重 α=0.03;URL 的 `ewma=low|mid|high`):开了之后每条线画成指数加权移动平均,原始数据以淡线垫在后面,缺口处断开;只在浏览器里算,不影响汇总的指标数字。 - 图表在数据刷新(轮询、实时)时原地更新,不重建;拖选区时只在本地更新,松手才取数。 - 总览是卡片,Agent 主机状态通过 SSE(`/api/public/live?topics=hosts`)实时更新,其余每 10 秒刷新。 - 生产部署时,把 `display/dist` 放在站点根、`admin/dist` 放在 `/admin/` 下(同源,Cookie 和 CSRF 才能工作)。 + +管理端线路画板:拖动 Agent 卡片调整位置,拖动空白处平移,滚轮或工具栏缩放;「显示全部节点」恢复可见范围,「重置布局」恢复默认排布。点击带箭头的连线,在右侧面板调整当前方向的开关、恢复自动或立即重试。节点位置按后端地址保存在浏览器中;节点聚焦后可用方向键移动。Agent 详情中的拨出连接继续使用紧凑表格。 diff --git a/web/admin/src/App.tsx b/web/admin/src/App.tsx index 5dddf6d..38e52ba 100644 --- a/web/admin/src/App.tsx +++ b/web/admin/src/App.tsx @@ -11,8 +11,7 @@ import { PasskeyNotice } from './PasskeyNotice' import { Setup } from './Setup' import { AgentDetail } from './pages/AgentDetail' import { Agents } from './pages/Agents' -import { Probes } from './pages/Probes' -import { ProbeDetail } from './pages/ProbeDetail' +import { Links } from './pages/Links' import { System } from './pages/System' import { Tasks } from './pages/Tasks' import { Tests } from './pages/Tests' @@ -228,7 +227,7 @@ function Login() { } const NAV = [ - { section: '运维', items: [{ to: '/agents', label: 'Agent', icon: Server }, { to: '/probes', label: 'Probe', icon: Radar }] }, + { section: '运维', items: [{ to: '/agents', label: 'Agent', icon: Server }, { to: '/links', label: '线路画板', icon: Radar }] }, { section: '测试', items: [{ to: '/tasks', label: '任务', icon: ListChecks }, { to: '/tests', label: '按需测试', icon: FlaskConical }] }, { section: '系统', items: [{ to: '/system', label: '系统', icon: Settings }] }, ] @@ -286,8 +285,7 @@ export function App() { } /> } /> } /> - } /> - } /> + } /> } /> } /> } /> diff --git a/web/admin/src/BackendUpdateNotice.tsx b/web/admin/src/BackendUpdateNotice.tsx index c8e01e3..b2d80c0 100644 --- a/web/admin/src/BackendUpdateNotice.tsx +++ b/web/admin/src/BackendUpdateNotice.tsx @@ -5,7 +5,7 @@ import type { BackendUpdateDto } from '@shared/api/types' import { Confirm, ErrorNotice, useAction } from '@shared/ui' import { useAuth } from './auth' -/** webhook 发布后显示当前通道的更新;用户确认同一个 seq 后,Backend 先备份数据库再退出,由 Quadlet 拉最新镜像重启(和 Agent、Probe 一样)。 */ +/** webhook 发布后显示当前通道的更新;用户确认同一个 seq 后,Backend 先备份数据库再退出,由 Quadlet 拉最新镜像重启(和 Agent 一样)。 */ export function BackendUpdateNotice() { const { me } = useAuth() const [update, setUpdate] = useState() diff --git a/web/admin/src/PasskeyNotice.tsx b/web/admin/src/PasskeyNotice.tsx index e7dc0e8..d5a755f 100644 --- a/web/admin/src/PasskeyNotice.tsx +++ b/web/admin/src/PasskeyNotice.tsx @@ -54,7 +54,7 @@ export function PasskeyNotice() {
- 还没有 Passkey:不注册 Passkey、不建立信任根就无法添加 Agent 和 Probe,现在只能做基础管理(架构如此:节点只信任由 Passkey 签名的信任根)。Passkey 也可以用来登录,不用输密码。 + 还没有 Passkey:不注册 Passkey、不建立信任根就无法添加 Agent,现在只能做基础管理(架构如此:节点只信任由 Passkey 签名的信任根)。Passkey 也可以用来登录,不用输密码。