Files
selfpost/internal/web/view/templates/health_body.html
T
mixandClaude Opus 5.5 ac985d03a8 sender check: connections and messages counted apart; downtime estimated when supervisord is silent (stage 2b)
Following the design commit df96690.

- Two columns (owner, 2026-10-14): sender_check_days.messages (migration
  0009, not deployed) holds the messages deferred mid-message, from
  cleanup's warning; deferred stays the connections smtpd turned away.
  AddSenderCheckDeferred takes which; the counter passes cleanup's as a
  message. The card has "Connections turned away" and "Messages deferred";
  it warns on either within 24 hours (one mark, as before).
- Supervisord silent at start: postfixStarted asks again every 2 s for 30 s
  (postfixState: started, running, known). With no answer the downtime is
  the time since the alive mark - an upper bound - booked with estimated = 1
  (sender_check_days.estimated, MAX over a day); the card prefixes such a
  period's time with "≈ " and its note says what ≈ means. Before, such a
  start counted nothing and the number the owner decides by read low.
- Help topic sender-check and the log topic word for word as the mockup
  (help.go).

Tests: store (connections and messages apart, a period with an estimated
day); logtail (cleanup's warnings are messages); cmd/panel (supervisord
silent: the time since the mark, estimated); view fixture and the Health
page at four columns with ≈; e2e reads the row's two counts (panel down:
connections; panel hung: messages). Schema at 0009 with the columns.

schema-migrations row 9, CHANGELOG [Unreleased], audit plan lines ticked
(two), roadmap 28/62.
Evidence: go vet ./... clean; go test of store, view, cmd/panel ok locally,
logtail but for the Windows-only test; the server run follows before the
push.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:16:02 +03:00

84 lines
4.1 KiB
HTML

{{/* The polled part of Health, in the page and in its fragment
(GET /server/health/fragment) alike. The left stack is the element that
polls (data-poll, outerHTML): all four of its boxes are readings. The right
stack ends in the static Configuration box, so its three readings are
swapped into place one by one, each box by its own id, when the fragment
marks them out of band (Health.AsFragment) - a fragment can replace only
the element that asked for it. */}}
{{define "health_body"}}{{template "health_stack" .}}
{{template "health_sockets" .}}
{{template "health_certificate" .}}
{{template "health_mail" .}}{{end}}
{{/* health_stack is the left stack: Processes, Sender check, Hostname and
reverse DNS, Machine. */}}
{{define "health_stack"}}<div class="column is-6" id="health-stack" data-poll aria-live="polite" hx-get="/server/health/fragment" hx-trigger="load" hx-swap="outerHTML">
{{template "box_open" .Processes}}
{{if .ProcessError}}
{{template "body_open"}}
<p class="has-text-danger">Could not ask supervisord for the process list.</p>
{{template "body_close"}}
{{else}}
<div class="table-container"><table class="table is-fullwidth">
<thead><tr><th>Program</th><th>State</th><th>Detail</th></tr></thead>
<tbody>{{range .ProcessRows}}
<tr><td>{{.Name}}</td><td>{{template "tag" .State}}</td><td class="sp-muted">{{.Detail}}</td></tr>{{end}}
</tbody>
</table></div>
{{end}}
{{template "box_close"}}
{{template "box_open" .SenderCheck}}
<div class="table-container"><table class="table is-fullwidth">
<thead><tr><th>Period</th><th>Panel not answering</th><th>Connections turned away</th><th>Messages deferred</th></tr></thead>
<tbody>{{range .SenderRows}}
<tr><td>{{.Period}}</td><td>{{.Down}}</td><td>{{.Deferred}}</td><td>{{.Messages}}</td></tr>{{end}}
</tbody>
</table></div>
{{template "body_open"}}
<p class="sp-muted">{{template "inline" .SenderNote}}</p>
{{template "body_close"}}
{{template "box_close"}}
{{template "box_open" .Hostname}}
{{template "body_open"}}
{{template "facts" .HostFacts}}
{{template "body_close"}}
{{template "box_close"}}
{{template "box_open" .Machine}}
<div class="table-container"><table class="table is-fullwidth">
<thead><tr><th>Resource</th><th>Usage</th><th>Detail</th></tr></thead>
<tbody>{{range .MachineRows}}
<tr><td>{{.Resource}}</td><td>{{if .Gauge}}<progress class="progress is-small {{.Gauge.Bar}} mb-1" value="{{.Gauge.Percent}}" max="100"></progress>{{.Gauge.Text}}{{else if .Usage}}<span class="sp-nowrap">{{.Usage}}</span>{{else}}<span class="sp-muted">—</span>{{end}}</td><td class="sp-muted">{{range .Detail}}<div>{{.}}</div>{{end}}</td></tr>{{end}}
</tbody>
</table></div>
{{template "box_close"}}
</div>{{end}}
{{define "health_sockets"}}{{template "box_open" .Sockets}}
<div class="table-container"><table class="table is-fullwidth">
<thead><tr><th>Milter</th><th>State</th></tr></thead>
<tbody>{{range .SocketRows}}
<tr><td>{{.Name}}{{if .Note}} <span class="sp-muted">· {{.Note}}</span>{{end}}<br><span class="sp-muted sp-mono sp-small">{{.Path}}</span>{{if .Detail}}<br><span class="sp-muted sp-small">{{.Detail}}</span>{{end}}</td><td>{{template "tag" .State}}</td></tr>{{end}}
</tbody>
</table></div>
{{template "box_close"}}{{end}}
{{define "health_certificate"}}{{template "box_open" .Certificate}}
{{template "body_open"}}
{{if .CertFacts}}{{template "facts" .CertFacts}}{{end}}
<p class="mt-4 {{if .CertProblem}}has-text-danger{{else}}sp-muted{{end}}">{{.CertDetail}}</p>
{{template "body_close"}}
{{template "box_close"}}{{end}}
{{/* health_mail is the Notification mail card. */}}
{{define "health_mail"}}{{template "box_open" .NotifyMail}}
<div class="table-container"><table class="table is-fullwidth">
<thead><tr><th>Record</th><th>State</th></tr></thead>
<tbody>{{range .NotifyRows}}
<tr><td>{{.Name}}<br><span class="sp-muted sp-mono sp-small">{{.Host}}</span></td><td>{{template "tag" .State}}</td></tr>{{end}}
</tbody>
</table></div>
{{template "body_open"}}
<p class="sp-muted">{{template "inline" .NotifyNote}}</p>
{{template "body_close"}}
{{template "box_close"}}{{end}}