package templates import ( "bytes" "context" "fmt" "vetting/internal/model" ) // HostTile renders a single dashboard card. It's the SSE-swap target // for per-host tile refreshes (`tile-N`) and contains a per-run log // pane (`log-M`) whose live tail is appended by the events hub. templ HostTile(t TileData) {
{ t.Host.Name }
{ tileStatus(t.Latest) }
MAC
{ t.Host.MAC }
WoL
{ fmt.Sprintf("%s:%d", t.Host.WoLBroadcastIP, t.Host.WoLPort) }
if t.Latest != nil && t.Latest.FailedStage != "" {
Failed at
{ t.Latest.FailedStage }
} if t.SpecDiffCritical > 0 {
Spec diffs
{ fmt.Sprintf("%d critical", t.SpecDiffCritical) }
}
if t.Latest != nil && t.Latest.State == model.StateFailedHolding && t.Latest.HoldIP != "" {
Host is holding — SSH available
{ sshInvocation(t.HoldKeyPath, t.Latest.HoldIP) }
} if t.Latest != nil {
}
if canStart(t.Latest) {
} else { } if canOverrideWipe(t.Latest) {
} if hasReport(t.Latest) { View report }
} func canOverrideWipe(r *model.Run) bool { if r == nil { return false } return r.State == model.StateFailedHolding && r.FailedStage == "Storage" } // hasReport is true once the reporting stage has produced an HTML // artifact. We cheat slightly: Completed runs always have one, and // that's the only state in which the tile wants to surface a link. func hasReport(r *model.Run) bool { return r != nil && r.State == model.StateCompleted } func canStart(r *model.Run) bool { if r == nil { return true } switch r.State { case model.StateCompleted, model.StateReleased, model.StateFailedHolding: return true } return false } func tileStatus(r *model.Run) string { if r == nil { return "Idle" } return string(r.State) } func tileMood(r *model.Run) string { if r == nil { return "idle" } switch r.State { case model.StateCompleted: return "pass" case model.StateFailed, model.StateFailedHolding: return "fail" case model.StateReleased: return "idle" } return "active" } func sshInvocation(keyPath, ip string) string { if keyPath == "" { return "ssh root@" + ip + " (hold key not yet recorded)" } return fmt.Sprintf("ssh -i %s root@%s", keyPath, ip) } // RenderTileString renders a single tile fragment so the orchestrator // can publish it over SSE without threading a context through every // event publisher. func RenderTileString(t TileData) string { var buf bytes.Buffer _ = HostTile(t).Render(context.Background(), &buf) return buf.String() }