From 72ac1b3334d0d4255576ff71e2948b071e3fab9d Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Wed, 20 May 2026 23:23:36 +0000 Subject: [PATCH] fix(ui): skip revoked-key detection until the key list is known existingKeyIds defaulted to an empty Set, which made every live api_key row render as (revoked) during the brief window before apiKeysApi.list() resolved, and permanently after a fetch failure. Use null as the unknown state and suppress the revoked badge until the parent provides a real Set. Refs: #9862 Signed-off-by: Ettore Di Giacinto --- core/http/react-ui/src/pages/Usage/SourcesTab.jsx | 7 ++++--- core/http/react-ui/src/pages/Usage/SourcesTable.jsx | 9 ++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core/http/react-ui/src/pages/Usage/SourcesTab.jsx b/core/http/react-ui/src/pages/Usage/SourcesTab.jsx index 7682ce5d9..784f8a35b 100644 --- a/core/http/react-ui/src/pages/Usage/SourcesTab.jsx +++ b/core/http/react-ui/src/pages/Usage/SourcesTab.jsx @@ -28,8 +28,9 @@ export default function SourcesTab({ period, adminUserId }) { const [sortKey, setSortKey] = useState('tokens') // Pull the current set of API key ids so the table can mark unknown keys as - // revoked. Failure is non-fatal: the revoked badge just won't render. - const [existingKeyIds, setExistingKeyIds] = useState(new Set()) + // revoked. null = "don't know yet" so the table won't dim live keys during + // the fetch or after a failure. + const [existingKeyIds, setExistingKeyIds] = useState(null) useEffect(() => { apiKeysApi .list() @@ -37,7 +38,7 @@ export default function SourcesTab({ period, adminUserId }) { const list = Array.isArray(resp) ? resp : (resp?.keys || []) setExistingKeyIds(new Set(list.map((k) => k.id))) }) - .catch(() => { /* revoked detection is best-effort */ }) + .catch(() => { /* leave existingKeyIds null so revoked detection is skipped */ }) }, []) useEffect(() => { diff --git a/core/http/react-ui/src/pages/Usage/SourcesTable.jsx b/core/http/react-ui/src/pages/Usage/SourcesTable.jsx index 23fb9f1c6..00abc5f75 100644 --- a/core/http/react-ui/src/pages/Usage/SourcesTable.jsx +++ b/core/http/react-ui/src/pages/Usage/SourcesTable.jsx @@ -37,7 +37,10 @@ function formatRelative(iso) { // onSelectKey: (id|null) => void // search / setSearch: free-text filter state lifted to the parent // sortKey / setSortKey: sort column state lifted to the parent -// existingKeyIds: Set of current (non-revoked) api key ids +// existingKeyIds: Set of current (non-revoked) api key ids, or null +// when the parent hasn't yet learned which keys exist. Null suppresses the +// revoked badge entirely so live keys aren't dimmed during the fetch or +// after a failure. export default function SourcesTable({ totals, selectedKey, @@ -46,7 +49,7 @@ export default function SourcesTable({ setSearch, sortKey, setSortKey, - existingKeyIds = new Set(), + existingKeyIds = null, }) { const { t } = useTranslation('admin') @@ -59,7 +62,7 @@ export default function SourcesTable({ tokens: k.tokens, requests: k.requests, last_used: k.last_used, - revoked: !existingKeyIds.has(k.api_key_id), + revoked: existingKeyIds != null && !existingKeyIds.has(k.api_key_id), })) const web = totals?.by_source?.web ? [{