Add search_tools permission support across the UI (key create/edit, team create,
object permissions view) with breaking-change alerts for the new least-privilege
default. Modernize the Search Tools page with AntD Tabs, a Test playground tab,
and ProviderLogo integration. Migrate TeamDropdown to self-fetching infinite
scroll pattern using useInfiniteTeams hook. Scope search tools visibility for
internal users based on their team memberships.
Backend: Add search_tools field to Prisma schema (all copies), Pydantic models
(ObjectPermissionBase + ObjectPermissionTable), and allowed routes for virtual
keys. Add permission filtering to /search_tools/list endpoint. Include
object_permission in team list v2 queries.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Internal users can now see the create modal (with a team selection
prompt). Updated the test from asserting the modal is hidden to
asserting the team selection prompt is shown.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove assertions for alias text (column was removed)
- Disambiguate "Team" filter label from "Team (Owner)" column header
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The dashboard layout was using Sidebar2, which routed all entries to
path-based URLs like /ui/keys — but only api-reference has been migrated.
Switch back to the old leftnav so unmigrated pages navigate to the legacy
root page (?page=X) and migrated pages use path routing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add TeamDropdown as first field in create MCP server form
- For internal users, hide form fields until team is selected
- Fix useMCPServerHealth to append new servers to cache on recheck
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removed low-value columns (Alias, Auth Type, Updated) to reduce
horizontal overflow. Added explicit size hints to remaining columns.
DataTable now applies column sizes to header and body cells.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The early return on missing auth params blocked the entire page from
rendering. The hooks already guard on accessToken being available, and
DataTable shows its own loading state via isLoading prop.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows the owning team alias resolved from team_id. Global servers
(team_id=null) display "Global". Header includes info icon explaining
that only servers from teams with mcp:read permission are visible.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The list endpoint returns an empty list (not 403) when a user has no
MCP servers available. For internal users, show a message suggesting
they may need mcp:read permission or team MCP server assignments.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace "Missing required authentication parameters" with a loading
state. When the MCP servers fetch fails (e.g. 403), show a clear
error message with steps on how to get mcp:read permission.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix double error handling in getTeamPermissionsCall: return empty data
on HTTP error instead of calling handleError + throwing, preventing
duplicate error notifications
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix double error handling in getTeamPermissionsCall: return empty data
on HTTP error instead of calling handleError + throwing, preventing
duplicate error notifications
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix unknown permissions duplication: seed selected state with only known
permissions so existingUnknown and selected are disjoint on save
- Disable Add MCP Server button for non-admins without a team selected,
show tooltip explaining they need to select a team first
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Separate save failure from refresh failure: close drawer after successful
save even if teamInfoCall refresh fails
- Preserve unknown permissions not in availablePermissions when saving,
preventing silent drops of permissions from newer backend versions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Type onUpdate as () => Promise<void> and await it before closing drawer
- Replace accessToken! assertion with explicit null guard
- Gate fetchAvailableTeamMemberPermissions behind canEditTeam check
- Pass team_id for admins too when a team is selected in the filter
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add UI support for the MCP team management permissions introduced in PR #24266.
- Add MemberPermissionsDrawer component (Ant Design Drawer) for managing
per-member MCP permissions (mcp:read, mcp:create, mcp:update, mcp:delete)
- Add permissions button to team member table actions column
- Fetch available permissions from GET /team/available_permissions
- Pass extra_permissions in team member update API calls
- Allow all users to create MCP servers directly (backend enforces permissions)
- Pass team_id when non-admin users create MCP servers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move callbacks outside try/catch so only mutation errors are caught,
not errors from onVersionCreated/onVersionStatusUpdated callbacks
- Replace policyName! non-null assertion with DISABLED_POLICY_KEY
sentinel to avoid undefined in cache keys when query is disabled
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add PolicyVersionsData type for select output; specify TData generic
so consumers get Policy[] (not Policy[] | undefined) for versions
- Remove empty-string queryKey fallback — use policyName! since
enabled:false prevents fetch when policyName is null
- Add cache invalidation tests for both mutation hooks
- Add explanatory comment for ?? [] fallback in component
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Make PolicyVersionsResponse.versions optional (Policy[] | undefined)
to match real API shape — select fallback handles normalization
- Add policyName guard to useUpdatePolicyVersionStatus mutationFn
to fail loudly instead of silently skipping cache invalidation
- Add test for null policyName in updateStatus mutation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Wrap mutateAsync calls in try/catch to swallow re-thrown errors
(notifications already handled by onError in mutation hooks)
- Use isLoading instead of isPending for version loading state —
isPending is true when query is disabled with no cache, isLoading
is only true during active fetches (matches original behavior)
- Add isLoading assertions to disabled-state tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace useEffect + useState fetch pattern for policy version management
with React Query hooks (useQuery + useMutation), following established
codebase conventions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add tests for ResponseTimeIndicator, KeyValueInput, QueryParamInput,
RoutePreview, OnboardingModal, EditUserModal, ModelFilters,
AuditLogDrawer, PassThroughInfoView, and EmailSettings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AntD v5 static message API doesn't render without an App wrapper or
useMessage() context holder. Mirrors the existing notification pattern
by adding message.useMessage() to AntdGlobalProvider and routing all
calls through a new MessageManager module.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a control plane capability that enables a central admin instance
to manage multiple regional worker proxies from a single UI.
Backend:
- Worker registry loaded from YAML config (worker_id, name, url)
- /.well-known/litellm-ui-config exposes is_control_plane and workers list
- /v3/login + /v3/login/exchange: opaque code exchange for cross-origin
username/password auth (JWT never in URL/logs, single-use 60s TTL)
- SSO cookie handoff with return_to → opaque code → exchange
- _validate_return_to: full origin validation (scheme+hostname+port)
- Startup warning when control_plane_url set without Redis
- Both /v3 endpoints gated behind control_plane_url config
Frontend:
- Worker selector dropdown on login page (gated behind is_control_plane)
- Cross-origin SSO code exchange handling on callback
- switchToWorkerUrl: localStorage-persisted worker URL for API calls
- useWorker hook: shared worker state management
- WorkerDropdown in navbar for switching workers
- Logout/switch clears worker state from localStorage
Tests:
- 7 tests for /v3/login + /v3/login/exchange
- 10 tests for _validate_return_to
- 2 tests for control plane discovery endpoint
Migrate the OldTeams table from Tremor to Ant Design components, matching the
Access Groups page pattern. Switch from /team/list to /v2/team/list for
server-side pagination, filtering, and sorting.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- clearChatHistory: use functional setChatHistory updater so blob URL
revocation operates on the latest snapshot, not a stale closure capture.
- Simplified mode: skip sessionStorage hydration and persistence for
messageTraceId, responsesSessionId, and useApiSessionManagement so
embedded widgets don't cross-contaminate the full playground session.
- Debounce race: skip re-writing empty chatHistory to sessionStorage
after clearChatHistory already removed the key.
- Added 5 new tests covering these fixes (39 total).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Removes 17 console.log statements that fired on every streaming chunk
in updateTextUI, updateTimingData, updateUsageData, and other hot-path
functions. The console.error for sessionStorage parse failures is kept.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The redirect useEffect fires before getUiConfig() completes, so
proxyBaseUrl is always "" on first render. Gate on !authLoading so
the redirect only fires after config is fetched, matching the pattern
used by the login redirect.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
router.replace was called directly during render, which is unsafe in
React 18 concurrent mode. Move it into a useEffect and use a computed
flag (isLegacyRedirect) to show LoadingScreen while redirecting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The leftnav was updated to emit page="api-reference" but only "api_ref"
was in LEGACY_REDIRECTS, causing clicks to fall through to the default
Usage page. Add "api-reference" entry to the redirect map. Also include
LITELLM_UI_API_DOC_BASE_URL in the hook's initial state to avoid a
brief flash of incorrect base URL.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move the API Reference page from query-param routing (?page=api_ref) to
Next.js path-based routing (/ui/api-reference). Add a LEGACY_REDIRECTS
map in the root page.tsx so users with old bookmarks are seamlessly
redirected. Future page migrations only need one new map entry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ExportOutlined icon next to nav items that link to external pages,
making it clear to users when a link opens in a new tab.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ChatUI stores endpointType as string but the narrowed prop expects
EndpointType — add explicit cast at the call site.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Matches the cast used in ChatUI.tsx — the react-syntax-highlighter
type definitions don't accept CSSProperties directly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Narrow endpointType prop from string to EndpointType enum
- Add missing test for MCP events on CHAT endpoint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract the chat message bubble rendering (~165 lines) into a dedicated
ChatMessageBubble component with 15 Vitest tests covering all display branches.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>