diff --git a/ui/litellm-dashboard/.eslintrc.json b/ui/litellm-dashboard/.eslintrc.json index 9d066e44922..ae9a0137548 100644 --- a/ui/litellm-dashboard/.eslintrc.json +++ b/ui/litellm-dashboard/.eslintrc.json @@ -62,6 +62,7 @@ "src/components/Settings/RouterSettings/Fallbacks/FallbackGroupConfig.tsx", "src/components/prompts/variable_textarea.tsx", "src/components/chat/MCPCredentialsTab.tsx", + "src/components/common_components/KeyLifecycleSettings.tsx", "src/components/prompts/prompt_editor_view/PromptEditorHeader.tsx", "src/components/prompts/prompt_editor_view/VersionHistorySidePanel.tsx", "src/app/(dashboard)/teams/components/TeamsTable/ModelsCell.tsx", diff --git a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.tsx b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.tsx index 17d65e1f66a..797b95309ed 100644 --- a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.tsx +++ b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.tsx @@ -1,21 +1,48 @@ import React, { useState } from "react"; -import { Select, Tooltip, Divider, Switch, Checkbox } from "antd"; -import { InfoCircleOutlined } from "@ant-design/icons"; -import { TextInput } from "@tremor/react"; - -const { Option } = Select; +import { Checkbox } from "@/components/ui/checkbox"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Switch } from "@/components/ui/switch"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { Info } from "lucide-react"; interface KeyLifecycleSettingsProps { - form: any; // Form instance from parent + // Form instance from parent (antd Form) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + form: any; autoRotationEnabled: boolean; onAutoRotationChange: (enabled: boolean) => void; rotationInterval: string; onRotationIntervalChange: (interval: string) => void; - isCreateMode?: boolean; // If true, shows "leave empty to never expire" instead of "-1 to never expire" + isCreateMode?: boolean; neverExpire?: boolean; onNeverExpireChange?: (checked: boolean) => void; } +const InfoTooltip: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => ( + + + + + + {children} + + +); + const KeyLifecycleSettings: React.FC = ({ form, autoRotationEnabled, @@ -26,20 +53,22 @@ const KeyLifecycleSettings: React.FC = ({ neverExpire = false, onNeverExpireChange, }) => { - // Predefined intervals const predefinedIntervals = ["7d", "30d", "90d", "180d", "365d"]; - // Check if current interval is custom - const isCustomInterval = rotationInterval && !predefinedIntervals.includes(rotationInterval); + const isCustomInterval = + rotationInterval && !predefinedIntervals.includes(rotationInterval); const [showCustomInput, setShowCustomInput] = useState(isCustomInterval); - const [customInterval, setCustomInterval] = useState(isCustomInterval ? rotationInterval : ""); - const [durationValue, setDurationValue] = useState(form?.getFieldValue?.("duration") || ""); + const [customInterval, setCustomInterval] = useState( + isCustomInterval ? rotationInterval : "", + ); + const [durationValue, setDurationValue] = useState( + form?.getFieldValue?.("duration") || "", + ); const handleIntervalChange = (value: string) => { if (value === "custom") { setShowCustomInput(true); - // Don't change the actual interval yet, wait for custom input } else { setShowCustomInput(false); setCustomInterval(""); @@ -47,7 +76,9 @@ const KeyLifecycleSettings: React.FC = ({ } }; - const handleCustomIntervalChange = (e: React.ChangeEvent) => { + const handleCustomIntervalChange = ( + e: React.ChangeEvent, + ) => { const value = e.target.value; setCustomInterval(value); onRotationIntervalChange(value); @@ -61,106 +92,120 @@ const KeyLifecycleSettings: React.FC = ({ form.setFieldsValue({ duration: value }); } }; + return ( - {/* Key Expiry Section */} - Key Expiry Settings + + Key Expiry Settings + - + Expire Key - - - + + Set when this key should expire. Format: 30s (seconds), 30m + (minutes), 30h (hours), 30d (days). Leave empty to keep the + current expiry unchanged. + {!isCreateMode && onNeverExpireChange && ( - { - const checked = e.target.checked; - onNeverExpireChange(checked); - if (checked) { - setDurationValue(""); - if (form && typeof form.setFieldValue === "function") { - form.setFieldValue("duration", ""); - } else if (form && typeof form.setFieldsValue === "function") { - form.setFieldsValue({ duration: "" }); + + { + const checked = c === true; + onNeverExpireChange(checked); + if (checked) { + setDurationValue(""); + if (form && typeof form.setFieldValue === "function") { + form.setFieldValue("duration", ""); + } else if ( + form && + typeof form.setFieldsValue === "function" + ) { + form.setFieldsValue({ duration: "" }); + } } - } - }} - className="ml-2 text-sm font-normal text-gray-600" - > + }} + /> Never Expire - + )} - - + handleDurationChange(e.target.value)} disabled={!isCreateMode && neverExpire} /> - + - {/* Auto-Rotation Section */} - Auto-Rotation Settings + + Auto-Rotation Settings + - + Enable Auto-Rotation - - - + + Key will automatically regenerate at the specified interval + for enhanced security. + {autoRotationEnabled && ( - + Rotation Interval - - - + + How often the key should be automatically rotated. Choose + the interval that best fits your security requirements. + - 7 days - 30 days - 90 days - 180 days - 365 days - Custom interval + + + + + 7 days + 30 days + 90 days + 180 days + 365 days + Custom interval + {showCustomInput && ( - - - Supported formats: seconds (s), minutes (m), hours (h), days (d) + + Supported formats: seconds (s), minutes (m), hours (h), + days (d) )} @@ -170,9 +215,10 @@ const KeyLifecycleSettings: React.FC = ({ {autoRotationEnabled && ( - - When rotation occurs, you'll receive a notification with the new key. The old key will be deactivated - after a brief grace period. + + When rotation occurs, you'll receive a notification with the + new key. The old key will be deactivated after a brief grace + period. )}