1package web
2
3import (
4 "database/sql"
5 "fmt"
6 "net/http"
7 "strings"
8
9 "github.com/go-chi/chi/v5"
10)
11
12func Routes(db *sql.DB) http.Handler {
13 r := chi.NewRouter()
14
15 r.Get("/", HandleDashboard(db))
16
17 return r
18}
19
20func HandleDashboard(db *sql.DB) http.HandlerFunc {
21 return func(w http.ResponseWriter, r *http.Request) {
22 type Result struct {
23 Name string
24 Statuses []string
25 }
26
27 rows, err := db.Query(`
28 SELECT name, status
29 FROM check_results
30 ORDER BY timestamp DESC
31 LIMIT 1000
32 `)
33 if err != nil {
34 http.Error(w, "DB error", 500)
35 return
36 }
37 defer rows.Close()
38
39 grouped := map[string][]string{}
40
41 for rows.Next() {
42 var name, status string
43 if err := rows.Scan(&name, &status); err == nil {
44 grouped[name] = append(grouped[name], status)
45 }
46 }
47
48 var html strings.Builder
49 html.WriteString(`<!DOCTYPE html><html><head><meta charset="utf-8"><title>Hestia</title></head><body style="font-family: sans-serif">`)
50 html.WriteString(`<h1>Health Checks</h1>`)
51
52 for name, statuses := range grouped {
53 html.WriteString(fmt.Sprintf("<h2>%s</h2><div style='display: flex; gap: 2px;'>", name))
54 for _, status := range statuses {
55 color := "#4caf50"
56 if status != "ok" {
57 color = "#f44336"
58 }
59 html.WriteString(fmt.Sprintf(`<div title="%s" style="width: 10px; height: 20px; background: %s;"></div>`, status, color))
60 }
61 html.WriteString("</div>")
62 }
63
64 html.WriteString(`</body></html>`)
65 w.Header().Set("Content-Type", "text/html")
66 w.Write([]byte(html.String()))
67 }
68}