mavweb: add notifications history page at /notifications

RecentNudges IPC method, store adapter, dispatch, and client proxy.
Web UI at /notifications showing recent nudge history with color-coded
outcomes, nav links from /dash and /history.
This commit is contained in:
kami
2026-07-05 13:20:24 +04:00
parent 85013f7b8b
commit 5c34fb14f9
5 changed files with 135 additions and 2 deletions
+26
View File
@@ -51,6 +51,9 @@ var historyHTML string
//go:embed trace.html
var traceHTML string
//go:embed notifications.html
var notificationsHTML string
// dashTmpl — the monitoring read surface, server-rendered from dash.html (no JS,
// no client fetch); meta-refresh keeps it live. html/template escapes the user
// text in facts/nudges. Read-only: browses the append-only store via CoreAPI,
@@ -139,6 +142,9 @@ func main() {
mux.HandleFunc("/trace", func(w http.ResponseWriter, r *http.Request) {
handleTrace(w, r, core)
})
mux.HandleFunc("/notifications", func(w http.ResponseWriter, r *http.Request) {
handleNotifications(w, r, core)
})
mux.HandleFunc("/api/revert", func(w http.ResponseWriter, r *http.Request) {
handleRevert(w, r, core)
})
@@ -378,6 +384,8 @@ input[type=text]{width:22rem}code{background:#f4f4f4;padding:.1rem .3rem}
var historyTmpl = template.Must(template.New("history").Parse(historyHTML))
var notificationsTmpl = template.Must(template.New("notifications").Parse(notificationsHTML))
var traceTmpl = template.Must(template.New("trace").Funcs(template.FuncMap{
"ago": func(t time.Time) string {
if t.IsZero() {
@@ -414,6 +422,24 @@ func handleHistory(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI) {
}
}
func handleNotifications(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI) {
if core == nil {
http.Error(w, "notifications disabled (no -core)", http.StatusServiceUnavailable)
return
}
ctx := r.Context()
nudges, err := core.RecentNudges(ctx, 50)
if err != nil {
log.Printf("notifications: %v", err)
http.Error(w, "notifications error: "+err.Error(), http.StatusBadGateway)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := notificationsTmpl.Execute(w, map[string]any{"Nudges": nudges}); err != nil {
log.Printf("notifications template: %v", err)
}
}
func handleTrace(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI) {
if core == nil {
http.Error(w, "trace disabled (no -core)", http.StatusServiceUnavailable)