Skip to content

fix(ui): forward init refresh + tick messages while splash is showing#5

Merged
torosent merged 1 commit into
mainfrom
fix/splash-drops-init-refresh
May 4, 2026
Merged

fix(ui): forward init refresh + tick messages while splash is showing#5
torosent merged 1 commit into
mainfrom
fix/splash-drops-init-refresh

Conversation

@torosent
Copy link
Copy Markdown
Owner

@torosent torosent commented May 4, 2026

Summary

Fixes a real bug where the active screen's first RefreshedMsg and first TickMsg were silently dropped while the splash was on screen, leaving users staring at 0 items · 0 running until they happened to switch screens or press r.

Root cause

    if _, isTick := msg.(state.TickMsg); isTick { ... }
    if scr, ok := m.screens[m.active]; ok { ... route to active screen ... }
}

The active screen's Init returns a tea.Batch that includes state.MakeRefreshedCmd (immediate fetch) and state.TickCmd (first poll). These run in goroutines and emit messages while the splash is still showing — which were dropped.

That alone broke the immediate fetch, but the kicker is clock.Real().Tick() returns time.After(d) — a one-shot channel. The screen's polling loop re-arms a new TickCmd only when it receives a TickMsg. If the first tick is dropped, the polling loop dies entirely.

End result: containers shown empty until the user switches screens (which re-runs that screen's Init) or hits r. You can see this clearly in the previous demo GIF — the screen shows 0 items for the first ~30 seconds even though demo data is fully populated.

Fix

Forward TickMsg, modal traffic, and other internal messages to the active screen even while the splash is up. The splash still owns KeyMsg and WindowSizeMsg via the typed cases above. (SplashDoneMsg continues to flip showSplash = false.)

Tests

Added TestAppForwardsInitMessagesDuringSplash in internal/ui/app_test.go. Verified locally:

  • Without the fix: test fails — view shows 0 items · 0 running, 0 exited.
  • With the fix: test passes — synthesized container row renders after splash dismissal.

Full suite (go test ./...) green.

Demo refresh

While I was here, regenerated docs/assets/c9s.gif against the fixed build and rewrote tools/demos/c9s.tape to a single dark-theme walk-through covering every major scenario:

  • Containers screen tour (help, filter, sort, inspect, pin, prune)
  • Number-shortcut nav through every resource (1-9, 0)
  • System sub-screens (:df, :dns, :property, :kernel)
  • Action modals (build, registry login)
  • v0.1.x features (:acr-login, :install-docker-shim)

The tape also sets up a fresh XDG_CONFIG_HOME so the recording always picks up the v0.1.4 default skin (k9s-gruvbox-dark) regardless of the recorder's local config.

The catch-all message-forwarding block in app.Update was gated
screen's Init (the immediate RefreshedMsg, plus the first TickMsg
from state.TickCmd) arrived while the splash was still on screen
and was silently dropped. Combined with clock.Real().Tick()
returning a one-shot channel via time.After, this killed the
auto-refresh polling loop entirely. The user saw '0 items · 0
running' until they happened to switch screens or press 'r'.

Now RefreshedMsg, TickMsg, and other internal messages are
forwarded to the active screen even while the splash is up; only
KeyMsg and WindowSizeMsg are still routed to the splash itself.

While I was here, also re-record docs/assets/c9s.gif against the
fixed build and rewrite tools/demos/c9s.tape to a single
dark-theme walk-through covering every major scenario. The tape
sets up a fresh XDG_CONFIG_HOME so the recording always picks up
the v0.1.4 default skin (k9s-gruvbox-dark) regardless of the
recorder's local config.
@torosent torosent merged commit 4e4c808 into main May 4, 2026
2 checks passed
@torosent torosent deleted the fix/splash-drops-init-refresh branch May 4, 2026 18:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant