From 24fc9929c9d74e6f11c2a55ebb2c83e7f40bd344 Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Sat, 2 May 2026 20:23:40 -0700 Subject: [PATCH] feat(ui): allow setting router fallbacks on key edit The key edit view exposed every other key-level setting but omitted router_settings, so users couldn't change fallbacks / retries / etc. on an existing key from the UI even though /key/update accepted them. Reuses the same RouterSettingsAccordion the create flow uses, wrapped in a collapsed antd Collapse so the form stays compact by default. --- .../components/key_team_helpers/key_list.tsx | 1 + .../components/templates/key_edit_view.tsx | 40 ++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/ui/litellm-dashboard/src/components/key_team_helpers/key_list.tsx b/ui/litellm-dashboard/src/components/key_team_helpers/key_list.tsx index f410a049762..4447bf2e6b3 100644 --- a/ui/litellm-dashboard/src/components/key_team_helpers/key_list.tsx +++ b/ui/litellm-dashboard/src/components/key_team_helpers/key_list.tsx @@ -98,6 +98,7 @@ export interface KeyResponse { budget_limits?: Array<{ budget_duration: string; max_budget: number; reset_at?: string }>; auto_rotate?: boolean; rotation_interval?: string; + router_settings?: Record | null; last_rotation_at?: string; key_rotation_at?: string; next_rotation_at?: string; diff --git a/ui/litellm-dashboard/src/components/templates/key_edit_view.tsx b/ui/litellm-dashboard/src/components/templates/key_edit_view.tsx index 9b38d930a50..a9a3e566c86 100644 --- a/ui/litellm-dashboard/src/components/templates/key_edit_view.tsx +++ b/ui/litellm-dashboard/src/components/templates/key_edit_view.tsx @@ -5,11 +5,14 @@ import { useUISettings } from "@/app/(dashboard)/hooks/uiSettings/useUISettings" import PolicySelector from "@/components/policies/PolicySelector"; import { InfoCircleOutlined } from "@ant-design/icons"; import { TextInput, Button as TremorButton } from "@tremor/react"; -import { Form, Input, Select, Switch, Tooltip } from "antd"; +import { Collapse, Form, Input, Select, Switch, Tooltip } from "antd"; import { useEffect, useState } from "react"; import { rolesWithWriteAccess } from "../../utils/roles"; import AgentSelector from "../agent_management/AgentSelector"; import AccessGroupSelector from "../common_components/AccessGroupSelector"; +import RouterSettingsAccordion, { + RouterSettingsAccordionValue, +} from "../common_components/RouterSettingsAccordion"; import { mapInternalToDisplayNames } from "../callback_info_helpers"; import KeyLifecycleSettings from "../common_components/KeyLifecycleSettings"; import PassThroughRoutesSelector from "../common_components/PassThroughRoutesSelector"; @@ -108,6 +111,14 @@ export function KeyEditView({ const [budgetLimits, setBudgetLimits] = useState( Array.isArray(keyData.budget_limits) ? keyData.budget_limits : [] ); + // Router settings (fallbacks, retries, etc.) — local edit state only. + // Initialized once from keyData; the editor remounts on each open + // (key_info_view conditionally renders KeyEditView), so no sync effect is needed. + const [routerSettings, setRouterSettings] = useState( + keyData.router_settings && Object.keys(keyData.router_settings).length > 0 + ? { router_settings: keyData.router_settings as RouterSettingsAccordionValue["router_settings"] } + : null, + ); const { data: organizations, isLoading: isOrganizationsLoading } = useOrganizations(); const { data: projects } = useProjects(); const { data: uiSettingsData } = useUISettings(); @@ -283,6 +294,14 @@ export function KeyEditView({ const validWindows = budgetLimits.filter((w) => w.budget_duration && w.max_budget !== null && w.max_budget !== undefined); values.budget_limits = validWindows.length > 0 ? validWindows : undefined; + // Include router_settings (fallbacks, retries, etc.) when set; send {} to clear. + if (routerSettings?.router_settings) { + const hasValues = Object.values(routerSettings.router_settings).some( + (v) => v !== null && v !== undefined && v !== "", + ); + values.router_settings = hasValues ? routerSettings.router_settings : {}; + } + await onSubmit(values); } finally { setIsKeySaving(false); @@ -724,6 +743,25 @@ export function KeyEditView({ + {accessToken && ( + Router Settings, + children: ( + + ), + }, + ]} + /> + )} + {/* Auto-Rotation Settings */}