1
0
forked from wrenn/wrenn

Fix capsules table blink on background poll refresh

Poll fetches now silently update data without triggering loading
states, spinner animations, or row fadeUp re-animations. Only manual
refresh shows the spin indicator.
This commit is contained in:
2026-03-25 19:44:13 +06:00
parent b0e6f5ffb3
commit 8d5ba3873a

View File

@ -56,6 +56,9 @@
// Briefly highlight a newly created capsule row
let newCapsuleId = $state<string | null>(null);
// Track whether initial load animation has played (suppress on poll refreshes)
let initialAnimationDone = $state(false);
let filteredCapsules = $derived.by(() => {
let list = searchQuery
? capsules.filter((c) => c.id.toLowerCase().includes(searchQuery.toLowerCase()))
@ -121,27 +124,33 @@
}
}
async function fetchCapsules() {
async function fetchCapsules(manual = false) {
const wasEmpty = capsules.length === 0;
if (wasEmpty) loading = true;
if (manual) {
spinning = true;
const spinTimer = new Promise<void>((resolve) => setTimeout(resolve, SPIN_DURATION));
var spinTimer = new Promise<void>((resolve) => setTimeout(resolve, SPIN_DURATION));
}
error = null;
const result = await listCapsules();
if (result.ok) {
capsules = result.data;
} else {
error = result.error;
}
loading = false;
// Mark initial entrance animation as done after first successful fetch
if (!initialAnimationDone) {
setTimeout(() => { initialAnimationDone = true; }, 400 + (capsules.length * 40));
}
if (autoRefresh) countdown = REFRESH_INTERVAL;
await spinTimer;
if (manual) {
await spinTimer!;
spinning = false;
}
}
async function handlePause(id: string) {
openMenuId = null;
@ -297,7 +306,7 @@
<!-- Refresh button -->
<button
onclick={fetchCapsules}
onclick={() => fetchCapsules(true)}
disabled={spinning}
class="flex h-8 w-8 items-center justify-center rounded-[var(--radius-button)] border border-[var(--color-border)] text-[var(--color-text-tertiary)] transition-colors duration-150 hover:border-[var(--color-border-mid)] hover:text-[var(--color-text-secondary)] disabled:opacity-50"
title="Refresh"
@ -415,7 +424,7 @@
{@const stripeColor = capsule.status === 'running' ? 'bg-[var(--color-accent)]' : capsule.status === 'paused' ? 'bg-[var(--color-amber)]' : 'bg-[var(--color-text-muted)]'}
<div
class="capsule-row relative grid grid-cols-[1.6fr_0.8fr_0.5fr_0.5fr_0.6fr_1fr_0.9fr] items-center overflow-hidden border-b border-[var(--color-border)] transition-colors duration-150 hover:bg-[var(--color-bg-3)] last:border-b-0 {newCapsuleId === capsule.id ? 'capsule-born' : ''}"
style="animation: fadeUp 0.35s ease both; animation-delay: {i * 40}ms"
style={initialAnimationDone ? '' : `animation: fadeUp 0.35s ease both; animation-delay: ${i * 40}ms`}
>
<!-- Left accent stripe -->
<div class="row-stripe pointer-events-none absolute left-0 top-0 h-full w-0.5 {stripeColor}"></div>