feat(desktop): paginate stream particles via windowed Firestore subscription #296
Reference in New Issue
Block a user
Delete Branch "claude/paginated-firestorm-particles-omb5bs"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Streams previously prefetched every particle through an unbounded Firestore
subscription. This adds a windowed source that anchors a
created_at desclimit query at the newest particle and grows it backward on demand, so the
already-seen history before a viewer's playback marker is no longer loaded.
useWindowedStreamParticles: tail-anchored live window that grows backwardto cover the resume marker and to service
loadOlder()(list scroll-up).Because the window always includes the newest particle, new arrivals stream
in and forward playback never needs a fetch. Includes anti-eviction growth
so a new tail particle never pushes loaded particles out of the window.
useStreamPlayback: consumes the windowed source instead of loading allchildren. New-tail and removal handling are derived from the children array
(Firestore change events can't tell a genuine arrival from pagination
backfill). Resume-from-marker waits for backward growth to reach an older
marker;
prevat the window edge pulls in older history.Playback resume, forward-only marker persistence, auto-advance-on-new, and
removal fallback are all preserved. List view and progress indicator continue
to render off the (now windowed) children; their pagination UX is a follow-up.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01V8gsmdVd7R8PJtn4UFnC4J
Summary by CodeRabbit
ℹ️ Recent review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Free
Run ID:
a7dcaead-cd97-4c6c-92e3-d67fcc34d181📥 Commits
Reviewing files that changed from the base of the PR and between
af69f98583and362a22bbc6.📒 Files selected for processing (5)
js/desktop/src/components/ui/scroll-area.tsxjs/desktop/src/features/particles/playback-page-indicator.tsxjs/desktop/src/features/particles/stream-bottom-bar.tsxjs/desktop/src/features/particles/stream-list-sidebar.tsxjs/desktop/src/features/particles/stream-view.tsx📝 Walkthrough
Walkthrough
Introduces
useWindowedStreamParticles, a tail-anchored Firestore hook with dynamic anti-eviction and backward-coverage growth that maintains a windowed view of particles. RewiresuseStreamPlaybackto use this hook instead of live Firestore subscriptions, extends its return value with backward pagination controls, and integrates those controls throughout the playback UI (page indicator, bottom bar, list sidebar) with scroll preservation and intersection-observer-driven older-item loading.Changes
Windowed particle stream and playback rewiring
useWindowedStreamParticleshookjs/desktop/src/hooks/use-windowed-stream-particles.tscreated_atdescending with dynamic limit. On new snapshots, freezes backward-coverage target from marker, tracks newest/oldest timestamps, grows limit to prevent anti-eviction when new tail items saturate the query, and grows limit by page size to cover the marker when saturated. Exposes reversed (ascending) children,loadOlder()callback, and loading/error flags. Returns inert result when path is undefined.useStreamPlaybackcore rewiringjs/desktop/src/hooks/use-stream-playback.tsuseLiveParticleChildrenwithuseWindowedStreamParticles, extends return type withhasMoreOlder,loadOlder,isLoadingOlder. DerivescurrentIndexandcurrentParticlefrom the loaded window. Replaces Firestore add/remove callbacks with effects that track new tail IDs (dispatchPARTICLE_ADDEDfor auto-advance) and detect removal of current particle from window (dispatchPARTICLE_REMOVED). Updates stream-reset block.prevnavigation, and returnjs/desktop/src/hooks/use-stream-playback.tshasMoreOlderis true, waits viainitFallbacktimeout instead of initializing to oldest; if history is exhausted, catches up to last loaded particle. Updatesprevcallback to callloadOlder()when at window start and older history exists, otherwise navigates backward within window. Preserves forward-progress guard on persisted marker update. Returns pagination fields.ScrollAreaviewport ref supportjs/desktop/src/components/ui/scroll-area.tsxviewportRefprop and forwards it to the underlying viewport primitive, enabling components to access and control scroll position.PlaybackPageIndicatorwindowed displayjs/desktop/src/features/particles/playback-page-indicator.tsxtotal,PAGE_SIZE) to sliding-window view usingloadedCountandVISIBLE_SEGMENTS. Computes clamped visible slice from current index. Adds optionalhasMoreOlderandonLoadOlderprops. Rewires stub navigation intogoOlder/goNewerhandlers, withgoOlderinvokingonLoadOlderwhen scrolling to oldest segment. Updates rendered segments to use slice-derived indices.BottomBarpagination props and wiringjs/desktop/src/features/particles/stream-bottom-bar.tsxtotaland addloadedCountwithhasMoreOlderandonLoadOlder. Rewires bothPlaybackPageIndicatorrender sites to pass new pagination props.StreamListSidebarscroll preservation and older-history loaderjs/desktop/src/features/particles/stream-list-sidebar.tsxhasMoreOlder,onLoadOlder,isLoadingOlder. Adds scroll position preservation via anchor-before-load and restore-after-items pattern usinguseLayoutEffect. ImplementsIntersectionObserveron top sentinel to triggeronLoadOlderwhen user scrolls near top and older items exist. Switches fromcurrentIndex-driven scrolling toselectedId-driven scrolling (scrolls only on true selection change). PassesviewportReftoScrollAreaand conditionally renders loader indicator.StreamViewInnerpagination wiringjs/desktop/src/features/particles/stream-view.tsxuseStreamPlaybackdestructuring to includehasMoreOlder,loadOlder,isLoadingOlder. Threads these values andloadedCountintoBottomBar(replacingtotal), and threads pagination state intoStreamListSidebarin list mode.Sequence Diagram(s)
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~75 minutes
Poem
Comment
@coderabbitai helpto get the list of available commands and usage tips.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.