fix(admin-ui): correct keys unwrap + request/audit pagination

useKeys treated the {keys:[...]} response as a bare array, so the Keys
tab threw at runtime (.find/.filter on a plain object). Unwrap .keys to
match the VirtualKey[] consumers expect (mirrors useBackends).

useRequests and useAudit sent page/page_size, but the backends only read
limit/offset, so every page returned the first page. Translate at the
hook boundary (limit=page_size, offset=(page-1)*page_size) and align the
RequestsResponse/AuditResponse types with the actual backend shape
(limit/offset/has_more; drop the never-sent total/page/page_size).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
whit3rabbit
2026-06-19 16:25:45 -05:00
co-authored by Claude Opus 4.8
parent e10d906383
commit c5609db0c7
3 changed files with 14 additions and 8 deletions
+2
View File
@@ -15,6 +15,8 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follo
- Admin UI managed-backend edit form now seeds existing values instead of starting blank (no-op saves / apparent config wipe).
- Admin UI now refreshes Settings/Env on `config_changed` websocket events from other sessions or the CLI.
- Admin UI request-log and observability backend filters are now populated (were empty, dead controls).
- Admin UI Keys tab now renders again: the `useKeys` hook unwraps the `{keys:[...]}` response instead of treating it as a bare array (the tab threw at runtime).
- Admin UI request-log and audit pagination now send `limit`/`offset` (the backend params) instead of `page`/`page_size`, so paging past the first page works.
---
+8 -4
View File
@@ -56,8 +56,10 @@ export function useRequests(params: {
model?: string
}) {
const query = new URLSearchParams()
query.set('page', String(params.page))
query.set('page_size', String(params.page_size))
// Backend paginates by limit/offset, not page/page_size. Keep the page-based
// hook signature and translate at the boundary.
query.set('limit', String(params.page_size))
query.set('offset', String((params.page - 1) * params.page_size))
if (params.backend) query.set('backend', params.backend)
if (params.status) query.set('status', params.status)
if (params.since) query.set('since', params.since)
@@ -75,7 +77,8 @@ export function useRequests(params: {
export function useKeys() {
return useQuery<VirtualKey[]>({
queryKey: ['keys'],
queryFn: () => apiFetch('/admin/api/keys'),
// Backend returns { keys: [...] }; unwrap to the bare array consumers expect (mirrors useBackends).
queryFn: () => apiFetch<{ keys: VirtualKey[] }>('/admin/api/keys').then(r => r.keys),
staleTime: Infinity,
})
}
@@ -209,7 +212,8 @@ export function useDiscoverModels() {
export function useAudit(params: { page: number; page_size: number }) {
return useQuery<AuditResponse>({
queryKey: ['audit', params],
queryFn: () => apiFetch(`/admin/api/audit?page=${params.page}&page_size=${params.page_size}`),
// Backend paginates by limit/offset, not page/page_size; translate here.
queryFn: () => apiFetch(`/admin/api/audit?limit=${params.page_size}&offset=${(params.page - 1) * params.page_size}`),
staleTime: Infinity,
})
}
+4 -4
View File
@@ -38,9 +38,8 @@ export interface RequestLogEntry {
export interface RequestsResponse {
requests: RequestLogEntry[]
total: number
page: number
page_size: number
limit: number
offset: number
has_more: boolean
}
@@ -171,7 +170,8 @@ export interface AuditEntry {
export interface AuditResponse {
entries: AuditEntry[]
total: number
limit: number
offset: number
has_more: boolean
}