fix: isolate logs team filter dropdown from root teams state bleed#25716
fix: isolate logs team filter dropdown from root teams state bleed#25716ryan-crabbe-berri merged 1 commit intomainfrom
Conversation
The Logs view's Team ID filter dropdown was reading `allTeams` from the root `teams` state in page.tsx, which the Teams page search overwrites with its filtered subset. Applying a team search on the Teams page made filtered-out teams disappear from the Logs filter dropdown. Swap the Team ID filter to use the existing `TeamDropdown` component via a small `FilterTeamDropdown` wrapper that adapts it to the filter slot's `FilterOptionCustomComponentProps` contract. The dropdown now drives its own `useInfiniteTeams` query against `/v2/team/list` with server-side search and an isolated react-query cache, unreachable from root state. Rename the now-unused `hookAllTeams` destructure to `allTeams` so the `KeyInfoView` passthrough receives the hook's unpolluted fetch instead of the polluted prop, and drop the dead `allTeams` prop from `SpendLogsTable` and both of its call sites.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR fixes a state bleed bug where searching on the Teams page would overwrite the shared Confidence Score: 5/5Safe to merge — the fix is well-scoped, all 38 tests pass, and the only remaining note is a P2 UX inconsistency about the ignored placeholder. All findings are P2 (style/UX). The core state-isolation fix is correct, test coverage is maintained, and no regressions are introduced. No files require special attention.
|
| Filename | Overview |
|---|---|
| ui/litellm-dashboard/src/components/common_components/FilterTeamDropdown.tsx | New 10-line wrapper bridging TeamDropdown to FilterOptionCustomComponentProps; placeholder prop is ignored (intentional, minor UX inconsistency) |
| ui/litellm-dashboard/src/components/view_logs/index.tsx | Removes allTeams prop, replaces inline client-side search with FilterTeamDropdown customComponent, and renames hookAllTeams→allTeams for KeyInfoView passthrough |
| ui/litellm-dashboard/src/app/page.tsx | Removes allTeams prop from SpendLogsTable call site; no other changes |
| ui/litellm-dashboard/src/app/(dashboard)/logs/page.tsx | Drops useTeams hook and allTeams prop entirely from the Logs page; clean removal |
| ui/litellm-dashboard/src/components/view_logs/index.test.tsx | Removes Team import and allTeams from defaultProps to match removed prop; mock for useLogFilterLogic still correctly includes allTeams |
Sequence Diagram
sequenceDiagram
participant TeamsPage as Teams Page (OldTeams)
participant RootState as Root teams state (app/page.tsx)
participant LogsFilter as Logs Team ID Filter
participant FilterTeamDD as FilterTeamDropdown
participant TeamDD as TeamDropdown
participant InfiniteTeams as useInfiniteTeams (/v2/team/list)
Note over TeamsPage,LogsFilter: BEFORE (buggy)
TeamsPage->>RootState: search "bleed-acme" → overwrites teams[]
LogsFilter->>RootState: read allTeams prop → sees only filtered subset ❌
Note over FilterTeamDD,InfiniteTeams: AFTER (fixed)
TeamsPage->>RootState: search "bleed-acme" → overwrites teams[]
LogsFilter->>FilterTeamDD: render customComponent with value/onChange
FilterTeamDD->>TeamDD: delegate value & onChange
TeamDD->>InfiniteTeams: own isolated react-query cache
InfiniteTeams-->>TeamDD: full unfiltered teams list ✅
TeamDD-->>LogsFilter: shows all teams regardless of root state
Reviews (1): Last reviewed commit: "fix: isolate logs team filter dropdown f..." | Re-trigger Greptile
| const FilterTeamDropdown: React.FC<FilterOptionCustomComponentProps> = ({ | ||
| value, | ||
| onChange, | ||
| }) => <TeamDropdown value={value} onChange={onChange} />; |
There was a problem hiding this comment.
Placeholder prop silently dropped
FilterOptionCustomComponentProps includes an optional placeholder prop, and filter.tsx always passes "Select Team ID..." to every customComponent. FilterTeamDropdown receives it but never forwards it, so users will always see TeamDropdown's hardcoded "Search or select a team" instead. This is a minor UX inconsistency vs every other filter slot. If intentional, a comment noting the deviation is worth adding; if not, TeamDropdown can accept an optional placeholder prop.
| const FilterTeamDropdown: React.FC<FilterOptionCustomComponentProps> = ({ | |
| value, | |
| onChange, | |
| }) => <TeamDropdown value={value} onChange={onChange} />; | |
| const FilterTeamDropdown: React.FC<FilterOptionCustomComponentProps> = ({ | |
| value, | |
| onChange, | |
| // placeholder is intentionally ignored — TeamDropdown has its own label | |
| }) => <TeamDropdown value={value} onChange={onChange} />; |
Summary
allTeamsfrom the rootteamsstate inapp/page.tsx, whichOldTeamsoverwrites with the filtered subset whenever a user searches on the Teams page. Applying a team search on the Teams page made filtered-out teams disappear from the Logs filter dropdown in a separate part of the app.TeamDropdowncomponent via a smallFilterTeamDropdownwrapper that adapts it to the filter slot'sFilterOptionCustomComponentPropscontract. The dropdown now drives its ownuseInfiniteTeamsquery against/v2/team/listwith server-sideteam_aliassearch and an isolated react-query cache, unreachable from root state.hookAllTeamsdestructure inSpendLogsTabletoallTeamsso theKeyInfoViewpassthrough receives the hook's unpolluted fetch instead of the polluted prop, and drop the deadallTeamsprop fromSpendLogsTableand both of its call sites (app/page.tsx,app/(dashboard)/logs/page.tsx).screenshots
before


after


Test plan
bleed-*teams via/team/new, fire one request through the proxy to produce a log entrybleed→ all 5 teams appearbleed-acme→ table narrows to one row (rootteamsstate now polluted)bleed→ all 5 teams still appear (dropdown reads from its ownuseInfiniteTeamscache, not root state)KeyInfoViewpanel opens and renders correctly (now receives the hook's unpollutedallTeams)npx vitest run src/components/view_logs/index.test.tsx src/components/view_logs/log_filter_logic.test.tsx→ 38/38 passingtsc --noEmit→ zero new errors on touched files