feat: pagination in the SPA for the Sites and Authors lists
This commit is contained in:
1 parent
500ad59458
commit
340a0ad461
34 files changed
+2833
-896
No files matched your search
@@ -21,6 +21,20 @@ export interface Call {
|
||||
body: Record<string, unknown> | undefined
|
||||
}
|
||||
|
||||
export class PagedReply {
|
||||
body: unknown
|
||||
total: number
|
||||
|
||||
constructor(body: unknown, total: number) {
|
||||
this.body = body
|
||||
this.total = total
|
||||
}
|
||||
}
|
||||
|
||||
export function paged(body: unknown, total: number) {
|
||||
return new PagedReply(body, total)
|
||||
}
|
||||
|
||||
export type Responder = (call: Call) => unknown | Promise<unknown>
|
||||
|
||||
export interface Backend {
|
||||
@@ -177,12 +191,25 @@ function pageOf(backend: Backend, query: URLSearchParams) {
|
||||
}
|
||||
}
|
||||
|
||||
function sitePageOf(backend: Backend, query: URLSearchParams) {
|
||||
const q = (query.get('q') ?? '').toLowerCase()
|
||||
const size = Number(query.get('size') ?? 25)
|
||||
const page = Number(query.get('page') ?? 1)
|
||||
const matching = backend.sites.filter((item) =>
|
||||
`${item.name} ${item.key} ${item.base_url}`.toLowerCase().includes(q),
|
||||
)
|
||||
return new PagedReply(
|
||||
structuredClone(matching.slice((page - 1) * size, page * size)),
|
||||
matching.length,
|
||||
)
|
||||
}
|
||||
|
||||
export function defaultRoute(backend: Backend, call: Call): unknown {
|
||||
const { method, path, query, body } = call
|
||||
const siteMatch = /^\/v1\/site\/(\d+)(\/default)?$/.exec(path)
|
||||
const authorMatch = /^\/v1\/author\/(\d+)$/.exec(path)
|
||||
if (method === 'GET' && path === '/v1/site/') {
|
||||
return structuredClone(backend.sites)
|
||||
return query.has('page') ? sitePageOf(backend, query) : structuredClone(backend.sites)
|
||||
}
|
||||
if (method === 'POST' && path === '/v1/site/') {
|
||||
if (backend.sites.some((site) => site.key === body?.key)) {
|
||||
@@ -349,9 +376,20 @@ export async function mountDirectory(
|
||||
backend.responders[`${call.method} ${pathname}`]
|
||||
return responder ? responder(call) : defaultRoute(backend, call)
|
||||
})
|
||||
const requestPaged = vi.fn(async (path: string, init?: RequestInit) => {
|
||||
const result = await request(path, init)
|
||||
if (result instanceof PagedReply) {
|
||||
return { body: result.body, total: result.total }
|
||||
}
|
||||
if (Array.isArray(result)) {
|
||||
return { body: result, total: result.length }
|
||||
}
|
||||
return { body: result, total: (result as { total: number }).total }
|
||||
})
|
||||
vi.mocked(useApi).mockReturnValue({
|
||||
getMe: vi.fn().mockResolvedValue({ verified: true, username: 'marta', id: 1 }),
|
||||
request,
|
||||
requestPaged,
|
||||
} as unknown as ReturnType<typeof useApi>)
|
||||
await router.push(url)
|
||||
const component = view === 'sites' ? SitesView : AuthorsView
|
||||
|
||||
Reference in new issue
Block a user