85 строки
3.3 KiB
Go
85 строки
3.3 KiB
Go
package webapp
|
|
|
|
import "net/http"
|
|
|
|
// handleChecks renders the worker's recent result rows. The
|
|
// runner's in-memory ring buffer supplies the data; Phase 1 reads
|
|
// from it directly with no extra caching.
|
|
//
|
|
// A "Run now" button is rendered on the page but stays disabled
|
|
// until the control plane accepts one-off check hints. The hint
|
|
// protocol is gated on the worker-notifier MVP plan
|
|
// (docs/plans/worker-notifier-mvp.md §N) and on
|
|
// docs/plans/separate-checks.md §11.6; once both are in place the
|
|
// RunNowEnabled flag flips to true and the handler reads
|
|
// s.deps.Runner.SubmitCheckHint(...) instead of the placeholder.
|
|
func (s *Server) handleChecks(w http.ResponseWriter, r *http.Request) {
|
|
s.renderRunnerPage(w, r, "Recent checks", "checks.html", func() any {
|
|
return checksPageData{
|
|
basePageData: s.newBasePage(r, "Recent checks", sessionFromContextOrEmpty(r)),
|
|
Rows: s.deps.Runner.RecentResults(50),
|
|
RunNowEnabled: false,
|
|
RunNowTooltip: "Run-now lands with the worker hint protocol (worker-notifier-mvp.md §N + separate-checks.md §11.6).",
|
|
}
|
|
})
|
|
}
|
|
|
|
type checksPageData struct {
|
|
basePageData
|
|
Rows []ResultRow
|
|
RunNowEnabled bool
|
|
RunNowTooltip string
|
|
}
|
|
|
|
// handleNotifications renders the worker's recent notification
|
|
// rows. Phase 1 only emits selfcheck alerts (email/telegram via the
|
|
// cached credentials), but the runner ring buffer is shape-stable
|
|
// for the main-app-issued notifications coming online in a later
|
|
// phase.
|
|
//
|
|
// A "Resend" button is rendered on the page but stays disabled
|
|
// until the worker resend protocol exists. Same gating as the
|
|
// "Run now" button on /checks.
|
|
func (s *Server) handleNotifications(w http.ResponseWriter, r *http.Request) {
|
|
s.renderRunnerPage(w, r, "Recent notifications", "notifications.html", func() any {
|
|
return notificationsPageData{
|
|
basePageData: s.newBasePage(r, "Recent notifications", sessionFromContextOrEmpty(r)),
|
|
Rows: s.deps.Runner.RecentNotifications(50),
|
|
ResendEnabled: false,
|
|
ResendTooltip: "Resend lands with the worker notification resend protocol (worker-notifier-mvp.md §N).",
|
|
}
|
|
})
|
|
}
|
|
|
|
type notificationsPageData struct {
|
|
basePageData
|
|
Rows []NotificationRow
|
|
ResendEnabled bool
|
|
ResendTooltip string
|
|
}
|
|
|
|
// renderRunnerPage is the small boilerplate-killer shared by
|
|
// handleChecks / handleNotifications / handleApps: write the
|
|
// no-store header, look up the session, build the page data via the
|
|
// caller-supplied closure, execute the template, and log + 500 on
|
|
// error. The closure receives no arguments because each handler
|
|
// already has its own copy of *Server and *http.Request in scope
|
|
// (this method is bound to *Server, so the closure captures them).
|
|
func (s *Server) renderRunnerPage(w http.ResponseWriter, _ *http.Request, logName, tmpl string, build func() any) {
|
|
writeNoStore(w)
|
|
if err := s.templates.Execute(w, tmpl, build()); err != nil {
|
|
s.deps.Logger.Printf("render %s: %v", logName, err)
|
|
http.Error(w, "template error", http.StatusInternalServerError)
|
|
}
|
|
}
|
|
|
|
// sessionFromContextOrEmpty is a thin wrapper around
|
|
// sessionFromContext that returns a nil session instead of a bool,
|
|
// for handlers that pass the session straight into a page-data
|
|
// struct (the Session zero value is harmless for template
|
|
// rendering).
|
|
func sessionFromContextOrEmpty(r *http.Request) *Session {
|
|
sess, _ := sessionFromContext(r.Context())
|
|
return sess
|
|
}
|