Feed date filter: early-stop global feed load, fix cross-date validation, show Loading while fetching

- Stop fetching combined-feed pages once the oldest activity in a batch predates
  the from-date (feed is newest-first, so everything needed is already loaded)
- Show "Loading…" instead of "No activities found" while eager-load is in progress
- Constrain From max to customTo (or today) and To min to customFrom so the
  range can't be inverted via the date pickers
This commit is contained in:
Davide Scaini
2026-05-15 09:24:02 +02:00
parent 1f3f5b3d3b
commit 8a06227243
+11 -2
View File
@@ -161,6 +161,8 @@
$: if ((query.trim() || customFrom || customTo || datePre !== 'all') && feedNextPage > 0 && !loadingAllFeedPages) {
loadingAllFeedPages = true;
(async () => {
// Snapshot at loop start — customFrom may change while we're fetching.
const fromFilter = customFrom;
while (feedNextPage > 0) {
const page = feedNextPage;
feedNextPage = page < feedTotalPages ? page + 1 : 0;
@@ -171,6 +173,12 @@
all = [...existing.values()].sort((a, b) =>
(b.started_at ?? '').localeCompare(a.started_at ?? ''),
);
// Feed is sorted newest-first. Once the oldest activity in this page
// predates our from-filter, everything needed is already loaded.
if (fromFilter && fresh.length > 0) {
const oldest = fresh.reduce((m, a) => (a.started_at ?? '') < (m.started_at ?? '') ? a : m);
if ((oldest.started_at ?? '') < fromFilter) { feedNextPage = 0; break; }
}
} catch { /* ignore — partial results still useful */ }
}
loadingAllFeedPages = false;
@@ -260,7 +268,7 @@
<input
type="date"
bind:value={customFrom}
max={today}
max={customTo || today}
on:change={() => { datePre = 'all'; }}
class="bg-transparent text-white text-sm focus:outline-none [color-scheme:dark]"
/>
@@ -270,6 +278,7 @@
<input
type="date"
bind:value={customTo}
min={customFrom}
max={today}
on:change={() => { datePre = 'all'; }}
class="bg-transparent text-white text-sm focus:outline-none [color-scheme:dark]"
@@ -332,7 +341,7 @@
<p class="text-red-400 text-center py-12">Could not load activities: {error}</p>
{:else if withSearch.length === 0}
<p class="text-zinc-500 text-center py-12">
{#if query.trim()}No activities match "{query.trim()}".{:else}No activities found.{/if}
{#if loadingAllFeedPages || loadingAllShards}Loading…{:else if query.trim()}No activities match "{query.trim()}".{:else}No activities found.{/if}
</p>
{:else}
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">