From 121fd7280bc3f77c61da7025cca06480798038b7 Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Fri, 26 Jun 2026 23:37:44 +0900 Subject: fix(heartbeat): hide runs loading state to prevent sidebar flicker --- src/features/heartbeat/ui/HeartbeatView.svelte | 33 ++++++++++++++++---------- 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'src/features') diff --git a/src/features/heartbeat/ui/HeartbeatView.svelte b/src/features/heartbeat/ui/HeartbeatView.svelte index d584cb3..d2a7e96 100644 --- a/src/features/heartbeat/ui/HeartbeatView.svelte +++ b/src/features/heartbeat/ui/HeartbeatView.svelte @@ -133,22 +133,32 @@ // ── Runs list (polls while mounted) ─────────────────────────────────────── let runs = $state([]); - let runsLoading = $state(false); + /** True after the first successful load (gates the "No runs yet" empty state + * WITHOUT flashing it before the initial fetch resolves). The per-poll + * loading is intentionally INVISIBLE — it's near-instant and a visible + * loading indicator caused the sidebar to flicker every poll (height shift). */ + let hasLoadedRuns = $state(false); let runsError = $state(null); let stoppingId = $state(null); let stopError = $state(null); let pollHandle: ReturnType | null = null; + /** Re-entrancy guard for background polling (no UI — prevents overlapping fetches). */ + let refreshInFlight = false; const RUN_POLL_MS = 4000; async function refreshRuns(): Promise { - runsLoading = true; - runsError = null; + if (refreshInFlight) return; + refreshInFlight = true; const result = await loadRuns(); - runsLoading = false; + refreshInFlight = false; if (result === null) return; if (result.ok) { runs = viewRuns(result.runs); + // Clear the error only on success so it stays visible (stable, no + // flicker) during an in-flight retry rather than vanishing mid-poll. + runsError = null; + hasLoadedRuns = true; } else { runsError = result.error; } @@ -373,23 +383,16 @@ {#if runsError}

{runsError}

- {:else if runs.length === 0 && !runsLoading} -

No runs yet. Enable the heartbeat to start the loop.

- {:else} + {:else if runs.length > 0}
    {#each runsView as run (run.id)}
  • @@ -433,6 +436,10 @@ {#if stopError}

    {stopError}

    {/if} + {:else if hasLoadedRuns} + +

    No runs yet. Enable the heartbeat to start the loop.

    {/if} -- cgit v1.2.3