ui: stream host-detail fragments over SSE so the page updates live
The detail page was only partly live: Pipeline + LogTabs subscribed to SSE, but the summary header, actions row, spec-diffs list and hold-key block all froze at page-load and required a manual refresh to catch up with state changes. Extract each of those four regions into its own named templ component with a stable id and sse-swap target, add Render*String helpers so the orchestrator can publish pre-rendered fragments, and register a HostDetailRenderer alongside the existing Tile/Pipeline renderers. PublishHostDetail is folded into publishTileUpdate so every call site that already refreshes a tile now also refreshes the detail page — keeps the fan-out honest without scattering new publish calls. The empty-state wrappers for spec-diffs and hold are load-bearing: without the <section id=... sse-swap=...> present at initial GET, the first live event after SpecValidate or Hold writes would have no DOM node to swap into. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -692,14 +692,10 @@ func (a *Agent) Hold(w http.ResponseWriter, r *http.Request) {
|
||||
URL: a.runLinkURL(runID),
|
||||
})
|
||||
}
|
||||
// Refresh the tile so the operator sees the ssh command.
|
||||
host, _ := a.Hosts.Get(r.Context(), mustHostID(a, r, runID))
|
||||
if host != nil {
|
||||
latest, _ := a.Runs.Get(r.Context(), runID)
|
||||
if orchestrator.TileRenderer != nil {
|
||||
payload := orchestrator.TileRenderer(r.Context(), *host, latest)
|
||||
a.EventHub.Publish(events.Event{Name: fmt.Sprintf("tile-%d", host.ID), Payload: payload})
|
||||
}
|
||||
// Refresh the tile + all detail-page fragments so the operator
|
||||
// sees the ssh command and the hold banner without reloading.
|
||||
if id := mustHostID(a, r, runID); id != 0 && a.Runner != nil {
|
||||
a.Runner.PublishTileUpdate(r.Context(), id)
|
||||
}
|
||||
writeJSON(w, http.StatusOK, HoldResponse{AuthorizedKey: kp.AuthorizedKey, RunID: runID})
|
||||
}
|
||||
@@ -907,11 +903,11 @@ func (a *Agent) resolveReporting(r *http.Request, runID int64) {
|
||||
log.Printf("reporting: mark completed: %v", err)
|
||||
}
|
||||
a.appendLog(runID, "info", "Reporting: wrote "+path+"; run completed.")
|
||||
// Publish a final tile update so the dashboard flips to pass mood.
|
||||
if host != nil && orchestrator.TileRenderer != nil {
|
||||
latest, _ := a.Runs.Get(ctx, runID)
|
||||
payload := orchestrator.TileRenderer(ctx, *host, latest)
|
||||
a.EventHub.Publish(events.Event{Name: fmt.Sprintf("tile-%d", host.ID), Payload: payload})
|
||||
// Publish a final tile + detail update so the dashboard flips to
|
||||
// pass mood and the detail page's summary/actions update without
|
||||
// the operator reloading.
|
||||
if host != nil && a.Runner != nil {
|
||||
a.Runner.PublishTileUpdate(ctx, host.ID)
|
||||
}
|
||||
hostName := "host"
|
||||
if host != nil {
|
||||
|
||||
Reference in New Issue
Block a user