panel: finish the monitoring rename below the URL layer

The previous two commits renamed the routes and the page titles but left
every identifier underneath still called sendlog/queue/logtail, so a
grep for "deliveries" found the route and nothing that serves it.

Renamed together, since they have to agree for a page to render at all:
the six template files, their {{define}} blocks, the pageFiles and
fragmentFiles keys, the .Active values the nav compares against, the
HTMX target ids, and the six page handlers.

Names that describe the data rather than the page keep their old form:
the send_log table and its store methods, internal/logtail, and the
sendLogData/readQueue/readLogTail helpers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-03 22:04:33 +03:00
parent 0ca5cba453
commit 5041f87e57
11 changed files with 51 additions and 50 deletions
+25 -24
View File
@@ -19,11 +19,12 @@ const (
logTailLines = 200 logTailLines = 200
) )
// handleSendLog renders the send-log monitoring page: server-side filters by // handleDeliveries renders the Deliveries page over the send log: server-side
// domain/application and pagination (spec 7.3.3). The row table itself is the // filters by domain/application and pagination (spec 7.3.3). The row table
// "sendlog_rows" fragment, shared verbatim with handleSendLogRows so the // itself is the "deliveries_rows" fragment, shared verbatim with
// initial page and its HTMX-polled refreshes never diverge. // handleDeliveriesRows so the initial page and its HTMX-polled refreshes never
func (s *Server) handleSendLog(w http.ResponseWriter, r *http.Request) { // diverge.
func (s *Server) handleDeliveries(w http.ResponseWriter, r *http.Request) {
data, err := s.sendLogData(r) data, err := s.sendLogData(r)
if err != nil { if err != nil {
logf("panel: send log: %v", err) logf("panel: send log: %v", err)
@@ -32,20 +33,20 @@ func (s *Server) handleSendLog(w http.ResponseWriter, r *http.Request) {
} }
data["Title"] = "SelfPost — deliveries" data["Title"] = "SelfPost — deliveries"
data["User"] = currentUser(r) data["User"] = currentUser(r)
data["Active"] = "sendlog" data["Active"] = "deliveries"
s.render(w, http.StatusOK, "sendlog", data) s.render(w, http.StatusOK, "deliveries", data)
} }
// handleSendLogRows serves the HTMX polling fragment for the send-log table // handleDeliveriesRows serves the HTMX polling fragment for the delivery table
// (spec 7.1: fragment endpoints return HTML, not JSON). // (spec 7.1: fragment endpoints return HTML, not JSON).
func (s *Server) handleSendLogRows(w http.ResponseWriter, r *http.Request) { func (s *Server) handleDeliveriesRows(w http.ResponseWriter, r *http.Request) {
data, err := s.sendLogData(r) data, err := s.sendLogData(r)
if err != nil { if err != nil {
logf("panel: send log rows: %v", err) logf("panel: send log rows: %v", err)
http.Error(w, "internal error", http.StatusInternalServerError) http.Error(w, "internal error", http.StatusInternalServerError)
return return
} }
s.renderFragment(w, http.StatusOK, "sendlog_rows", data) s.renderFragment(w, http.StatusOK, "deliveries_rows", data)
} }
// sendLogData reads the domain/app filters and page number off the query // sendLogData reads the domain/app filters and page number off the query
@@ -109,22 +110,22 @@ func parsePage(v string) int {
return n return n
} }
// handleQueue renders the mail-queue monitoring page (spec 7.2.11). // handleMailQueue renders the Mail queue page (spec 7.2.11).
func (s *Server) handleQueue(w http.ResponseWriter, r *http.Request) { func (s *Server) handleMailQueue(w http.ResponseWriter, r *http.Request) {
out, errText := readQueue() out, errText := readQueue()
s.render(w, http.StatusOK, "queue", map[string]any{ s.render(w, http.StatusOK, "mail_queue", map[string]any{
"Title": "SelfPost — mail queue", "Title": "SelfPost — mail queue",
"User": currentUser(r), "User": currentUser(r),
"Active": "queue", "Active": "mail_queue",
"Output": out, "Output": out,
"Error": errText, "Error": errText,
}) })
} }
// handleQueueBody serves the HTMX polling fragment for the queue view. // handleMailQueueBody serves the HTMX polling fragment for the queue view.
func (s *Server) handleQueueBody(w http.ResponseWriter, r *http.Request) { func (s *Server) handleMailQueueBody(w http.ResponseWriter, r *http.Request) {
out, errText := readQueue() out, errText := readQueue()
s.renderFragment(w, http.StatusOK, "queue_body", map[string]any{ s.renderFragment(w, http.StatusOK, "mail_queue_body", map[string]any{
"Output": out, "Output": out,
"Error": errText, "Error": errText,
}) })
@@ -142,22 +143,22 @@ func readQueue() (string, string) {
return out, "" return out, ""
} }
// handleLogTail renders the mail.log monitoring page (spec 7.2.13). // handleSystemLog renders the System log page over mail.log (spec 7.2.13).
func (s *Server) handleLogTail(w http.ResponseWriter, r *http.Request) { func (s *Server) handleSystemLog(w http.ResponseWriter, r *http.Request) {
lines, errText := s.readLogTail() lines, errText := s.readLogTail()
s.render(w, http.StatusOK, "logtail", map[string]any{ s.render(w, http.StatusOK, "system_log", map[string]any{
"Title": "SelfPost — system log", "Title": "SelfPost — system log",
"User": currentUser(r), "User": currentUser(r),
"Active": "logtail", "Active": "system_log",
"Lines": lines, "Lines": lines,
"Error": errText, "Error": errText,
}) })
} }
// handleLogTailBody serves the HTMX polling fragment for the log-tail view. // handleSystemLogBody serves the HTMX polling fragment for the log-tail view.
func (s *Server) handleLogTailBody(w http.ResponseWriter, r *http.Request) { func (s *Server) handleSystemLogBody(w http.ResponseWriter, r *http.Request) {
lines, errText := s.readLogTail() lines, errText := s.readLogTail()
s.renderFragment(w, http.StatusOK, "logtail_body", map[string]any{ s.renderFragment(w, http.StatusOK, "system_log_body", map[string]any{
"Lines": lines, "Lines": lines,
"Error": errText, "Error": errText,
}) })
+7 -7
View File
@@ -30,19 +30,19 @@ var pageFiles = map[string][]string{
"backup": {"templates/backup.html"}, "backup": {"templates/backup.html"},
"domain_detail": {"templates/domain_detail.html"}, "domain_detail": {"templates/domain_detail.html"},
"domain_delete": {"templates/domain_delete.html"}, "domain_delete": {"templates/domain_delete.html"},
"sendlog": {"templates/sendlog.html", "templates/sendlog_rows.html"}, "deliveries": {"templates/deliveries.html", "templates/deliveries_rows.html"},
"queue": {"templates/queue.html", "templates/queue_body.html"}, "mail_queue": {"templates/mail_queue.html", "templates/mail_queue_body.html"},
"logtail": {"templates/logtail.html", "templates/logtail_body.html"}, "system_log": {"templates/system_log.html", "templates/system_log_body.html"},
"status": {"templates/status.html", "templates/status_body.html"}, "status": {"templates/status.html", "templates/status_body.html"},
} }
// fragmentFiles maps a fragment name (also its {{define}} block name) to its // fragmentFiles maps a fragment name (also its {{define}} block name) to its
// template file, for standalone rendering by the HTMX polling endpoints. // template file, for standalone rendering by the HTMX polling endpoints.
var fragmentFiles = map[string]string{ var fragmentFiles = map[string]string{
"sendlog_rows": "templates/sendlog_rows.html", "deliveries_rows": "templates/deliveries_rows.html",
"queue_body": "templates/queue_body.html", "mail_queue_body": "templates/mail_queue_body.html",
"logtail_body": "templates/logtail_body.html", "system_log_body": "templates/system_log_body.html",
"status_body": "templates/status_body.html", "status_body": "templates/status_body.html",
} }
func loadTemplates() (*templates, error) { func loadTemplates() (*templates, error) {
@@ -19,6 +19,6 @@
</div> </div>
<div class="card"> <div class="card">
{{template "sendlog_rows" .}} {{template "deliveries_rows" .}}
</div> </div>
{{end}} {{end}}
@@ -1,5 +1,5 @@
{{define "sendlog_rows"}} {{define "deliveries_rows"}}
<div id="sendlog-rows" hx-get="/deliveries/rows?domain={{.FilterDomain}}&app={{.FilterApp}}&p={{.Page}}" <div id="deliveries-rows" hx-get="/deliveries/rows?domain={{.FilterDomain}}&app={{.FilterApp}}&p={{.Page}}"
hx-trigger="every 5s" hx-swap="outerHTML"> hx-trigger="every 5s" hx-swap="outerHTML">
{{if .Rows}} {{if .Rows}}
<table> <table>
+3 -3
View File
@@ -38,9 +38,9 @@
<div class="links"> <div class="links">
{{if eq .Active "status"}}<span aria-current="page">Status</span>{{else}}<a href="/status">Status</a>{{end}} {{if eq .Active "status"}}<span aria-current="page">Status</span>{{else}}<a href="/status">Status</a>{{end}}
{{if eq .Active "domains"}}<span aria-current="page">Domains</span>{{else}}<a href="/domains">Domains</a>{{end}} {{if eq .Active "domains"}}<span aria-current="page">Domains</span>{{else}}<a href="/domains">Domains</a>{{end}}
{{if eq .Active "sendlog"}}<span aria-current="page">Deliveries</span>{{else}}<a href="/deliveries">Deliveries</a>{{end}} {{if eq .Active "deliveries"}}<span aria-current="page">Deliveries</span>{{else}}<a href="/deliveries">Deliveries</a>{{end}}
{{if eq .Active "queue"}}<span aria-current="page">Mail queue</span>{{else}}<a href="/mail-queue">Mail queue</a>{{end}} {{if eq .Active "mail_queue"}}<span aria-current="page">Mail queue</span>{{else}}<a href="/mail-queue">Mail queue</a>{{end}}
{{if eq .Active "logtail"}}<span aria-current="page">System log</span>{{else}}<a href="/system-log">System log</a>{{end}} {{if eq .Active "system_log"}}<span aria-current="page">System log</span>{{else}}<a href="/system-log">System log</a>{{end}}
{{if eq .Active "backup"}}<span aria-current="page">Backup</span>{{else}}<a href="/backup">Backup</a>{{end}} {{if eq .Active "backup"}}<span aria-current="page">Backup</span>{{else}}<a href="/backup">Backup</a>{{end}}
</div> </div>
<div class="session"> <div class="session">
@@ -3,6 +3,6 @@
<div class="card"> <div class="card">
<h2>Pending messages</h2> <h2>Pending messages</h2>
{{template "queue_body" .}} {{template "mail_queue_body" .}}
</div> </div>
{{end}} {{end}}
@@ -1,5 +1,5 @@
{{define "queue_body"}} {{define "mail_queue_body"}}
<div id="queue-body" hx-get="/mail-queue/body" hx-trigger="every 5s" hx-swap="outerHTML"> <div id="mail-queue-body" hx-get="/mail-queue/body" hx-trigger="every 5s" hx-swap="outerHTML">
{{if .Error}}<p class="error">{{.Error}}</p>{{end}} {{if .Error}}<p class="error">{{.Error}}</p>{{end}}
<span class="code">{{if .Output}}{{.Output}}{{else}}Queue is empty.{{end}}</span> <span class="code">{{if .Output}}{{.Output}}{{else}}Queue is empty.{{end}}</span>
</div> </div>
@@ -3,6 +3,6 @@
<div class="card"> <div class="card">
<h2>Recent log entries</h2> <h2>Recent log entries</h2>
{{template "logtail_body" .}} {{template "system_log_body" .}}
</div> </div>
{{end}} {{end}}
@@ -1,5 +1,5 @@
{{define "logtail_body"}} {{define "system_log_body"}}
<div id="logtail-body" hx-get="/system-log/body" hx-trigger="every 5s" hx-swap="outerHTML"> <div id="system-log-body" hx-get="/system-log/body" hx-trigger="every 5s" hx-swap="outerHTML">
{{if .Error}}<p class="error">{{.Error}}</p>{{end}} {{if .Error}}<p class="error">{{.Error}}</p>{{end}}
<span class="code">{{if .Lines}}{{range .Lines}}{{.}} <span class="code">{{if .Lines}}{{range .Lines}}{{.}}
{{end}}{{else}}No log lines yet.{{end}}</span> {{end}}{{else}}No log lines yet.{{end}}</span>
+1 -1
View File
@@ -99,7 +99,7 @@ func TestNavMarksActivePage(t *testing.T) {
var buf bytes.Buffer var buf bytes.Buffer
err = tmpl.pages["dashboard"].ExecuteTemplate(&buf, "nav", map[string]any{ err = tmpl.pages["dashboard"].ExecuteTemplate(&buf, "nav", map[string]any{
"User": "admin", "User": "admin",
"Active": "queue", "Active": "mail_queue",
}) })
if err != nil { if err != nil {
t.Fatalf("execute nav: %v", err) t.Fatalf("execute nav: %v", err)
+6 -6
View File
@@ -185,12 +185,12 @@ func (s *Server) Handler() http.Handler {
// Monitoring screens (spec 7.2.11-13): each page and its HTMX polling // Monitoring screens (spec 7.2.11-13): each page and its HTMX polling
// fragment (spec 7.1 — the /rows and /body endpoints return HTML, not JSON). // fragment (spec 7.1 — the /rows and /body endpoints return HTML, not JSON).
authed.HandleFunc("GET /deliveries", s.handleSendLog) authed.HandleFunc("GET /deliveries", s.handleDeliveries)
authed.HandleFunc("GET /deliveries/rows", s.handleSendLogRows) authed.HandleFunc("GET /deliveries/rows", s.handleDeliveriesRows)
authed.HandleFunc("GET /mail-queue", s.handleQueue) authed.HandleFunc("GET /mail-queue", s.handleMailQueue)
authed.HandleFunc("GET /mail-queue/body", s.handleQueueBody) authed.HandleFunc("GET /mail-queue/body", s.handleMailQueueBody)
authed.HandleFunc("GET /system-log", s.handleLogTail) authed.HandleFunc("GET /system-log", s.handleSystemLog)
authed.HandleFunc("GET /system-log/body", s.handleLogTailBody) authed.HandleFunc("GET /system-log/body", s.handleSystemLogBody)
mux.Handle("/", s.requireAuth(authed)) mux.Handle("/", s.requireAuth(authed))