From 87cb33cffe3416bd892bad9e8821b39b58092cc0 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Sat, 9 May 2026 14:47:12 +0300 Subject: [PATCH] fix(frontend): stop event-log flicker on pagination MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pagination/filter reloads were collapsing the panel into a "Loading events…" placeholder and then replaying the stagger entry animation, which read as the whole section being reconstructed. Keep the existing rows + paginator mounted during reload (with a soft dim) and only run the aurora-rise cascade on the very first non-empty render. --- frontend/src/routes/+page.svelte | 42 +++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 0acd48c..3845141 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -96,6 +96,10 @@ let confirmClearEvents = $state(false); let refreshSeconds = $state(loadRefreshSeconds()); let selectedEvent = $state(null); + // Stagger entry animation should play once on initial load only — + // without this, every pagination/filter change re-runs the cascade + // (~600ms of fade-up per row) which reads as the panel "reconstructing". + let eventsAnimated = $state(false); // Auto-refresh ticker — re-creates the interval whenever the user // changes the cadence. ``$effect`` returns a cleanup that fires on @@ -279,6 +283,16 @@ } } + // Disable stagger entry animation once the first non-empty list has + // rendered + had time to play. Subsequent pagination/filter reloads + // then settle in place instead of re-running the cascade. + $effect(() => { + if (eventsAnimated) return; + if (!status?.recent_events?.length) return; + const handle = setTimeout(() => { eventsAnimated = true; }, 700); + return () => clearTimeout(handle); + }); + const filteredProviderCount = $derived(globalProviderFilter.providerType ? providers.filter(p => p.type === globalProviderFilter.providerType).length : displayProviders); @@ -675,18 +689,23 @@ {/snippet} - {#if eventsLoading} -

{t('dashboard.loadingEvents')}

- {:else if status.recent_events.length === 0} -
- -

{t('dashboard.noEvents')}

-
+ {#if status.recent_events.length === 0} + {#if eventsLoading} +

{t('dashboard.loadingEvents')}

+ {:else} +
+ +

{t('dashboard.noEvents')}

+
+ {/if} {:else} -
+
{#each status.recent_events as event, i (event.id)}