mirror of
https://github.com/navidrome/navidrome.git
synced 2026-11-03 08:57:53 +01:00
* feat(ui): add perPageStore helper for items-per-page persistence * feat(ui): persist items-per-page selection in localStorage * feat(ui): enable per-page persistence on album grid, missing files and playlist tracks * feat(ui): restore saved album grid page size on fresh load * feat(ui): restore saved items-per-page on list load * fix(ui): move defaultRowsPerPageOptions to perPageStore to satisfy react-refresh lint * fix(ui): correct defaultRowsPerPageOptions import in List and add render test * refactor(ui): default getStoredPerPage fallback to the first option The fallback equalled options[0] at three of four call sites; default it so those sites stop restating it. SongList and useAlbumsPerPage still pass an explicit fallback where it legitimately differs from the first option. * fix(ui): persist only user-selected page sizes, validate album size against width Persisting on every pagination context value let a URL-injected perPage (e.g. the perPage=15 album link in NowPlayingPanel) or a forced single-option mobile grid overwrite the saved preference. Persist only a value that is an actual option in a multi-option selector. Also validate the album grid's redux session value against the current width so a size chosen at a wider breakpoint can't leave an out-of-range selector. * fix(ui): restore saved items-per-page on the radio list RadioList passed a hard-coded perPage that overrode List's stored seed via the props spread, so a radio-list page size was persisted but never restored. Seed it from storage like the other list views. * fix(ui): persist page size only on an actual selector change Watching the pagination context value meant any valid value persisted itself: loading a list at a breakpoint where the saved size is invalid stored the responsive fallback, and opening a URL with a valid ?perPage= stored that too, either way discarding the user's real preference. Inject a wrapped setPerPage instead, so only the rows-per-page selector writes. This also drops the option-validation heuristics, which the new trigger makes unnecessary.
27 lines
913 B
JavaScript
27 lines
913 B
JavaScript
import React from 'react'
|
|
import { render, screen } from '@testing-library/react'
|
|
import { describe, it, expect, vi } from 'vitest'
|
|
import { List } from './List'
|
|
|
|
// Only stub the heavy react-admin List controller (data fetching, router sync);
|
|
// everything else, including our own Pagination/perPageStore wiring, stays real
|
|
// so a bad import (the bug this test guards against) throws on render.
|
|
vi.mock('react-admin', async (importOriginal) => {
|
|
const actual = await importOriginal()
|
|
return {
|
|
...actual,
|
|
List: ({ children }) => <div data-testid="ra-list">{children}</div>,
|
|
}
|
|
})
|
|
|
|
describe('List', () => {
|
|
it('renders without throwing and shows its children', () => {
|
|
render(
|
|
<List resource="song">
|
|
<div>list content</div>
|
|
</List>,
|
|
)
|
|
expect(screen.getByTestId('ra-list')).toBeInTheDocument()
|
|
expect(screen.getByText('list content')).toBeInTheDocument()
|
|
})
|
|
})
|