仪表盘细节修整,内核卡片搬左列并加重启

- 曲线空态和图共用一个定高容器,数据到来不再挤下面的内容
- 路由行去掉行间分割线:它会吃掉 hover 高亮的圆角
- 每路走势线先合并成 28 桶再画。3 秒一个采样直接全画,在一条
  百来像素宽的线上只剩噪声;没采集的桶画断口,不画假零
- 环形图两段加圆角,交界用底色描边让出间隙
- 内核卡片从右列搬到服务器和路由之间(左列本来就矮一截),加
  「重启内核」:POST /restart 后内核自我 exec、PID 不变,恢复没有
  任何通知,只能每 2 秒探一次,半分钟探不到交还给外壳心跳
This commit is contained in:
2026-08-11 22:42:40 +08:00
parent eec5b791c8
commit 07a43b5a56
6 changed files with 248 additions and 54 deletions
+9 -1
View File
@@ -12,7 +12,7 @@
import listenerFields from '../shared/listener-fields.json' with { type: 'json' }
import { applyConfig, listBackups, readConfig, restoreBackup } from './config-store.ts'
import { hostInfo, probeExit } from './host.ts'
import { kernelVersion, proxyGet, proxyWrite, selectProxy } from './kernel.ts'
import { kernelVersion, proxyGet, proxyWrite, restartKernel, selectProxy } from './kernel.ts'
import { tokenFromRequest, tokenMatches } from './auth.ts'
import type { ConfigObject } from '../vendor/config-editor/index.ts'
import type { Env } from './env.ts'
@@ -214,6 +214,14 @@ function makeRoute(env: Env, token: string) {
: json({ message: upstream.message || '内核拒绝了这次切换' }, 422)
}
// 重启内核进程。运行时动作,不碰配置文件;和其它写操作一样单独点名,不开通用口子
if (path === '/api/kernel/restart' && req.method === 'POST') {
const upstream = await restartKernel(env)
return upstream.ok
? json({ ok: true })
: json({ message: upstream.message || '内核拒绝了重启请求' }, 502)
}
if (path.startsWith('/api/kernel/') && (req.method === 'PUT' || req.method === 'DELETE')) {
const target = path.slice('/api/kernel'.length)
const rule = WRITABLE.find((w) => w.method === req.method && w.pattern.test(target))