Merge branch 'fix/queue-pagination-envelope' — queue UI renders rows again

MR 6's backend + MR 7's UI had mismatched envelope assumptions. Backend
returned pagination as sibling fields to data; UI's ApiResponse<T> wrapper
only typed data, so 'body.data' (the queue) became undefined at runtime.
This commit is contained in:
2026-04-19 00:46:49 +02:00
2 changed files with 28 additions and 12 deletions

View File

@@ -180,11 +180,15 @@ func (h *Handler) ListQueue(c *gin.Context) {
c.JSON(apiErr.Status, apierror.NewResponse(apiErr))
return
}
// Envelope matches ApiResponse<T>{data, meta} convention used by the rest
// of the API (see web/src/lib/api/types.ts PaginationMeta).
c.JSON(http.StatusOK, gin.H{
"data": rows,
"total": total,
"limit": limit,
"offset": offset,
"data": rows,
"meta": gin.H{
"total": total,
"limit": limit,
"offset": offset,
},
})
}

View File

@@ -62,8 +62,7 @@ function parseLimit(raw: string | null): ValidLimit {
return (VALID_LIMITS as readonly number[]).includes(n) ? (n as ValidLimit) : 50;
}
type QueueListBody = {
data: DiscoveredMarket[];
type QueueMeta = {
total: number;
limit: number;
offset: number;
@@ -75,14 +74,27 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
const offset = (page - 1) * limit;
const [queueRes, statsRes] = await Promise.all([
serverFetch<QueueListBody>(`/admin/discovery/queue?limit=${limit}&offset=${offset}`, cookies),
serverFetch<DiscoveredMarket[]>(
`/admin/discovery/queue?limit=${limit}&offset=${offset}`,
cookies
),
serverFetch<Stats>(`/admin/discovery/stats`, cookies)
]);
// serverFetch casts the full JSON body as ApiResponse<T>; the actual response
// shape is { data: [...], total: N, limit: N, offset: N } so queueRes.data
// is the QueueListBody with all fields.
const body = queueRes.data;
return { queue: body.data, total: body.total, stats: statsRes.data, limit, offset, page };
// Pagination info lives on the envelope's `meta` field alongside `data`.
// apiFetch/serverFetch only types the `data` slot, so cast for meta access.
const meta = (queueRes as unknown as { meta?: QueueMeta }).meta ?? {
total: 0,
limit,
offset
};
return {
queue: queueRes.data,
total: meta.total,
stats: statsRes.data,
limit,
offset,
page
};
};
export const actions: Actions = {