Dashboard tab: CPU/mem/load, hwmon temps+fans, net, disks, filesystems, UPS with 10-min sparklines

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-17 13:37:39 -07:00
co-authored by Claude Fable 5.1
parent 24d64245ec
commit 3c6f4d4639
10 changed files with 982 additions and 34 deletions
+21 -2
View File
@@ -17,6 +17,7 @@ import (
"hamlab/internal/auth"
"hamlab/internal/config"
"hamlab/internal/metrics"
"hamlab/internal/term"
)
@@ -27,6 +28,7 @@ type Server struct {
sessions *auth.Sessions
limiter auth.Limiter
mgr *term.Manager
metrics *metrics.Collector
version string
started time.Time
user string
@@ -35,9 +37,9 @@ type Server struct {
mux *http.ServeMux
}
func New(cfg *config.Config, sessions *auth.Sessions, mgr *term.Manager, ui fs.FS, version string) *Server {
func New(cfg *config.Config, sessions *auth.Sessions, mgr *term.Manager, col *metrics.Collector, ui fs.FS, version string) *Server {
host, _ := os.Hostname()
s := &Server{cfg: cfg, sessions: sessions, mgr: mgr, ui: ui, version: version,
s := &Server{cfg: cfg, sessions: sessions, mgr: mgr, metrics: col, ui: ui, version: version,
started: time.Now(), host: host, user: os.Getenv("USER")}
if s.user == "" {
s.user = "core"
@@ -52,6 +54,8 @@ func New(cfg *config.Config, sessions *auth.Sessions, mgr *term.Manager, ui fs.F
m.HandleFunc("PATCH /api/terminals/{id}", s.auth(s.renameTerminal))
m.HandleFunc("DELETE /api/terminals/{id}", s.auth(s.deleteTerminal))
m.HandleFunc("GET /api/terminals/{id}/attach", s.auth(s.attach))
m.HandleFunc("GET /api/metrics", s.auth(s.metricsLatest))
m.HandleFunc("GET /api/metrics/history", s.auth(s.metricsHistory))
m.HandleFunc("/api/", func(w http.ResponseWriter, _ *http.Request) { jsonErr(w, 404, "not found") })
m.HandleFunc("/", s.static)
s.mux = m
@@ -162,6 +166,21 @@ func (s *Server) me(w http.ResponseWriter, _ *http.Request) {
})
}
// ---- metrics (Dashboard) ----
func (s *Server) metricsLatest(w http.ResponseWriter, _ *http.Request) {
smp, ok := s.metrics.Latest()
if !ok {
jsonErr(w, 503, "no sample yet")
return
}
jsonOK(w, 200, smp)
}
func (s *Server) metricsHistory(w http.ResponseWriter, _ *http.Request) {
jsonOK(w, 200, s.metrics.History())
}
// ---- terminals ----
func (s *Server) listTerminals(w http.ResponseWriter, _ *http.Request) {