feat(media): pagination

This commit is contained in:
Florian Sylvain committed 2026-10-13 19:54:59 +02:00
1 parent 04dc151ed7
commit 63c1e7076e
65 files changed
+2960 -365

No files matched your search

+18 -15
View File
@@ -226,7 +226,7 @@ function fixture(ids?: number[]): MediaItem[] {
}
function listBody(items: MediaItem[], counts = { all: 12, unused: 2, duplicates: 2 }) {
return { items, next_cursor: null, counts }
return { items, total: items.length, page: 1, size: 25, counts }
}
function listWithout(id: number) {
@@ -440,7 +440,7 @@ describe('Default, many images', () => {
)
expect(document.body.querySelector('h1')?.textContent?.trim()).toBe('Media')
expect(listCalls().map(([path]) => path)).toEqual([
'/v1/media/?filter=all&sort=newest&limit=100',
'/v1/media/?filter=all&sort=newest&page=1&size=25',
])
expect(tabs().map(textOf)).toEqual(['All 12', 'Unused 2', 'Duplicates 2'])
expect(tab('All').getAttribute('aria-selected')).toBe('true')
@@ -565,7 +565,8 @@ describe('List view', () => {
expect(router.currentRoute.value.query).toEqual({ view: 'list' })
expect(document.body.querySelectorAll('[data-testid="media-row"]')).toHaveLength(12)
expect(listCalls()).toHaveLength(1)
expect(listCalls()).toHaveLength(2)
expect(lastListPath()).toBe('/v1/media/?filter=all&sort=newest&page=1&size=25')
activate(ariaLabel('Grid view'))
await flushPromises()
@@ -603,14 +604,14 @@ describe('List view', () => {
describe('The query string is the source of truth', () => {
it.each([
['?filter=unused', 'filter=unused&sort=newest&limit=100'],
['?sort=largest', 'filter=all&sort=largest&limit=100'],
['?sort=name', 'filter=all&sort=name&limit=100'],
['?sort=oldest', 'filter=all&sort=oldest&limit=100'],
['?q=wall', 'q=wall&filter=all&sort=newest&limit=100'],
['?view=list', 'filter=all&sort=newest&limit=100'],
['?filter=bogus&sort=zzz', 'filter=all&sort=newest&limit=100'],
['?filter=duplicates', 'filter=duplicates&sort=newest&limit=100'],
['?filter=unused', 'filter=unused&sort=newest&page=1&size=25'],
['?sort=largest', 'filter=all&sort=largest&page=1&size=25'],
['?sort=name', 'filter=all&sort=name&page=1&size=25'],
['?sort=oldest', 'filter=all&sort=oldest&page=1&size=25'],
['?q=wall', 'q=wall&filter=all&sort=newest&page=1&size=25'],
['?view=list', 'filter=all&sort=newest&page=1&size=25'],
['?filter=bogus&sort=zzz', 'filter=all&sort=newest&page=1&size=25'],
['?filter=duplicates', 'filter=duplicates&sort=newest&page=1&size=100'],
])('opening /media%s requests %s', async (url, request) => {
await mountPage({}, `/media${url}`)
@@ -657,7 +658,7 @@ describe('The query string is the source of truth', () => {
vi.advanceTimersByTime(1)
await flushPromises()
expect(router.currentRoute.value.query).toEqual({ q: 'wall' })
expect(lastListPath()).toBe('/v1/media/?q=wall&filter=all&sort=newest&limit=100')
expect(lastListPath()).toBe('/v1/media/?q=wall&filter=all&sort=newest&page=1&size=25')
tab('Unused').focus()
press(tab('Unused'), 'Enter')
@@ -712,7 +713,7 @@ describe('The Duplicates tab', () => {
expect(tab('Duplicates').getAttribute('aria-selected')).toBe('true')
expect(router.currentRoute.value.query).toEqual({ filter: 'duplicates' })
expect(lastListPath()).toBe('/v1/media/?filter=duplicates&sort=newest&limit=100')
expect(lastListPath()).toBe('/v1/media/?filter=duplicates&sort=newest&page=1&size=100')
})
})
@@ -813,7 +814,7 @@ describe('Empty library and no results', () => {
vi.advanceTimersByTime(120)
await flushPromises()
expect(lastListPath()).toBe('/v1/media/?q=wall&filter=unused&sort=newest&limit=100')
expect(lastListPath()).toBe('/v1/media/?q=wall&filter=unused&sort=newest&page=1&size=25')
expect(document.body.textContent).toContain('No images match "wall"')
expect(document.body.textContent).toContain(
'Nothing matches in Unused. Check the spelling, or clear the filters.',
@@ -998,7 +999,9 @@ describe('Detail panel', () => {
await clickCard('floorboards.jpg')
expect(requestMock.mock.calls.some(([path]) => path === '/v1/media/?hash=0e')).toBe(true)
expect(
requestMock.mock.calls.some(([path]) => path === '/v1/media/?hash=0e&page=1&size=100'),
).toBe(true)
const alert = panel()!.querySelector('[data-testid="duplicate-alert"]')!
expect(textOf(alert)).toContain('Identical to 2 other images')
expect(textOf(alert)).toContain(