diff --git a/client/components/app/LazyBookshelf.vue b/client/components/app/LazyBookshelf.vue index 920f13576..76fba3016 100644 --- a/client/components/app/LazyBookshelf.vue +++ b/client/components/app/LazyBookshelf.vue @@ -379,55 +379,49 @@ export default { let entityPath = this.entityName === 'series-books' ? 'items' : this.entityName const fullQueryString = this.getFetchQueryString(page) - const payload = await this.$axios.$get(`/api/libraries/${this.currentLibraryId}/${entityPath}${fullQueryString}`).catch((error) => { - console.error('failed to fetch items', error) - return null - }) + try { + const payload = await this.$axios.$get(`/api/libraries/${this.currentLibraryId}/${entityPath}${fullQueryString}`) + const results = Array.isArray(payload.results) ? payload.results : null + if (!results) { + throw new Error('Invalid browse payload: missing results array') + } - this.isFetchingEntities = false - if (this.pendingReset) { - this.pendingReset = false - this.resetEntities() - return - } - if (payload) { - try { - const results = Array.isArray(payload.results) ? payload.results : null - if (!results) { - throw new Error('Invalid browse payload: missing results array') + this.paginationMode = payload.paginationMode || this.paginationMode + this.nextCursor = payload.nextCursor || null + this.isCountDeferred = !!payload.isCountDeferred + + if (this.paginationMode === 'keyset') { + if (this.nextCursor) { + this.pageCursors[page + 1] = this.nextCursor + } else { + delete this.pageCursors[page + 1] } + } - this.paginationMode = payload.paginationMode || this.paginationMode - this.nextCursor = payload.nextCursor || null - this.isCountDeferred = !!payload.isCountDeferred + if (!this.initialized) { + this.initialized = true + this.totalEntities = payload.total + this.totalShelves = Math.ceil(this.totalEntities / this.entitiesPerShelf) + this.entities = new Array(this.totalEntities) + } - if (this.paginationMode === 'keyset') { - if (this.nextCursor) { - this.pageCursors[page + 1] = this.nextCursor - } else { - delete this.pageCursors[page + 1] - } + for (let i = 0; i < results.length; i++) { + const index = i + startIndex + this.entities[index] = results[i] + if (this.entityComponentRefs[index]) { + this.entityComponentRefs[index].setEntity(this.entities[index]) } + } - if (!this.initialized) { - this.initialized = true - this.totalEntities = payload.total - this.totalShelves = Math.ceil(this.totalEntities / this.entitiesPerShelf) - this.entities = new Array(this.totalEntities) - } - - for (let i = 0; i < results.length; i++) { - const index = i + startIndex - this.entities[index] = results[i] - if (this.entityComponentRefs[index]) { - this.entityComponentRefs[index].setEntity(this.entities[index]) - } - } - - this.$eventBus.$emit('bookshelf-total-entities', this.totalEntities) - } catch (error) { - console.error(`Failed to process page ${page}`, error) - return null + this.$eventBus.$emit('bookshelf-total-entities', this.totalEntities) + } catch (error) { + console.error(`Failed to load page ${page}`, error) + throw error + } finally { + this.isFetchingEntities = false + if (this.pendingReset) { + this.pendingReset = false + this.resetEntities() } } }, diff --git a/client/cypress/tests/components/app/LazyBookshelf.cy.js b/client/cypress/tests/components/app/LazyBookshelf.cy.js index e073e93d8..cf699faf5 100644 --- a/client/cypress/tests/components/app/LazyBookshelf.cy.js +++ b/client/cypress/tests/components/app/LazyBookshelf.cy.js @@ -121,7 +121,7 @@ describe('LazyBookshelf', () => { }) }) - it('clears progressive loading state when a keyset follow-up chunk fails', () => { + it('retries a failed keyset follow-up chunk after the initial load recovers', () => { const getStub = cy.stub() getStub.onFirstCall().resolves({ @@ -137,12 +137,28 @@ describe('LazyBookshelf', () => { paginationMode: 'keyset', isCountDeferred: true }) + getStub.onThirdCall().resolves({ + results: [{ id: 'item-2', mediaType: 'book', media: { metadata: { title: 'Beta' } } }], + total: 4, + nextCursor: null, + paginationMode: 'keyset', + isCountDeferred: true + }) cy.spy(console, 'error').as('consoleError') mountBookshelf(getStub).then(({ wrapper }) => { cy.wrap(getStub).should('have.been.calledTwice') cy.get('@consoleError').should('have.been.called') + cy.wrap(null) + .then(() => { + expect(wrapper.vm.pagesLoaded[1]).to.equal(undefined) + return wrapper.vm.loadPage(1) + }) + .then(() => { + expect(getStub).to.have.been.calledThrice + expect(wrapper.vm.entities[1].id).to.equal('item-2') + }) cy.wrap(null).then(() => { expect(wrapper.vm.isProgressiveLoading).to.equal(false) expect(wrapper.vm.progressiveLoadProgress).to.equal(100)