perf: round 13 — grouped-view virtualization, notification/login query narrowing, HTTP dedup, locale precompute
Benchmark-gated (BEFORE/AFTER + equivalence/safety gate per change), same discipline as rounds 2-12. Full write-up in benches/ROUND13.md. Shipped: - V1 Grouped views windowed (files route + ResourceList). The grid arm was the last unwindowed path (trash is grouped-by-default in grid): each swimlane now feeds its own VirtualList, outer container a flex stack. vitest gate: 800-item grouped grid mounts <120 .file-item (was 800). - Q1 get_users_by_ids drops the <=512 KiB avatar image + ui_preferences JSONB (notification path never reads them). 30-member fan-out 8.60 -> 0.25 ms (34.3x), ~7.7 MB off the wire. - Q2 Login provisioning is_empty() -> SELECT EXISTS for calendar + address book (every login). 0.193 -> 0.170 ms, widens with owned-row count. - Q3 Recent-access prunes only when the upsert inserted (RETURNING xmax=0) — a re-access can't grow the set. 0.567 -> 0.324 ms (1.75x). - L1 Locale supported-codes precomputed once vs rebuilt per anonymous request. 616 -> 17.3 ns (35.7x), 18 -> 1 allocs. - H1 Duplicate /api TraceLayer removed (global stack already wraps it). 1.86 -> 1.42 us/request, -6 allocs. - H2 client_ip span field: borrow-only ClientIpDisplay vs owned String. 187 -> 173 ns, -1 alloc. Not shipped (discipline): the "media hooks read the blob 3x" lead was a correctness bug, not a perf dup — the raw-path metadata/faces readers resolve only for local+unencrypted+single-chunk blobs and silently produce nothing otherwise. Flagged for maintainers; routing through read_blob_bytes is a correctness fix (perf-neutral-to-negative), not a benchmark-gated perf change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BfidAJD5AHw23jtvBUNamB
This commit is contained in:
@@ -1455,9 +1455,6 @@
|
||||
// renders; `hiddenCount` above lets the template surface a "you're
|
||||
// hiding N items" hint so users aren't confused.
|
||||
const isEmpty = $derived(visibleFolders.length === 0 && visibleFiles.length === 0);
|
||||
const viewClass = $derived(
|
||||
filesStore.viewMode === 'grid' ? 'files-grid-view' : 'files-list-view'
|
||||
);
|
||||
|
||||
// Client-side sort (flat, Drive-style). The listing endpoint returns the
|
||||
// folder contents unsorted; sorting here avoids a refetch per column click.
|
||||
@@ -1562,6 +1559,25 @@
|
||||
return [...map.values()];
|
||||
});
|
||||
|
||||
// Each group's folders + files folded into ONE ordered `Entry` stream
|
||||
// (folders first, then files — the exact render order the un-windowed
|
||||
// `{#each folders}{#each files}` produced), so each swimlane can feed a
|
||||
// windowed <VirtualList> instead of mounting every row/card
|
||||
// (benches/ROUND13.md §V1). `buildFileRows` is intentionally identity-
|
||||
// and order-only: it must NOT read favoriteIds/sharedIds/selection, or a
|
||||
// single star/select toggle would rebuild every swimlane (the ROUND11
|
||||
// §S2 fine-grained-star invariant).
|
||||
const groupedEntries = $derived(
|
||||
groups.map((g) => ({
|
||||
key: g.key,
|
||||
label: g.label,
|
||||
entries: [
|
||||
...g.folders.map((folder) => ({ kind: 'folder' as const, folder })),
|
||||
...g.files.map((file) => ({ kind: 'file' as const, file }))
|
||||
] as Entry[]
|
||||
}))
|
||||
);
|
||||
|
||||
// ── Toolbar controls (upload split-button + group-by popup menu) ─────────
|
||||
// The group-by popup + sort-direction + view toggle live in the shared
|
||||
// <ListToolbar>; this page only owns the upload split-button dropdown.
|
||||
@@ -1893,17 +1909,34 @@
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="files-container" bind:clientWidth={gridWidth}>
|
||||
{#if groupBy !== ''}
|
||||
<div class={viewClass}>
|
||||
{#if groupBy !== '' && filesStore.viewMode === 'list'}
|
||||
<!-- Grouped list: each swimlane's rows are windowed (was: every row
|
||||
of every group mounted at once — benches/ROUND13.md §V1). -->
|
||||
<div class="files-list-view">
|
||||
{@render fileListHeader()}
|
||||
{#each groups as group (group.key)}
|
||||
{#each groupedEntries as group (group.key)}
|
||||
<div class="resource-list__swimlane-header">{group.label}</div>
|
||||
{#each group.folders as folder (folder.id)}
|
||||
{@render folderRow(folder)}
|
||||
{/each}
|
||||
{#each group.files as file (file.id)}
|
||||
{@render fileRow(file)}
|
||||
{/each}
|
||||
<VirtualList items={group.entries} rowHeight={56} key={entryKey} row={entryRow} />
|
||||
{/each}
|
||||
</div>
|
||||
{:else if groupBy !== ''}
|
||||
<!-- Grouped grid: a flex stack of (header + its own windowed card grid)
|
||||
per swimlane. The grid lives on each VirtualList's inner window via
|
||||
`windowClass`, so the outer stack isn't itself a grid. Was the last
|
||||
unwindowed path (benches/ROUND13.md §V1). -->
|
||||
<div class="files-grouped-grid">
|
||||
{#each groupedEntries as group (group.key)}
|
||||
<div class="resource-list__swimlane-header resource-list__swimlane-header--grid">
|
||||
{group.label}
|
||||
</div>
|
||||
<VirtualList
|
||||
items={group.entries}
|
||||
columns={gridColumns(gridWidth)}
|
||||
rowHeight={240}
|
||||
windowClass="files-grid-view"
|
||||
key={entryKey}
|
||||
row={entryRow}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{:else if filesStore.viewMode === 'list'}
|
||||
|
||||
Reference in New Issue
Block a user