diff --git a/ui/litellm-dashboard/src/components/add_model/model_connection_test.tsx b/ui/litellm-dashboard/src/components/add_model/model_connection_test.tsx index b4836777119..14cdba0fed6 100644 --- a/ui/litellm-dashboard/src/components/add_model/model_connection_test.tsx +++ b/ui/litellm-dashboard/src/components/add_model/model_connection_test.tsx @@ -1,12 +1,18 @@ import React from "react"; -import { Typography, Button, Divider } from "antd"; -import { WarningOutlined, InfoCircleOutlined, CopyOutlined } from "@ant-design/icons"; +import { Button } from "@/components/ui/button"; +import { + AlertTriangle, + CheckCircle2, + Copy, + Info, + Loader2, +} from "lucide-react"; import { testConnectionRequest } from "../networking"; import { prepareModelAddRequest } from "./handle_add_model_submit"; import NotificationsManager from "../molecules/notifications_manager"; -const { Text } = Typography; interface ModelConnectionTestProps { + // eslint-disable-next-line @typescript-eslint/no-explicit-any formValues: Record; accessToken: string; testMode: string; @@ -18,84 +24,84 @@ interface ModelConnectionTestProps { const ModelConnectionTest: React.FC = ({ formValues, accessToken, - testMode, modelName = "this model", - onClose, onTestComplete, }) => { const [error, setError] = React.useState(null); - const [rawRequest, setRawRequest] = React.useState(null); + // eslint-disable-next-line @typescript-eslint/no-explicit-any const [rawResponse, setRawResponse] = React.useState(null); const [isLoading, setIsLoading] = React.useState(true); const [isSuccess, setIsSuccess] = React.useState(false); const [showDetails, setShowDetails] = React.useState(false); - const testModelConnection = async () => { - setIsLoading(true); - setShowDetails(false); - setError(null); - setRawRequest(null); - setRawResponse(null); - setIsSuccess(false); - - // Add a small delay to ensure form values are fully populated - await new Promise((resolve) => setTimeout(resolve, 100)); - - try { - console.log("Testing connection with form values:", formValues); - const result = await prepareModelAddRequest(formValues, accessToken, null); - - if (!result) { - console.log("No result from prepareModelAddRequest"); - setError("Failed to prepare model data. Please check your form inputs."); - setIsSuccess(false); - setIsLoading(false); - return; - } - - console.log("Result from prepareModelAddRequest:", result); - - const { litellmParamsObj, modelInfoObj, modelName: returnedModelName } = result[0]; - - const response = await testConnectionRequest(accessToken, litellmParamsObj, modelInfoObj, modelInfoObj?.mode); - if (response.status === "success") { - NotificationsManager.success("Connection test successful!"); - setError(null); - setIsSuccess(true); - } else { - const errorMessage = response.result?.error || response.message || "Unknown error"; - setError(errorMessage); - setRawRequest(litellmParamsObj); - setRawResponse(response.result?.raw_request_typed_dict); - setIsSuccess(false); - } - } catch (error) { - console.error("Test connection error:", error); - setError(error instanceof Error ? error.message : String(error)); - setIsSuccess(false); - } finally { - setIsLoading(false); - if (onTestComplete) onTestComplete(); - } - }; - React.useEffect(() => { - // Run the test once when component mounts - // Add a small timeout to ensure form values are ready + const testModelConnection = async () => { + setIsLoading(true); + setShowDetails(false); + setError(null); + setRawResponse(null); + setIsSuccess(false); + + await new Promise((resolve) => setTimeout(resolve, 100)); + + try { + const result = await prepareModelAddRequest( + formValues, + accessToken, + null, + ); + + if (!result) { + setError( + "Failed to prepare model data. Please check your form inputs.", + ); + setIsSuccess(false); + setIsLoading(false); + return; + } + + const { litellmParamsObj, modelInfoObj } = result[0]; + + const response = await testConnectionRequest( + accessToken, + litellmParamsObj, + modelInfoObj, + modelInfoObj?.mode, + ); + if (response.status === "success") { + NotificationsManager.success("Connection test successful!"); + setError(null); + setIsSuccess(true); + } else { + const errorMessage = + response.result?.error || response.message || "Unknown error"; + setError(errorMessage); + setRawResponse(response.result?.raw_request_typed_dict); + setIsSuccess(false); + } + } catch (err) { + console.error("Test connection error:", err); + setError(err instanceof Error ? err.message : String(err)); + setIsSuccess(false); + } finally { + setIsLoading(false); + if (onTestComplete) onTestComplete(); + } + }; + const timer = setTimeout(() => { testModelConnection(); }, 200); return () => clearTimeout(timer); - }, []); // Empty dependency array means this runs once on mount + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); const getCleanErrorMessage = (errorMsg: string) => { if (!errorMsg) return "Unknown error"; const mainError = errorMsg.split("stack trace:")[0].trim(); - const cleanedError = mainError.replace(/^litellm\.(.*?)Error: /, ""); - return cleanedError; }; @@ -108,6 +114,7 @@ const ModelConnectionTest: React.FC = ({ const formatCurlCommand = ( apiBase: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any requestBody: Record, requestHeaders: Record, ) => { @@ -137,152 +144,104 @@ ${formattedBody} : ""; return ( -
+
{isLoading ? ( -
-
- {/* Simple CSS spinner */} -
+
+
+
- Testing connection to {modelName}... - + Testing connection to {modelName}...
) : isSuccess ? ( -
-
- -
- +
+ {/* eslint-disable-next-line litellm-ui/no-raw-tailwind-colors */} + + Connection to {modelName} successful! - +
) : ( - <> -
-
- - - Connection to {modelName} failed - -
- -
+
+ + - - Error:{" "} - - - {errorMessage} - + Connection to {modelName} failed + +
- {error && ( -
- -
- )} -
+
+ Error: + + {errorMessage} + - {showDetails && ( -
- - Troubleshooting Details - -
+                
+ {showDetails ? "Hide Details" : "Show Details"} +
)} - -
- - API Request - -
-                {curlCommand || "No request data available"}
-              
- -
- + + {showDetails && ( +
+ + Troubleshooting Details + +
+                {typeof error === "string"
+                  ? error
+                  : JSON.stringify(error, null, 2)}
+              
+
+ )} + +
+ + API Request + +
+              {curlCommand || "No request data available"}
+            
+ +
+
)} - -
-