D4 Part 1: hub fonts + sprite + statusColor semantic remap
- static/fonts/: the 4 vendored woff2 (byte-copied from
felhom-controller), embedded (embed.go) and served at /static/fonts/
(font/woff2, immutable) mirroring the chart.min.js pattern. No CDN
before, none now.
- templates/icons.html: 12-symbol Lucide sprite partial (icon_sprite),
included at the top of <body> on all 9 pages ({{template}} — the hub
has no shared layout; per-page include is the minimal shared block).
- statusColor now returns v2 semantic tokens (nominal/warn/crit/
neutral) consumed as class suffixes: ok->nominal, warn+stale->warn,
down+fail->crit, pending+disabled->neutral (a not-yet-provisioned or
deliberately paused customer is a normal fleet state), blocked->warn
(intentional operator cut-off, attention-worthy not an outage),
unknown->neutral. The inline style="color: {{statusColor}}" pattern
is dead: dashboard + customer_unified render a class-based
.status-dot-<token>; statusIcon (constant "●") retired from funcmap
and templates.
- Tests (new; the hub web package had no funcmap/template tests):
TestStatusColorTruthTable over the full enumerated status set —
red-proven vs the old implementation (ok returned "#4ade80") — and
TestTemplatesParseWithFuncmap.
This commit is contained in:
+29
-12
@@ -73,7 +73,6 @@ func New(store *store.Store, passwordHash, apiKey, version string, staleThreshol
|
||||
return timeAgo(*t)
|
||||
},
|
||||
"statusColor": statusColor,
|
||||
"statusIcon": statusIcon,
|
||||
"formatFloat": func(f float64) string { return fmt.Sprintf("%.0f", f) },
|
||||
"joinStrings": func(s []string, sep string) string { return strings.Join(s, sep) },
|
||||
"json": func(v interface{}) template.JS {
|
||||
@@ -204,6 +203,17 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/javascript")
|
||||
w.Header().Set("Cache-Control", "public, max-age=86400")
|
||||
w.Write(chartJS)
|
||||
case strings.HasPrefix(path, "/static/fonts/"):
|
||||
// Vendored brand fonts (design system v2) — embedded, no CDN.
|
||||
name := strings.TrimPrefix(path, "/static/fonts/")
|
||||
data, err := fontFS.ReadFile("static/fonts/" + name)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "font/woff2")
|
||||
w.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
|
||||
w.Write(data)
|
||||
case path == "/configuration":
|
||||
if r.Method == http.MethodPost {
|
||||
s.handleConfigurationAction(w, r)
|
||||
@@ -608,25 +618,32 @@ func timeAgo(t time.Time) string {
|
||||
return fmt.Sprintf("%dd ago", days)
|
||||
}
|
||||
|
||||
// statusColor maps a status value to a design-system-v2 semantic token, consumed as a
|
||||
// class suffix (status-dot-nominal, tag-nominal, …) — never as an inline color (D4).
|
||||
// Exception-color principle: a healthy fleet is blue/neutral; amber/red only on deviation.
|
||||
// ok -> nominal (blue — operating normally)
|
||||
// warn, stale -> warn (amber — degraded / stale report)
|
||||
// down, fail -> crit (red — outage)
|
||||
// pending -> neutral (a not-yet-provisioned customer is a normal fleet state)
|
||||
// disabled -> neutral (deliberately paused — not a deviation)
|
||||
// blocked -> warn (an operator cut a customer off: intentional but attention-worthy)
|
||||
func statusColor(status string) string {
|
||||
switch status {
|
||||
case "ok":
|
||||
return "#4ade80" // green
|
||||
case "warn":
|
||||
return "#facc15" // yellow
|
||||
return "nominal"
|
||||
case "warn", "stale":
|
||||
return "warn"
|
||||
case "down", "fail":
|
||||
return "#f87171" // red
|
||||
case "disabled", "pending", "blocked":
|
||||
return "#94a3b8" // gray
|
||||
return "crit"
|
||||
case "blocked":
|
||||
return "warn"
|
||||
case "disabled", "pending":
|
||||
return "neutral"
|
||||
default:
|
||||
return "#94a3b8" // gray
|
||||
return "neutral"
|
||||
}
|
||||
}
|
||||
|
||||
func statusIcon(status string) string {
|
||||
return "●"
|
||||
}
|
||||
|
||||
// handleConfiguration renders the Configuration page.
|
||||
func (s *Server) handleConfiguration(w http.ResponseWriter, r *http.Request) {
|
||||
csrfToken := s.getCSRFToken(r)
|
||||
|
||||
Reference in New Issue
Block a user