ui: split /hosts/{id} into host page + /runs/{runID} run page
Host page owns host metadata, full runs table with per-row stage strip, in-flight banner, and empty-state CTA. Run page owns pipeline, active step, logs, sub-steps, spec diffs, and hold banner with a breadcrumb back to the host. Dashboard tile reverts to host-only. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+31
-19
@@ -78,7 +78,6 @@ func main() {
|
||||
|
||||
tiles := &api.TileEnricher{
|
||||
Runs: runStore,
|
||||
Stages: stageStore,
|
||||
Artifacts: artifactStore,
|
||||
SpecDiffs: specDiffStore,
|
||||
}
|
||||
@@ -113,28 +112,41 @@ func main() {
|
||||
PublicURL: cfg.Server.PublicURL,
|
||||
}
|
||||
|
||||
// Inject the host-detail fragment renderer. The closure reuses
|
||||
// LoadHostDetailData so the SSE-pushed HTML matches an identical
|
||||
// reload-rendered page byte-for-byte, then hands each region to
|
||||
// its Render*String helper.
|
||||
orchestrator.HostDetailRenderer = func(ctx context.Context, hostID int64) (orchestrator.HostDetailFragments, bool) {
|
||||
// Orchestrator-side publishes always reference the latest run —
|
||||
// SSE topics are keyed by runID, so a stale ?run=N bookmark
|
||||
// doesn't affect what the server pushes.
|
||||
d, err := ui.LoadHostDetailData(ctx, hostID, 0)
|
||||
// Inject the host-page + run-page fragment renderers. Each reuses
|
||||
// the matching LoadHostPageData / LoadRunPageData so SSE-pushed HTML
|
||||
// matches an initial page load byte-for-byte, then hands each region
|
||||
// to its Render*String helper.
|
||||
orchestrator.HostPageRenderer = func(ctx context.Context, hostID int64) (orchestrator.HostPageFragments, bool) {
|
||||
d, err := ui.LoadHostPageData(ctx, hostID)
|
||||
if err != nil {
|
||||
return orchestrator.HostDetailFragments{}, false
|
||||
return orchestrator.HostPageFragments{}, false
|
||||
}
|
||||
f := orchestrator.HostDetailFragments{
|
||||
Summary: templates.RenderDetailSummaryString(d),
|
||||
Actions: templates.RenderDetailActionsString(d),
|
||||
SpecDiffs: templates.RenderDetailSpecDiffsString(d),
|
||||
Hold: templates.RenderDetailHoldString(d),
|
||||
rows := make(map[int64]string, len(d.Runs))
|
||||
for _, r := range d.Runs {
|
||||
rows[r.ID] = templates.RenderRunRowString(templates.RunRowData{
|
||||
Run: r,
|
||||
Stages: d.RunStages[r.ID],
|
||||
Live: d.ActiveRun != nil && d.ActiveRun.ID == r.ID,
|
||||
})
|
||||
}
|
||||
if d.Tile.Latest != nil {
|
||||
f.LatestRunID = d.Tile.Latest.ID
|
||||
return orchestrator.HostPageFragments{
|
||||
Summary: templates.RenderHostSummaryString(d),
|
||||
Actions: templates.RenderHostActionsString(d),
|
||||
InFlightBanner: templates.RenderInFlightBannerString(d),
|
||||
RunRows: rows,
|
||||
}, true
|
||||
}
|
||||
|
||||
orchestrator.RunPageRenderer = func(ctx context.Context, runID int64) (orchestrator.RunPageFragments, bool) {
|
||||
d, err := ui.LoadRunPageData(ctx, runID)
|
||||
if err != nil {
|
||||
return orchestrator.RunPageFragments{}, false
|
||||
}
|
||||
return f, true
|
||||
return orchestrator.RunPageFragments{
|
||||
Header: templates.RenderRunHeaderString(d),
|
||||
Hold: templates.RenderHoldBannerString(d),
|
||||
SpecDiffs: templates.RenderRunSpecDiffsString(d),
|
||||
}, true
|
||||
}
|
||||
|
||||
agentAPI := &api.Agent{
|
||||
|
||||
Reference in New Issue
Block a user