fix: dashboard infinite scroll re-appending the same batch of items#369
Open
builtbyproxy wants to merge 1 commit into
Open
fix: dashboard infinite scroll re-appending the same batch of items#369builtbyproxy wants to merge 1 commit into
builtbyproxy wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #352. The media dashboard's infinite scroll can get stuck repeating the same batch of items indefinitely while scrolling.
Root cause
MediaGridManager.loadMore()(web/templates/components/media-grid.templ) only advanced its rendering cursor (this.renderedItems) and resetthis.isLoadinginside thesetTimeout(..., delay)callback that kicks offrenderItems(). ButrenderItems()itself staggers each card's skeleton-to-content swap with its own per-itemsetTimeout(index * 50ms), so the grid keeps growing/reflowing well afterloadMore()'s own callback has already returned and clearedisLoading.Any layout reflow during that window (for example, the dashboard's default request-status filter running ~10ms after load, which briefly empties the grid via
clearGrid()) can nudge the scroll sentinel back into theIntersectionObserver'srootMarginand fireloadMore()again. Since the cursor hadn't advanced yet, the re-entrant call computes the exact samestartIndex/endIndex, re-slices the same items fromfilteredItems, and appends them again. If the reflow keeps happening (it does, since every subsequent stagger-swap reflows too), the same batch repeats indefinitely.Fix
Advance
renderedItemsandhasMoreDatasynchronously as soon asloadMore()decides which slice to load, before the rendersetTimeout. Any re-entrant call (spurious or otherwise) then always sees the next slice instead of the stale one, so it moves forward instead of repeating.Verification
jellysweep.dbthat the underlyingmediatable had zero duplicate rows (active row count,COUNT(DISTINCT jellyfin_id), andCOUNT(DISTINCT title)all matched) — the bug is purely in the frontend rendering cursor, not the data layer.go tool templ generateregeneratesmedia-grid_templ.gocleanly from the patched.templsource.go build ./...andgo vet ./...pass.Test plan
go build ./.../go vet ./...clean