@@ -546,7 +546,7 @@ type publicStatusJSONResponse struct {
|
||||
func (s *Server) publicStatusJSON(w http.ResponseWriter, r *http.Request) {
|
||||
v, e := s.monitors.PublicStatusPage(r.Context(), r.PathValue("slug"))
|
||||
if e != nil {
|
||||
http.Error(w, "status page not found", 404)
|
||||
http.Error(w, "Statusseite nicht gefunden", 404)
|
||||
return
|
||||
}
|
||||
out := publicStatusJSONResponse{Name: v.Name, Slug: v.Slug, Description: v.Description, Status: v.Status, Services: []publicServiceJSON{}}
|
||||
@@ -560,7 +560,20 @@ func (s *Server) publicStatusJSON(w http.ResponseWriter, r *http.Request) {
|
||||
jsonOut(w, 200, out)
|
||||
}
|
||||
|
||||
var publicStatusTemplate = template.Must(template.New("status").Funcs(template.FuncMap{"upper": strings.ToUpper}).Parse(`<!doctype html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="refresh" content="30"><title>{{.Name}} · Status</title><style>:root{color-scheme:dark}body{margin:0;background:#0b0f14;color:#e8edf3;font:15px system-ui,-apple-system,Segoe UI,sans-serif}.wrap{max-width:900px;margin:0 auto;padding:54px 20px}.brand{color:#8b98a8;font-size:13px;margin-bottom:28px}h1{font-size:34px;margin:0 0 8px}.desc{color:#9aa8b7;margin-bottom:22px;white-space:pre-wrap}.summary,.service{background:#121820;border:1px solid #222c38;border-radius:14px;padding:18px 20px;margin:12px 0}.summary{display:flex;align-items:center;justify-content:space-between;gap:18px}.summary strong{font-size:17px}.dot{width:11px;height:11px;border-radius:50%;display:inline-block;flex:0 0 auto}.up{background:#26c281}.down{background:#ef5b5b}.maintenance{background:#f0b849}.pending,.paused,.unknown{background:#8290a2}.service h2{font-size:17px;margin:0}.row{display:flex;align-items:center;justify-content:space-between;gap:15px}.meta{color:#8b98a8;font-size:13px;margin-top:5px}.probe{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;padding:10px 0;border-top:1px solid #1d2631;margin-top:10px}.probe+.probe{margin-top:0}.badge{font-size:12px;text-transform:uppercase;font-weight:700;letter-spacing:.04em}.footer{color:#647181;font-size:12px;text-align:center;margin-top:32px}@media(max-width:600px){.wrap{padding:30px 14px}h1{font-size:28px}.summary{align-items:flex-start;flex-direction:column}.probe{grid-template-columns:auto 1fr}.probe .meta{grid-column:2}}</style></head><body><main class="wrap"><div class="brand">Dockwatch Public Status</div><h1>{{.Name}}</h1><div class="desc">{{.Description}}</div><section class="summary"><div><strong>{{if eq .Status "up"}}All published services operational{{else if eq .Status "down"}}Service disruption detected{{else if eq .Status "maintenance"}}Maintenance in progress{{else}}Status being evaluated{{end}}</strong><div class="meta">This page refreshes automatically every 30 seconds.</div></div><div class="row"><span class="dot {{.Status}}"></span><span class="badge">{{upper .Status}}</span></div></section>{{range .Services}}<section class="service"><div class="row"><div><h2>{{.Name}}</h2><div class="meta">{{.Description}}</div></div><div class="row"><span class="dot {{.Status}}"></span><span class="badge">{{upper .Status}}</span></div></div>{{range .Monitors}}<div class="probe"><span class="dot {{.Status}}"></span><span>{{.Name}}</span><span class="meta">{{printf "%.2f" .Uptime24h}}% / 24h{{if .LastLatencyMS}} · {{.LastLatencyMS}} ms{{end}}</span></div>{{end}}</section>{{else}}<section class="service">No public services configured.</section>{{end}}<div class="footer">Only explicitly published service status is shown · powered by Dockwatch</div></main></body></html>`))
|
||||
var publicStatusTemplate = template.Must(template.New("status").Funcs(template.FuncMap{"upper": strings.ToUpper, "statusDE": func(v string) string {
|
||||
switch strings.ToLower(v) {
|
||||
case "up":
|
||||
return "Verfügbar"
|
||||
case "down":
|
||||
return "Ausgefallen"
|
||||
case "maintenance":
|
||||
return "Wartung"
|
||||
case "paused":
|
||||
return "Pausiert"
|
||||
default:
|
||||
return "Unbekannt"
|
||||
}
|
||||
}}).Parse(`<!doctype html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="refresh" content="30"><title>{{.Name}} · Status</title><style>:root{color-scheme:dark}body{margin:0;background:#0b0f14;color:#e8edf3;font:15px system-ui,-apple-system,Segoe UI,sans-serif}.wrap{max-width:900px;margin:0 auto;padding:54px 20px}.brand{color:#8b98a8;font-size:13px;margin-bottom:28px}h1{font-size:34px;margin:0 0 8px}.desc{color:#9aa8b7;margin-bottom:22px;white-space:pre-wrap}.summary,.service{background:#121820;border:1px solid #222c38;border-radius:14px;padding:18px 20px;margin:12px 0}.summary{display:flex;align-items:center;justify-content:space-between;gap:18px}.summary strong{font-size:17px}.dot{width:11px;height:11px;border-radius:50%;display:inline-block;flex:0 0 auto}.up{background:#26c281}.down{background:#ef5b5b}.maintenance{background:#f0b849}.pending,.paused,.unknown{background:#8290a2}.service h2{font-size:17px;margin:0}.row{display:flex;align-items:center;justify-content:space-between;gap:15px}.meta{color:#8b98a8;font-size:13px;margin-top:5px}.probe{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;padding:10px 0;border-top:1px solid #1d2631;margin-top:10px}.probe+.probe{margin-top:0}.badge{font-size:12px;text-transform:uppercase;font-weight:700;letter-spacing:.04em}.footer{color:#647181;font-size:12px;text-align:center;margin-top:32px}@media(max-width:600px){.wrap{padding:30px 14px}h1{font-size:28px}.summary{align-items:flex-start;flex-direction:column}.probe{grid-template-columns:auto 1fr}.probe .meta{grid-column:2}}</style></head><body><main class="wrap"><div class="brand">Dockwatch · Öffentlicher Status</div><h1>{{.Name}}</h1><div class="desc">{{.Description}}</div><section class="summary"><div><strong>{{if eq .Status "up"}}Alle veröffentlichten Dienste sind verfügbar{{else if eq .Status "down"}}Dienststörung erkannt{{else if eq .Status "maintenance"}}Wartung läuft{{else}}Status wird ermittelt{{end}}</strong><div class="meta">Diese Seite wird automatisch alle 30 Sekunden aktualisiert.</div></div><div class="row"><span class="dot {{.Status}}"></span><span class="badge">{{statusDE .Status}}</span></div></section>{{range .Services}}<section class="service"><div class="row"><div><h2>{{.Name}}</h2><div class="meta">{{.Description}}</div></div><div class="row"><span class="dot {{.Status}}"></span><span class="badge">{{statusDE .Status}}</span></div></div>{{range .Monitors}}<div class="probe"><span class="dot {{.Status}}"></span><span>{{.Name}}</span><span class="meta">{{printf "%.2f" .Uptime24h}}% / 24h{{if .LastLatencyMS}} · {{.LastLatencyMS}} ms{{end}}</span></div>{{end}}</section>{{else}}<section class="service">Keine öffentlichen Dienste konfiguriert.</section>{{end}}<div class="footer">Es werden nur ausdrücklich veröffentlichte Dienststatus angezeigt · bereitgestellt von Dockwatch</div></main></body></html>`))
|
||||
|
||||
func (s *Server) publicStatusPage(w http.ResponseWriter, r *http.Request) {
|
||||
v, e := s.monitors.PublicStatusPage(r.Context(), r.PathValue("slug"))
|
||||
|
||||
Reference in New Issue
Block a user