From 5c7e5d432498d3798ebdacacef437ce95e250bef Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 19 Jul 2025 12:42:02 -0700 Subject: [PATCH] Revert "Regenerate Key State Management and Authentication Issues (#12729)" This reverts commit 663abbe27575205801659c264f57e4f90bdd2cbe. --- .../src/components/key_info_view.tsx | 300 +++++------------- .../src/components/regenerate_key_modal.tsx | 102 ++---- 2 files changed, 114 insertions(+), 288 deletions(-) diff --git a/ui/litellm-dashboard/src/components/key_info_view.tsx b/ui/litellm-dashboard/src/components/key_info_view.tsx index bb105b96ab..fa0e1818d1 100644 --- a/ui/litellm-dashboard/src/components/key_info_view.tsx +++ b/ui/litellm-dashboard/src/components/key_info_view.tsx @@ -13,37 +13,19 @@ import { Title, Badge, TextInput, - Select as TremorSelect, + Select as TremorSelect } from "@tremor/react"; -import { - ArrowLeftIcon, - TrashIcon, - RefreshIcon, -} from "@heroicons/react/outline"; +import { ArrowLeftIcon, TrashIcon, RefreshIcon } from "@heroicons/react/outline"; import { keyDeleteCall, keyUpdateCall } from "./networking"; import { KeyResponse } from "./key_team_helpers/key_list"; -import { - Form, - Input, - InputNumber, - message, - Select, - Tooltip, - Button as AntdButton, -} from "antd"; +import { Form, Input, InputNumber, message, Select, Tooltip, Button as AntdButton } from "antd"; import { KeyEditView } from "./key_edit_view"; import { RegenerateKeyModal } from "./regenerate_key_modal"; -import { rolesWithWriteAccess } from "../utils/roles"; +import { rolesWithWriteAccess } from '../utils/roles'; import ObjectPermissionsView from "./object_permissions_view"; import LoggingSettingsView from "./logging_settings_view"; -import { - copyToClipboard as utilCopyToClipboard, - formatNumberWithCommas, -} from "@/utils/dataUtils"; -import { - extractLoggingSettings, - formatMetadataForDisplay, -} from "./key_info_utils"; +import { copyToClipboard as utilCopyToClipboard, formatNumberWithCommas } from "@/utils/dataUtils"; +import { extractLoggingSettings, formatMetadataForDisplay } from "./key_info_utils"; import { CopyIcon, CheckIcon } from "lucide-react"; interface KeyInfoViewProps { @@ -57,38 +39,20 @@ interface KeyInfoViewProps { userRole: string | null; teams: any[] | null; premiumUser: boolean; - setAccessToken: (token: string) => void; } -export default function KeyInfoView({ - keyId, - onClose, - keyData, - accessToken, - userID, - userRole, - teams, - onKeyDataUpdate, - onDelete, - premiumUser, - setAccessToken, -}: KeyInfoViewProps) { +export default function KeyInfoView({ keyId, onClose, keyData, accessToken, userID, userRole, teams, onKeyDataUpdate, onDelete, premiumUser }: KeyInfoViewProps) { const [isEditing, setIsEditing] = useState(false); const [form] = Form.useForm(); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isRegenerateModalOpen, setIsRegenerateModalOpen] = useState(false); const [copiedStates, setCopiedStates] = useState>({}); - const [currentKeyData, setCurrentKeyData] = useState(keyData); - React.useEffect(() => { - setCurrentKeyData(keyData); - }, [keyData]); - - if (!currentKeyData) { + if (!keyData) { return (
- - {currentKeyData.key_alias || "API Key"} -
- - {currentKeyData.token} - + {keyData.key_alias || "API Key"} +
+ {keyData.token} - ) : ( - - ) - } - onClick={() => copyToClipboard(currentKeyData.token, "key-id")} + icon={copiedStates["key-id"] ? : } + onClick={() => copyToClipboard(keyData.token, "key-id")} className={`left-2 z-10 transition-all duration-200 ${ - copiedStates["key-id"] - ? "text-green-600 bg-green-50 border-green-200" - : "text-gray-500 hover:text-gray-700 hover:bg-gray-100" + copiedStates["key-id"] + ? 'text-green-600 bg-green-50 border-green-200' + : 'text-gray-500 hover:text-gray-700 hover:bg-gray-100' }`} />
{userRole && rolesWithWriteAccess.includes(userRole) && (
- + - )} + {!isEditing && userRole && rolesWithWriteAccess.includes(userRole) && ( + + )}
{isEditing ? ( setIsEditing(false)} onSubmit={handleKeyUpdate} teams={teams} @@ -453,57 +353,49 @@ export default function KeyInfoView({
Key ID - {currentKeyData.token} + {keyData.token}
- +
Key Alias - {currentKeyData.key_alias || "Not Set"} + {keyData.key_alias || "Not Set"}
Secret Key - {currentKeyData.key_name} + {keyData.key_name}
Team ID - {currentKeyData.team_id || "Not Set"} + {keyData.team_id || "Not Set"}
Organization - {currentKeyData.organization_id || "Not Set"} + {keyData.organization_id || "Not Set"}
Created - - {new Date(currentKeyData.created_at).toLocaleString()} - + {new Date(keyData.created_at).toLocaleString()}
Expires - - {currentKeyData.expires - ? new Date(currentKeyData.expires).toLocaleString() - : "Never"} - + {keyData.expires ? new Date(keyData.expires).toLocaleString() : "Never"}
Spend - - ${formatNumberWithCommas(currentKeyData.spend, 4)} USD - + ${formatNumberWithCommas(keyData.spend, 4)} USD
Budget - {currentKeyData.max_budget !== null - ? `$${formatNumberWithCommas(currentKeyData.max_budget, 2)}` + {keyData.max_budget !== null + ? `$${formatNumberWithCommas(keyData.max_budget, 2)}` : "Unlimited"}
@@ -511,9 +403,8 @@ export default function KeyInfoView({
Models
- {currentKeyData.models && - currentKeyData.models.length > 0 ? ( - currentKeyData.models.map((model, index) => ( + {keyData.models && keyData.models.length > 0 ? ( + keyData.models.map((model, index) => ( Rate Limits - - TPM:{" "} - {currentKeyData.tpm_limit !== null - ? currentKeyData.tpm_limit - : "Unlimited"} - - - RPM:{" "} - {currentKeyData.rpm_limit !== null - ? currentKeyData.rpm_limit - : "Unlimited"} - - - Max Parallel Requests:{" "} - {currentKeyData.max_parallel_requests !== null - ? currentKeyData.max_parallel_requests - : "Unlimited"} - - - Model TPM Limits:{" "} - {currentKeyData.metadata?.model_tpm_limit - ? JSON.stringify( - currentKeyData.metadata.model_tpm_limit, - ) - : "Unlimited"} - - - Model RPM Limits:{" "} - {currentKeyData.metadata?.model_rpm_limit - ? JSON.stringify( - currentKeyData.metadata.model_rpm_limit, - ) - : "Unlimited"} - + TPM: {keyData.tpm_limit !== null ? keyData.tpm_limit : "Unlimited"} + RPM: {keyData.rpm_limit !== null ? keyData.rpm_limit : "Unlimited"} + Max Parallel Requests: {keyData.max_parallel_requests !== null ? keyData.max_parallel_requests : "Unlimited"} + Model TPM Limits: {keyData.metadata?.model_tpm_limit ? JSON.stringify(keyData.metadata.model_tpm_limit) : "Unlimited"} + Model RPM Limits: {keyData.metadata?.model_rpm_limit ? JSON.stringify(keyData.metadata.model_rpm_limit) : "Unlimited"}
Metadata
-                      {formatMetadataForDisplay(currentKeyData.metadata)}
+                      {formatMetadataForDisplay(keyData.metadata)}
                     
@@ -594,4 +454,4 @@ export default function KeyInfoView({
); -} +} \ No newline at end of file diff --git a/ui/litellm-dashboard/src/components/regenerate_key_modal.tsx b/ui/litellm-dashboard/src/components/regenerate_key_modal.tsx index 3a67b278f1..84a406d2fc 100644 --- a/ui/litellm-dashboard/src/components/regenerate_key_modal.tsx +++ b/ui/litellm-dashboard/src/components/regenerate_key_modal.tsx @@ -11,9 +11,7 @@ interface RegenerateKeyModalProps { visible: boolean; onClose: () => void; accessToken: string | null; - setAccessToken: (token: string) => void; premiumUser: boolean; - onKeyUpdate?: (updatedKeyData: Partial) => void; } export function RegenerateKeyModal({ @@ -21,9 +19,7 @@ export function RegenerateKeyModal({ visible, onClose, accessToken, - setAccessToken, premiumUser, - onKeyUpdate, }: RegenerateKeyModalProps) { const [form] = Form.useForm(); const [regeneratedKey, setRegeneratedKey] = useState(null); @@ -86,59 +82,19 @@ export function RegenerateKeyModal({ const handleRegenerateKey = async () => { if (!selectedToken || !accessToken) return; - const isOwnKey = selectedToken.token === accessToken; - setIsRegenerating(true); try { const formValues = await form.validateFields(); const response = await regenerateKeyCall(accessToken, selectedToken.token, formValues); setRegeneratedKey(response.key); - - if (onKeyUpdate) { - const updatedKeyData = { - ...selectedToken, - token: response.key, - key_name: response.key, - max_budget: formValues.max_budget, - tpm_limit: formValues.tpm_limit, - rpm_limit: formValues.rpm_limit, - expires: formValues.duration - ? calculateNewExpiryTime(formValues.duration) || undefined - : selectedToken.expires, - }; - onKeyUpdate(updatedKeyData); - } - - // If user regenerated their own authentication key, update accessToken - if (isOwnKey) { - setAccessToken(response.key); - } - message.success("API Key regenerated successfully"); } catch (error) { console.error("Error regenerating key:", error); message.error("Failed to regenerate API Key"); - setIsRegenerating(false); + setIsRegenerating(false); // Reset regenerating state on error } }; - const calculateNewExpiryTime = (duration: string) => { - const now = new Date(); - let newExpiry: Date; - - if (duration.endsWith("s")) { - newExpiry = add(now, { seconds: parseInt(duration) }); - } else if (duration.endsWith("h")) { - newExpiry = add(now, { hours: parseInt(duration) }); - } else if (duration.endsWith("d")) { - newExpiry = add(now, { days: parseInt(duration) }); - } else { - return null; - } - - return newExpiry.toISOString(); - }; - const handleClose = () => { setRegeneratedKey(null); setIsRegenerating(false); @@ -151,43 +107,49 @@ export function RegenerateKeyModal({ title="Regenerate API Key" open={visible} onCancel={handleClose} - footer={ - regeneratedKey - ? [ - , - ] - : [ - , - , - ] - } + footer={regeneratedKey ? [ + , + ] : [ + , + , + ]} > {regeneratedKey ? ( Regenerated Key

- Please replace your old key with the new key generated. For security reasons,{" "} - you will not be able to view it again through your LiteLLM account. If you lose this secret key, - you will need to generate a new one. + Please replace your old key with the new key generated. For + security reasons, you will not be able to view it again{" "} + through your LiteLLM account. If you lose this secret key, you + will need to generate a new one.

Key Alias:
-
{selectedToken?.key_alias || "No alias set"}
+
+                {selectedToken?.key_alias || "No alias set"}
+              
New API Key:
{regeneratedKey}
- message.success("API Key copied to clipboard")}> + message.success("API Key copied to clipboard")} + > @@ -220,9 +182,13 @@ export function RegenerateKeyModal({
Current expiry: {selectedToken?.expires ? new Date(selectedToken.expires).toLocaleString() : "Never"}
- {newExpiryTime &&
New expiry: {newExpiryTime}
} + {newExpiryTime && ( +
+ New expiry: {newExpiryTime} +
+ )} )} ); -} +} \ No newline at end of file