From c5609db0c73aaf45c86317e1bd74cec18afa8ff4 Mon Sep 17 00:00:00 2001 From: whit3rabbit Date: Fri, 19 Jun 2026 16:25:45 -0500 Subject: [PATCH] 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) --- CHANGELOG.md | 2 ++ crates/proxy/admin-ui/src/api/queries.ts | 12 ++++++++---- crates/proxy/admin-ui/src/api/types.ts | 8 ++++---- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26341d2..627c692 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. --- diff --git a/crates/proxy/admin-ui/src/api/queries.ts b/crates/proxy/admin-ui/src/api/queries.ts index 5e58153..bfefbaa 100644 --- a/crates/proxy/admin-ui/src/api/queries.ts +++ b/crates/proxy/admin-ui/src/api/queries.ts @@ -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({ 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({ 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, }) } diff --git a/crates/proxy/admin-ui/src/api/types.ts b/crates/proxy/admin-ui/src/api/types.ts index ca6eafc..fc98a69 100644 --- a/crates/proxy/admin-ui/src/api/types.ts +++ b/crates/proxy/admin-ui/src/api/types.ts @@ -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 }