feat(ui): slim dashboard tile to hostname + online/offline only
Run status, Start/Cancel/View controls, and non-destructive toggle all
live on /hosts/{id} — duplicating them on the dashboard tile clogged
the grid and wouldn't scale past a handful of hosts.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -40,17 +40,15 @@ func TestHumanAgoFrom(t *testing.T) {
|
||||
}
|
||||
|
||||
// TestHostTile_OverlayLink asserts the tile includes the tile-link <a>
|
||||
// that makes the whole card clickable. The action button stays a
|
||||
// sibling element, so CSS (z-index) keeps it on top of the overlay.
|
||||
//
|
||||
// Heartbeat must be fresh because canStart now gates on LastSeenAt —
|
||||
// an offline host renders a disabled button (no form), which is
|
||||
// covered by TestHostTile_DisabledStartWhenOffline below.
|
||||
// that makes the whole card clickable, and that the dashboard tile is
|
||||
// stripped down to just hostname + last-seen badge — no action controls
|
||||
// or run-state UI clogging the dashboard at scale.
|
||||
func TestHostTile_OverlayLink(t *testing.T) {
|
||||
now := time.Now()
|
||||
data := TileData{
|
||||
Host: model.Host{ID: 42, Name: "tile-test", MAC: "aa:bb:cc:dd:ee:ff"},
|
||||
LastSeenAt: &now,
|
||||
Latest: &model.Run{State: model.StateCompleted},
|
||||
}
|
||||
var buf strings.Builder
|
||||
if err := HostTile(data).Render(context.Background(), &buf); err != nil {
|
||||
@@ -63,39 +61,21 @@ func TestHostTile_OverlayLink(t *testing.T) {
|
||||
if !strings.Contains(html, `class="tile-link"`) {
|
||||
t.Fatalf("tile missing tile-link class: %s", html)
|
||||
}
|
||||
// Fresh heartbeat + no run → Start form must render.
|
||||
if !strings.Contains(html, `/hosts/42/start`) {
|
||||
t.Fatalf("expected Start vetting form in tile: %s", html)
|
||||
}
|
||||
// Dropped content that used to live on the tile — confirm it has
|
||||
// actually moved off so the slim-down is real.
|
||||
for _, dropped := range []string{`tile-meta`, `tile-log`, `tile-actions`, `tile-hold`} {
|
||||
for _, dropped := range []string{
|
||||
`tile-meta`, `tile-log`, `tile-actions`, `tile-hold`,
|
||||
`tile-primary-action`, `tile-status`, `tile-start-form`,
|
||||
`tile-nd-toggle`, `tile-cancel-form`,
|
||||
`/hosts/42/start`, `/hosts/42/cancel`,
|
||||
`Start vetting`, `Non-destructive`, `Cancel run`, `View report`,
|
||||
} {
|
||||
if strings.Contains(html, dropped) {
|
||||
t.Errorf("slim tile still contains dropped class %q", dropped)
|
||||
t.Errorf("slim tile still contains dropped content %q", dropped)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestHostTile_DisabledStartWhenOffline: no heartbeat → disabled button
|
||||
// with the quick.sh tooltip, not a submittable form. Mirrors the
|
||||
// server-side StartRun 409 so the UI matches the handler.
|
||||
func TestHostTile_DisabledStartWhenOffline(t *testing.T) {
|
||||
data := TileData{
|
||||
Host: model.Host{ID: 42, Name: "tile-test", MAC: "aa:bb:cc:dd:ee:ff"},
|
||||
}
|
||||
var buf strings.Builder
|
||||
if err := HostTile(data).Render(context.Background(), &buf); err != nil {
|
||||
t.Fatalf("render: %v", err)
|
||||
}
|
||||
html := buf.String()
|
||||
if strings.Contains(html, `/hosts/42/start`) {
|
||||
t.Fatalf("offline host should not expose a Start form: %s", html)
|
||||
}
|
||||
if !strings.Contains(html, `disabled`) || !strings.Contains(html, `quick.sh`) {
|
||||
t.Fatalf("expected disabled Start button with quick.sh tooltip: %s", html)
|
||||
}
|
||||
}
|
||||
|
||||
// TestHostTile_NoStageStrip: the tile no longer carries the Phase 3
|
||||
// per-stage mini run-view — the runs-table on /hosts/{id} owns the
|
||||
// stage-strip now. Guards against the regression that would bring
|
||||
|
||||
Reference in New Issue
Block a user