feat(ui): add block/unblock key action to key info page - #34116
Conversation
Adds a Block Key / Unblock Key action to the key info page, wired to the existing /key/block and /key/unblock endpoints which previously had no UI. The Reset Spend and Delete Key buttons move together with it into a new overflow dropdown next to Regenerate Key, and a red Blocked tag shows next to the key alias while the key is blocked.
Greptile SummaryThis PR adds block and unblock actions to the key information page. The main changes are:
Confidence Score: 5/5This looks safe to merge.
|
| Filename | Overview |
|---|---|
| ui/litellm-dashboard/src/app/(dashboard)/hooks/keys/useSetKeyBlockedState.ts | Adds an authenticated mutation using the shared API client and invalidates key queries after success. |
| ui/litellm-dashboard/src/components/networking.tsx | Exports the existing shared API client for use by dashboard hooks. |
| ui/litellm-dashboard/src/components/templates/KeyInfoHeader.tsx | Moves destructive actions into an overflow menu and displays the blocked state. |
| ui/litellm-dashboard/src/components/templates/key_info_view.tsx | Adds permission-gated block and unblock confirmation flows with local state updates and notifications. |
| ui/litellm-dashboard/src/app/(dashboard)/hooks/keys/useSetKeyBlockedState.test.ts | Covers endpoint selection, payloads, errors, authentication checks, and cache invalidation. |
| ui/litellm-dashboard/src/components/templates/KeyInfoHeader.test.tsx | Covers dropdown actions, conditional visibility, callbacks, disabled regeneration, and blocked-state rendering. |
Reviews (1): Last reviewed commit: "feat(ui): add block/unblock key action t..." | Re-trigger Greptile
|
QA'd this end-to-end on BEFORE (base AFTER (this PR) — full flow: Live proxy proof (same throwaway key, The dropdown item correctly flips between "Block Key" and "Unblock Key" based on state, and the confirm modals show the expected copy (block warns about the 401; unblock is lighter). |
…grations (#34206) Delete Key moved into the key info page's overflow dropdown (#34116) and the credentials table's row actions moved into a shared DataTable overflow menu, so both specs were clicking a button that no longer exists. Point them at the menu items instead. Add a CredentialsPanel unit test asserting the update payload drops the masked api key and keeps the edited api base, so that guard is not held up solely by an e2e a table migration can silently disarm.
…n UI The key info header moved Delete Key into the More key actions menu (#34116) and the credentials table moved row actions into a dropdown with data-testids (shared DataTable migration), so both specs timed out looking for buttons that no longer exist. Reproduced against a proxy serving a fresh dashboard build; both pass after pointing them at the menus.
Relevant issues
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
Verified end to end at commit 75d708c against a live proxy on localhost:4000 with the dashboard dev server on localhost:3000. UI flow, with screenshots to follow in a comment:
curl -X POST http://localhost:4000/key/generate -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"key_alias": "block-ui-test-key", "models": []}'Type
🆕 New Feature
Changes
The proxy has had
/key/blockand/key/unblockendpoints for a long time, but the Admin UI never exposed them; the keys table can render a Blocked status (e.g., for SCIM-deactivated users) yet there was no way to set it. This PR adds the action to the key info pageThe Reset Spend and Delete Key buttons in the key info header are replaced by a "..." overflow dropdown next to Regenerate Key holding the three destructive actions: Block Key (or Unblock Key when the key is already blocked), Reset Spend, and Delete Key. Blocking asks for confirmation and explains that requests will be rejected with a 401 until unblocked; unblocking asks for a lighter confirmation. While blocked, a red Blocked tag renders next to the key alias
The new
useSetKeyBlockedStatehook posts to/key/blockor/key/unblockthrough the sharedapiClient(rawfetchis lint-banned outsidesrc/lib/http/) and invalidates the keys query cache on success so the table status badge stays in sync. Blocking is offered to proxy admins and team admins, matching the reset spend gating and the admin-only check the backend enforces on these routes.apiClientinnetworking.tsxis now exported so hooks can use itOf note, I first wired the hook to the typed openapi-fetch
fetchClient, but its rebase middleware clones the outgoingRequest, which turns the JSON body into a streaming upload that Chrome only allows over HTTP/2; against the plain HTTP/1.1 dev proxy the POST dies withERR_ALPN_NEGOTIATION_FAILED. The plainapiClientsends a string body and works everywhereTests:
KeyInfoHeader.test.tsxcovers the dropdown (all three items render and fire their handlers, Block flips to Unblock based on blocked state, items hide when the caller lacks the corresponding permission callback, Blocked tag rendering) anduseSetKeyBlockedState.test.tscovers endpoint selection per direction, the request payload, cache invalidation, error surfacing, and the missing-token guardFinal Attestation