e69da2a99b
The only operational surface was /healthz and a fold-out roster inside the owner's own reading page. This gives the owner a page: two sections of facts on the same measured sheet, no cards. - admin.go holds every route that reaches past the acting Reader, listed once in adminRoutes() and wrapped in requireOwner at registration - a missing gate is visible in the route list rather than hidden inside a handler. A non-owner gets 404, the same answer revoke already gave. - Lane figures arrive through the LaneReporter seam, so the page reads the running poller rather than a table. newRouter converts a nil *Poller to a nil interface: a typed nil would make the page claim a poller exists. - The roster moves out of the reading page and gains the Sighting counters, the blocked verdict and Clear marks. Clearing restores a privilege, so it is a plain ghost button; --danger stays with revocation. - --patina is the page's one accent, held at the weight of the other action accents. Neither --ember (new chapter) nor --danger (destruction) is borrowed for system health.
37 lines
1.6 KiB
HTML
37 lines
1.6 KiB
HTML
{{/* Poll Lane status: one row per Site, refreshing itself so a run can be
|
|
watched rather than sampled by reloading. The refresh is one attribute on
|
|
the fragment root and the endpoint answers with this same fragment, so the
|
|
swap replaces the element that asked for it.
|
|
|
|
Every figure here is read out of the running poller, never out of a table:
|
|
a Site absent from Rows has not completed a pass since the last restart,
|
|
which the empty state must say — zeroes would read as a stopped Lane. */}}
|
|
{{define "lanes"}}
|
|
<section class="lanes" id="lanes" aria-live="polite"
|
|
hx-get="/ui/admin/lanes" hx-trigger="every 30s" hx-swap="outerHTML">
|
|
<h2>Poll Lanes</h2>
|
|
{{if .Rows}}
|
|
<ul class="lanelist">
|
|
{{range .Rows}}
|
|
<li{{if .Attention}} class="attention"{{end}}>
|
|
<span class="lane-site">{{.Site}}</span>
|
|
<span class="lane-fact">{{.Due}} due</span>
|
|
<span class="lane-fact">ran {{.Ran}}</span>
|
|
<span class="lane-fact">gap {{.Gap}}</span>
|
|
{{if .Clamped}}<span class="lane-mark">gap at floor</span>{{end}}
|
|
{{if .Refusing}}<span class="lane-mark">refusing</span>{{end}}
|
|
{{if .BrowserLost}}<span class="lane-mark">no browser</span>{{end}}
|
|
</li>
|
|
{{end}}
|
|
</ul>
|
|
{{else}}
|
|
<p class="setup-copy">No data yet — no Lane has completed a pass since the
|
|
backend started.</p>
|
|
{{end}}
|
|
<p class="setup-copy lane-browser">Browser sidecar:
|
|
{{if not .BrowserConfigured}}not configured — comix, kagane and novelfull
|
|
pages are not fetched through it{{else if .BrowserReachable}}reachable
|
|
{{else}}unreachable{{end}}.</p>
|
|
</section>
|
|
{{end}}
|