fix(ui): wire team_id filter to key alias dropdown on Virtual Keys tab - #25114
Conversation
The Key Alias dropdown on the Virtual Keys page was showing aliases from all teams regardless of which team was selected. The team_id was never passed through the frontend chain to the backend /key/aliases endpoint. - Backend: add optional team_id query param to /key/aliases endpoint - networking.tsx: add team_id param to keyAliasesCall - useKeyAliases: accept and forward team_id to API call and query key - filter.tsx: pass allFilters context to custom filter components - PaginatedKeyAliasSelect: read Team ID from allFilters and pass to hook
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR wires Key changes:
Notable findings:
Confidence Score: 5/5Safe to merge; all findings are non-blocking style and UX suggestions with no correctness, security, or data-integrity impact. The core change — parameterizing /key/aliases with team_id and threading it through the frontend — is logically correct, properly parameterized (no SQL injection risk), and cache-keyed correctly so stale data is never served. All remaining findings are P2: a stale-selection UX edge case, a fragile string-key coupling, a leftover console.log, and a style-guide note on an inline import. None affect correctness or data integrity. filter.tsx (stale sibling-filter clearing) and PaginatedKeyAliasSelect.tsx (hardcoded filter key lookup)
|
| Filename | Overview |
|---|---|
| litellm/proxy/management_endpoints/key_management_endpoints.py | Adds optional team_id query parameter to the /key/aliases endpoint; correctly appended to the parameterized raw-SQL WHERE clause consistent with the existing search param pattern. |
| ui/litellm-dashboard/src/components/networking.tsx | Adds optional team_id param to keyAliasesCall; correctly conditionally appended to URLSearchParams. A pre-existing console.log of the full response remains in the production path. |
| ui/litellm-dashboard/src/app/(dashboard)/hooks/keys/useKeyAliases.ts | Threads team_id through the React Query hook; correctly included in the queryKey so cache is keyed per team, ensuring stale data from the previous team is not served. |
| ui/litellm-dashboard/src/components/KeyAliasSelect/PaginatedKeyAliasSelect/PaginatedKeyAliasSelect.tsx | Reads team_id from the allFilters bag via the hardcoded key "Team ID", an implicit contract on filter option naming; does not reset its selection when the team filter changes. |
| ui/litellm-dashboard/src/components/molecules/filter.tsx | Passes tempValues as allFilters to custom filter components — a clean mechanism for sibling-filter awareness — but does not clear dependent sibling values when a parent filter changes, leading to stale selections. |
Sequence Diagram
sequenceDiagram
participant User
participant FilterComponent
participant PaginatedKeyAliasSelect
participant useInfiniteKeyAliases
participant keyAliasesCall
participant Backend as /key/aliases
User->>FilterComponent: Select Team ID
FilterComponent->>FilterComponent: update tempValues["Team ID"]
FilterComponent->>PaginatedKeyAliasSelect: re-render with allFilters
PaginatedKeyAliasSelect->>useInfiniteKeyAliases: call with team_id
useInfiniteKeyAliases->>keyAliasesCall: fetch page 1 + team_id
keyAliasesCall->>Backend: GET /key/aliases?page=1&team_id=...
Backend-->>keyAliasesCall: filtered aliases for team
keyAliasesCall-->>PaginatedKeyAliasSelect: dropdown shows team aliases only
User->>FilterComponent: Clear Team ID
FilterComponent->>PaginatedKeyAliasSelect: re-render with allFilters (Team ID empty)
PaginatedKeyAliasSelect->>useInfiniteKeyAliases: call with team_id=undefined
useInfiniteKeyAliases->>keyAliasesCall: fetch page 1, no team_id
keyAliasesCall->>Backend: GET /key/aliases?page=1
Backend-->>keyAliasesCall: all aliases
keyAliasesCall-->>PaginatedKeyAliasSelect: dropdown shows all aliases
Comments Outside Diff (3)
-
litellm/proxy/management_endpoints/key_management_endpoints.py, line 4367-4369 (link)Inline import inside function body
from litellm.proxy.proxy_server import prisma_clientis placed inside the function body rather than at module level.CLAUDE.mdstyle guidance says to avoid imports within methods — they make dependencies harder to trace and hurt readability — with an exception only for unavoidable circular imports.If the circular-import exception applies here (which it may, given
proxy_server.pyimports this module), that should be documented with a comment explaining why the inline import is necessary, rather than left implicit.Context Used: CLAUDE.md (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
-
ui/litellm-dashboard/src/components/networking.tsx, line 3299 (link)Debug
console.logleft in production pathconsole.log("/key/aliases API Response:", data)will emit every API response to the browser console in production, potentially leaking key alias metadata to anyone with devtools open. This should be removed or downgraded to a conditional debug-level statement. -
ui/litellm-dashboard/src/components/molecules/filter.tsx, line 107-113 (link)Stale sibling-filter value not cleared when a parent filter changes
When a user selects a team, picks an alias from that team's aliases, then switches to a different team,
tempValues["Team ID"]updates buttempValues["Key Alias"]retains the previously selected alias.onApplyFiltersis immediately called with both values, so downstream consumers apply the new team filter combined with the stale alias from the old team, returning 0 results with no indication to the user.Consider clearing dependent sibling filters when a parent filter changes — for example, resetting
"Key Alias"whenever"Team ID"changes. To keep the logic reusable, this dependency could be expressed as an optionalclearSiblingsfield onFilterOptionrather than hardcoded insidehandleFilterChange.
Reviews (1): Last reviewed commit: "fix(ui): wire team_id filter to key alia..." | Re-trigger Greptile
| wait: DEBOUNCE_MS, | ||
| }); | ||
|
|
||
| const teamId = allFilters?.["Team ID"] || undefined; |
There was a problem hiding this comment.
Hardcoded filter key couples component to naming convention
allFilters?.["Team ID"] creates an implicit contract that any enclosing FilterComponent must have a filter option whose name is exactly "Team ID". This happens to hold for both VirtualKeysTable.tsx and view_logs/index.tsx today, but the component itself has no way to enforce or document this assumption. If any page renames the team filter or reuses PaginatedKeyAliasSelect outside of FilterComponent, the extracted teamId will silently resolve to undefined and team-scoping will be dropped without any error or warning.
A more explicit and type-safe approach is to expose teamId as a first-class optional prop alongside allFilters, falling back to allFilters only when the explicit prop is absent.
1521004
into
litellm_ryan-march-31
…s-team-filter-alias-dropdown fix(ui): wire team_id filter to key alias dropdown on Virtual Keys tab
Summary
team_idwas never passed through the frontend to the/key/aliasesbackend endpointteam_idas an optional query parameter to the backend/key/aliasesendpointteam_idthrough the full frontend chain:keyAliasesCall→useInfiniteKeyAliases→PaginatedKeyAliasSelectFilterComponentframework to pass current filter state (allFilters) to custom filter components so they can react to sibling filter valuesScreenshots
Test plan
/key/aliases?team_id=<id>returns only that team's aliases via curl