ui: uptime chip, #0004 shadows, tick marks, raw metrics; server: config meta injection

- ui: add uptime% chip (green >=99, red below) after ssh; remove "up" word
- ui: all shadows use #0004 shadow-color; modal shadow-lg derives from it
- ui: status modal draws a datetime tick mark every 20 history entries from the newest
- server: drop max_points/downsampling/bucketing; metrics served raw, plots share a ~24h window
- docs: fix ps --no-headers in top example; document raw metrics API
- server: inject <meta name=title/description> into index.html from config title + per-group host patterns (shared with --check recap)
This commit is contained in:
2026-08-02 02:06:27 +02:00
parent 6ade221621
commit c988ddf22f
14 changed files with 238 additions and 151 deletions
+9 -11
View File
@@ -77,6 +77,7 @@ type machineStatus struct {
ICMP string `json:"icmp"`
TCP string `json:"tcp"`
LastPing *time.Time `json:"lastPing"`
Uptime *float64 `json:"uptime,omitempty"`
SSHConfigured bool `json:"sshConfigured"`
SSH *sshResultState `json:"ssh"`
Metrics []metricStatus `json:"metrics"`
@@ -648,6 +649,13 @@ func (m *Monitor) StatusPayload() statusPayload {
ms.ICMP = checkNA
ms.TCP = checkNA
}
if m.history != nil {
up, down := m.history.Uptime(mc.ID)
if up+down > 0 {
u := float64(up) / float64(up+down) * 100
ms.Uptime = &u
}
}
if group == "" {
p.Machines = append(p.Machines, ms)
return
@@ -703,16 +711,6 @@ func (m *Monitor) metricsHandler(w http.ResponseWriter, r *http.Request) {
return
}
q := r.URL.Query()
maxPoints := 100
if v := q.Get("max_points"); v != "" {
if n, err := strconv.Atoi(v); err == nil {
maxPoints = n
}
} else if v := q.Get("limit"); v != "" {
if n, err := strconv.Atoi(v); err == nil {
maxPoints = n
}
}
var minTS, maxTS int64
if v := q.Get("min"); v != "" {
minTS, _ = strconv.ParseInt(v, 10, 64)
@@ -720,7 +718,7 @@ func (m *Monitor) metricsHandler(w http.ResponseWriter, r *http.Request) {
if v := q.Get("max"); v != "" {
maxTS, _ = strconv.ParseInt(v, 10, 64)
}
entries, err := m.history.QueryMetrics(machine, q.Get("name"), minTS, maxTS, maxPoints, q.Get("shared") != "")
entries, err := m.history.QueryMetrics(machine, q.Get("name"), minTS, maxTS)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return