panel: show the send log's status as a badge
test / test (push) Has been cancelled

The send log was the one place in the panel where a status was bare text, next
to a delivery's own page where the same value is a badge, and a domain list
where the DNS verdict is one too — so a message's outcome looked like a
different kind of fact depending on which page you read it from.

The level travels on the row rather than being worked out in the template:
deliveryLevel is the one place that decides what a status means, the delivery
page already reads it, and a second mapping written into the template or the
stylesheet would have been free to drift from it. sent is ok, deferred a
warning, bounced and rejected errors, and queued unknown — nothing has gone
wrong, nothing has been reported yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 01:23:52 +03:00
parent aeba3f8db1
commit 7cc499d57c
3 changed files with 22 additions and 3 deletions
+14 -1
View File
@@ -145,6 +145,17 @@ func deliveryLevel(status string) string {
}
}
// sendLogRow is a row of the send log as the table draws it: the stored row
// plus the badge level its status maps onto. The level is carried rather than
// derived in the template because deliveryLevel is the one place that decides
// what a status means — the delivery page already reads it, and a second
// mapping written in the template or the stylesheet would be free to drift
// from it.
type sendLogRow struct {
store.SendLogRow
Level string // ok / warn / error / unknown, as deliveryLevel returns
}
// deliveryEvent is one step of a message's history, as the timeline on the
// delivery page draws it. At is zero for the step that has not happened yet —
// the delivery report a queued message is still waiting for.
@@ -324,8 +335,10 @@ func (h *Handlers) sendLogData(r *http.Request) (map[string]any, error) {
if err != nil {
return nil, err
}
view := make([]sendLogRow, len(rows))
for i := range rows {
rows[i].Subject = mailhdr.DecodeSubject(rows[i].Subject)
view[i] = sendLogRow{SendLogRow: rows[i], Level: deliveryLevel(rows[i].Status)}
}
domainNames := make([]string, 0, len(assigned))
@@ -358,7 +371,7 @@ func (h *Handlers) sendLogData(r *http.Request) (map[string]any, error) {
lastPage = int((total + sendLogPageSize - 1) / sendLogPageSize)
}
return map[string]any{
"Rows": rows,
"Rows": view,
"FilterDomains": domainNames,
"FilterApps": logins,
"FilterDomain": filter.Domain,
@@ -13,7 +13,7 @@
<td>{{.From}}</td>
<td>{{.To}}</td>
<td class="subject"><span title="{{.Subject}}">{{.Subject}}</span></td>
<td class="status">{{.Status}}</td>
<td class="status"><span class="st st-{{.Level}}">{{.Status}}</span></td>
<td class="actions"><a href="/deliveries/{{.ID}}?domain={{$.FilterDomain}}&app={{$.FilterApp}}&p={{$.Page}}">Details</a></td>
</tr>
{{end}}