ui: keep detail-page SSE swaps live after the first outerHTML replace
CI / Lint + build + test (push) Successful in 1m28s
Release / release (push) Successful in 6m29s

Pipeline fragment payload was a bare <div class=pipeline>, but the
sse-swap=pipeline-N wrapper lived only in the page shell. The first
outerHTML swap destroyed the wrapper, so every subsequent pipeline
event had nothing to target — forcing a manual refresh. RenderPipelineString
now emits the full <section id=pipeline-N sse-swap=... hx-swap=outerHTML>
wrapper, used from both the shell and the orchestrator publish path.

Also drop the red-bar styling from the empty DetailHold placeholder:
the wrapper's detail-hold class was painting an unconditional red band
between Pipeline and Actions whenever no hold was active.
This commit is contained in:
2026-04-18 17:03:39 -04:00
parent e73e31af92
commit cdd6cae3b0
5 changed files with 429 additions and 320 deletions
+17 -18
View File
@@ -34,15 +34,7 @@ templ HostDetail(d HostDetailData) {
@DetailSummary(d)
if d.Tile.Latest != nil {
<section
id={ fmt.Sprintf("pipeline-%d", d.Tile.Latest.ID) }
class="detail-section"
sse-swap={ fmt.Sprintf("pipeline-%d", d.Tile.Latest.ID) }
hx-swap="outerHTML"
>
<h2>Pipeline</h2>
@Pipeline(BuildPipeline(d.Tile.Latest, d.Stages))
</section>
@PipelineSection(d.Tile.Latest, BuildPipeline(d.Tile.Latest, d.Stages))
} else {
<section class="detail-section">
<h2>Pipeline</h2>
@@ -206,17 +198,24 @@ templ DetailSpecDiffs(d HostDetailData) {
// target. Keyed on run ID for the same reason as DetailSpecDiffs.
templ DetailHold(d HostDetailData) {
if d.Tile.Latest != nil {
<section
id={ fmt.Sprintf("detail-hold-%d", d.Tile.Latest.ID) }
class="detail-section detail-hold"
sse-swap={ fmt.Sprintf("detail-hold-%d", d.Tile.Latest.ID) }
hx-swap="outerHTML"
>
if d.Tile.Latest.State == model.StateFailedHolding && d.Tile.Latest.HoldIP != "" {
if d.Tile.Latest.State == model.StateFailedHolding && d.Tile.Latest.HoldIP != "" {
<section
id={ fmt.Sprintf("detail-hold-%d", d.Tile.Latest.ID) }
class="detail-section detail-hold"
sse-swap={ fmt.Sprintf("detail-hold-%d", d.Tile.Latest.ID) }
hx-swap="outerHTML"
>
<h2>Host is holding — SSH available</h2>
<code class="hold-ssh">{ sshInvocation(d.Tile.HoldKeyPath, d.Tile.Latest.HoldIP) }</code>
}
</section>
</section>
} else {
<section
id={ fmt.Sprintf("detail-hold-%d", d.Tile.Latest.ID) }
class="detail-hold-placeholder"
sse-swap={ fmt.Sprintf("detail-hold-%d", d.Tile.Latest.ID) }
hx-swap="outerHTML"
></section>
}
}
}