package templates import ( "fmt" "vetting/internal/model" ) // ActiveStepData is the per-stage payload for the expanded step panel. // The handler builds one per stage in DefaultStageOrder and hands it to // ActiveStep so the template stays free of any slicing logic. type ActiveStepData struct { RunID int64 Stage model.Stage SubSteps []model.SubStep LogReplay string Open bool } // ActiveStep renders one stage's expanded panel: the header summary // (state badge, stage name, duration), any sub-step rows, a per-step // search box, and a live log pane scoped to that stage's SSE topic. // Uses
so the server-picked default stage // opens automatically on page load; app.js takes over after that for // SSE-driven auto-advance. templ ActiveStep(d ActiveStepData) {
{ stageMarker(string(d.Stage.State)) } { d.Stage.Name } { stageDurationFromStage(d.Stage) }
if len(d.SubSteps) > 0 {
    for _, ss := range d.SubSteps { @SubStepRow(ss) }
}
@templ.Raw(d.LogReplay)
} // SubStepsForStage filters a flat []SubStep to just the entries for one // stage. Used by host_detail when wiring ActiveStepData — keeps the // filtering logic testable and off the template surface. func SubStepsForStage(all []model.SubStep, stageName string) []model.SubStep { out := make([]model.SubStep, 0, len(all)) for _, ss := range all { if ss.StageName == stageName { out = append(out, ss) } } return out } func stageDurationFromStage(s model.Stage) string { if d := elapsed(s.StartedAt, s.CompletedAt); d >= 0 { return fmtElapsed(d, false) } return "" }