From 37350484540c1ec4a45c62a4c330830d8e42bd4d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 23 Apr 2026 21:24:58 +0000 Subject: [PATCH] feat(ui): organisms/RegenerateKeyModal to shadcn - antd Modal/Alert/Button/Col/Row/Flex/Input/Space/Typography + antd icons (Check/Copy/Sync) \u2192 shadcn Dialog/Button/Input + native grid + lucide icons. - Kept antd Form/Form.Item/InputNumber + AntInput for the two duration fields (Form binds validateFields/rules/extra). - Swept inline style objects (colors, padding, font) to Tailwind semantic tokens; preserved amber warning banner + emerald success text behind no-raw-tailwind-colors eslint-disables. Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang --- .../organisms/RegenerateKeyModal.tsx | 257 ++++++++++-------- 1 file changed, 142 insertions(+), 115 deletions(-) diff --git a/ui/litellm-dashboard/src/components/organisms/RegenerateKeyModal.tsx b/ui/litellm-dashboard/src/components/organisms/RegenerateKeyModal.tsx index 27f96eccab1..dcf3e8ebfd0 100644 --- a/ui/litellm-dashboard/src/components/organisms/RegenerateKeyModal.tsx +++ b/ui/litellm-dashboard/src/components/organisms/RegenerateKeyModal.tsx @@ -1,6 +1,15 @@ import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; -import { CheckOutlined, CopyOutlined, SyncOutlined } from "@ant-design/icons"; -import { Alert, Button, Col, Flex, Form, Input, InputNumber, Modal, Row, Space, Typography } from "antd"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Check, Copy, AlertTriangle, RefreshCw } from "lucide-react"; +import { Form, InputNumber, Input as AntInput } from "antd"; import { add } from "date-fns"; import { useEffect, useState } from "react"; import { CopyToClipboard } from "react-copy-to-clipboard"; @@ -8,8 +17,6 @@ import { KeyResponse } from "../key_team_helpers/key_list"; import NotificationManager from "../molecules/notifications_manager"; import { regenerateKeyCall } from "../networking"; -const { Text } = Typography; - interface RegenerateKeyModalProps { selectedToken: KeyResponse | null; visible: boolean; @@ -17,10 +24,16 @@ interface RegenerateKeyModalProps { onKeyUpdate?: (updatedKeyData: Partial) => void; } -export function RegenerateKeyModal({ selectedToken, visible, onClose, onKeyUpdate }: RegenerateKeyModalProps) { +export function RegenerateKeyModal({ + selectedToken, + visible, + onClose, + onKeyUpdate, +}: RegenerateKeyModalProps) { const { accessToken } = useAuthorized(); const [form] = Form.useForm(); const [regeneratedKey, setRegeneratedKey] = useState(null); + // eslint-disable-next-line @typescript-eslint/no-explicit-any const [regenerateFormData, setRegenerateFormData] = useState(null); const [newExpiryTime, setNewExpiryTime] = useState(null); const [isRegenerating, setIsRegenerating] = useState(false); @@ -39,7 +52,9 @@ export function RegenerateKeyModal({ selectedToken, visible, onClose, onKeyUpdat } }, [visible, selectedToken, form, accessToken]); - const calculateNewExpiryTime = (duration: string | undefined): string | null => { + const calculateNewExpiryTime = ( + duration: string | undefined, + ): string | null => { if (!duration) return null; try { @@ -67,7 +82,8 @@ export function RegenerateKeyModal({ selectedToken, visible, onClose, onKeyUpdat } return newExpiry.toLocaleString(); - } catch (error) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (_error) { return null; } }; @@ -95,10 +111,6 @@ export function RegenerateKeyModal({ selectedToken, visible, onClose, onKeyUpdat setRegeneratedKey(response.key); NotificationManager.success("Virtual Key regenerated successfully"); - // Build the update payload. Spread the API response first so any new - // fields it returns (new token, timestamps, etc.) are captured, then - // override with the explicit form values — the user's just-submitted - // edits must win over whatever the API echoes back. const updatedKeyData: Partial = { ...response, token: response.token || response.key_id || selectedToken.token, @@ -107,11 +119,11 @@ export function RegenerateKeyModal({ selectedToken, visible, onClose, onKeyUpdat tpm_limit: formValues.tpm_limit, rpm_limit: formValues.rpm_limit, expires: formValues.duration - ? (calculateNewExpiryTime(formValues.duration) ?? selectedToken.expires) + ? (calculateNewExpiryTime(formValues.duration) ?? + selectedToken.expires) : selectedToken.expires, }; - // Update the parent component with new key data if (onKeyUpdate) { onKeyUpdate(updatedKeyData); } @@ -120,7 +132,7 @@ export function RegenerateKeyModal({ selectedToken, visible, onClose, onKeyUpdat } catch (error) { console.error("Error regenerating key:", error); NotificationManager.fromBackend(error); - setIsRegenerating(false); // Reset regenerating state on error + setIsRegenerating(false); } }; @@ -137,143 +149,158 @@ export function RegenerateKeyModal({ selectedToken, visible, onClose, onKeyUpdat }; return ( - - - - - - , - ] - : [ - - - - , - ] - } - > - {regeneratedKey ? ( - - + (!o ? handleClose() : undefined)}> + e.preventDefault()} + > + + Regenerate Virtual Key + - - - Key Alias - - {selectedToken?.key_alias || "No alias set"} - - - - - Virtual Key - -
- {regeneratedKey} + {regeneratedKey ? ( +
+ {/* eslint-disable-next-line litellm-ui/no-raw-tailwind-colors */} +
+ + + Save it now, you will not see it again +
- - - ) : ( -
{ - if ("duration" in changedValues) { - setRegenerateFormData((prev: { duration?: string }) => ({ ...prev, duration: changedValues.duration })); - } - }} - > - - - - - +
+ Key Alias + {selectedToken?.key_alias || "No alias set"} +
+ +
+ + Virtual Key + +
+ {regeneratedKey} +
+
+
+ ) : ( + { + if ("duration" in changedValues) { + setRegenerateFormData( + (prev: { duration?: string }) => ({ + ...prev, + duration: changedValues.duration, + }), + ); + } + }} + > + + + + +
- + - - - - - - +
- - +
- +
+ Current expiry:{" "} - {selectedToken?.expires ? new Date(selectedToken.expires).toLocaleString() : "Never"} - + {selectedToken?.expires + ? new Date(selectedToken.expires).toLocaleString() + : "Never"} + {newExpiryTime && ( - + // eslint-disable-next-line litellm-ui/no-raw-tailwind-colors + New expiry: {newExpiryTime} - + )} - +
} > - +
- - + Recommended: 24h to 72h for production keys - + } rules={[ { pattern: /^(\d+(s|m|h|d|w|mo))?$/, - message: "Must be a duration like 30s, 30m, 24h, 2d, 1w, or 1mo", + message: + "Must be a duration like 30s, 30m, 24h, 2d, 1w, or 1mo", }, ]} > - + - - - - )} - +
+ + )} + + + {regeneratedKey ? ( + <> + + + + + + ) : ( + <> + + + + )} + + +
); }