diff --git a/ui/litellm-dashboard/.eslintrc.json b/ui/litellm-dashboard/.eslintrc.json index ecebf685b32..b00d944a961 100644 --- a/ui/litellm-dashboard/.eslintrc.json +++ b/ui/litellm-dashboard/.eslintrc.json @@ -83,6 +83,7 @@ "src/components/SearchTools/SearchToolColumn.tsx", "src/components/team/available_teams.tsx", "src/components/AIHub/forms/MakeAgentPublicForm.tsx", + "src/components/AIHub/forms/MakeMCPPublicForm.tsx", "src/components/permissions/VectorStorePermissions.tsx", "src/components/permissions/AgentPermissions.tsx", "src/components/permissions/MCPServerPermissions.tsx", diff --git a/ui/litellm-dashboard/src/components/AIHub/forms/MakeMCPPublicForm.tsx b/ui/litellm-dashboard/src/components/AIHub/forms/MakeMCPPublicForm.tsx index d7103da9ed7..5a44885fa42 100644 --- a/ui/litellm-dashboard/src/components/AIHub/forms/MakeMCPPublicForm.tsx +++ b/ui/litellm-dashboard/src/components/AIHub/forms/MakeMCPPublicForm.tsx @@ -1,6 +1,15 @@ import React, { useState, useEffect } from "react"; -import { Modal, Form, Steps, Button, Checkbox } from "antd"; -import { Text, Title, Badge } from "@tremor/react"; +import { Form, Steps } from "antd"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Checkbox } from "@/components/ui/checkbox"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { cn } from "@/lib/utils"; import { makeMCPPublicCall } from "../../networking"; import NotificationsManager from "../../molecules/notifications_manager"; import { MCPServerData } from "@/components/mcp_hub_table_columns"; @@ -15,6 +24,16 @@ interface MakeMCPPublicFormProps { onSuccess: () => void; } +const STATUS_BADGE_CLASSES = (status?: string): string => { + if (status === "active" || status === "healthy") { + return "bg-emerald-100 text-emerald-700 dark:bg-emerald-950 dark:text-emerald-300"; + } + if (status === "inactive" || status === "unhealthy") { + return "bg-red-100 text-red-700 dark:bg-red-950 dark:text-red-300"; + } + return "bg-muted text-muted-foreground"; +}; + const MakeMCPPublicForm: React.FC = ({ visible, onClose, @@ -23,7 +42,9 @@ const MakeMCPPublicForm: React.FC = ({ onSuccess, }) => { const [currentStep, setCurrentStep] = useState(0); - const [selectedServers, setSelectedServers] = useState>(new Set()); + const [selectedServers, setSelectedServers] = useState>( + new Set(), + ); const [loading, setLoading] = useState(false); const [form] = Form.useForm(); @@ -37,7 +58,9 @@ const MakeMCPPublicForm: React.FC = ({ const handleNext = () => { if (currentStep === 0) { if (selectedServers.size === 0) { - NotificationsManager.fromBackend("Please select at least one MCP server to make public"); + NotificationsManager.fromBackend( + "Please select at least one MCP server to make public", + ); return; } setCurrentStep(1); @@ -69,22 +92,22 @@ const MakeMCPPublicForm: React.FC = ({ } }; - // Initialize and preselect already public servers when modal opens useEffect(() => { if (visible && mcpHubData.length > 0) { - // Extract server IDs from servers that are already public const publicServerIds = mcpHubData .filter((server) => server.mcp_info?.is_public === true) .map((server) => server.server_id); - // Preselect servers that are already public setSelectedServers(new Set(publicServerIds)); } - }, [visible]); // Only re-run when modal visibility changes, not when mcpHubData updates + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [visible]); const handleSubmit = async () => { if (selectedServers.size === 0) { - NotificationsManager.fromBackend("Please select at least one MCP server to make public"); + NotificationsManager.fromBackend( + "Please select at least one MCP server to make public", + ); return; } @@ -92,15 +115,18 @@ const MakeMCPPublicForm: React.FC = ({ try { const serverIdsToMakePublic = Array.from(selectedServers); - // Make batch API call for all servers await makeMCPPublicCall(accessToken, serverIdsToMakePublic); - NotificationsManager.success(`Successfully made ${serverIdsToMakePublic.length} MCP server(s) public!`); + NotificationsManager.success( + `Successfully made ${serverIdsToMakePublic.length} MCP server(s) public!`, + ); handleClose(); onSuccess(); } catch (error) { console.error("Error making MCP servers public:", error); - NotificationsManager.fromBackend("Failed to make MCP servers public. Please try again."); + NotificationsManager.fromBackend( + "Failed to make MCP servers public. Please try again.", + ); } finally { setLoading(false); } @@ -108,87 +134,109 @@ const MakeMCPPublicForm: React.FC = ({ const renderStep1Content = () => { const allServersSelected = - mcpHubData.length > 0 && mcpHubData.every((server) => selectedServers.has(server.server_id)); + mcpHubData.length > 0 && + mcpHubData.every((server) => selectedServers.has(server.server_id)); const isIndeterminate = selectedServers.size > 0 && !allServersSelected; return (
- Select MCP Servers to Make Public -
+

+ Select MCP Servers to Make Public +

+
+ +
- - Select the MCP servers you want to be visible on the public model hub. Users will still require a valid - Virtual Key to use these servers. - +

+ Select the MCP servers you want to be visible on the public model + hub. Users will still require a valid Virtual Key to use these + servers. +

-
+
{mcpHubData.length === 0 ? ( -
- No MCP servers available. +
+

No MCP servers available.

) : ( mcpHubData.map((server) => { const isPublic = server.mcp_info?.is_public === true; return ( -
handleServerSelection(server.server_id, e.target.checked)} + onCheckedChange={(c) => + handleServerSelection(server.server_id, c === true) + } />
-
- {server.server_name} +
+ + {server.server_name} + {isPublic && ( - + Public )} - + {server.transport} {server.status || "unknown"}
- {server.description || server.url} - {server.allowed_tools && server.allowed_tools.length > 0 && ( -
- {server.allowed_tools.slice(0, 3).map((tool, idx) => ( - - {tool} - - ))} - {server.allowed_tools.length > 3 && ( - +{server.allowed_tools.length - 3} more - )} -
- )} +

+ {server.description || server.url} +

+ {server.allowed_tools && + server.allowed_tools.length > 0 && ( +
+ {server.allowed_tools + .slice(0, 3) + .map((tool, idx) => ( + + {tool} + + ))} + {server.allowed_tools.length > 3 && ( + + +{server.allowed_tools.length - 3} more + + )} +
+ )}
-
+ ); }) )} @@ -196,10 +244,11 @@ const MakeMCPPublicForm: React.FC = ({
{selectedServers.size > 0 && ( -
- - {selectedServers.size} MCP server{selectedServers.size !== 1 ? "s" : ""} selected - +
+

+ {selectedServers.size} MCP server + {selectedServers.size !== 1 ? "s" : ""} selected +

)}
@@ -209,48 +258,62 @@ const MakeMCPPublicForm: React.FC = ({ const renderStep2Content = () => { return (
- Confirm Making MCP Servers Public +

+ Confirm Making MCP Servers Public +

-
- - Warning: Once you make these MCP servers public, anyone who can go to the{" "} - /ui/model_hub_table will be able to know they exist on the proxy. - +
+

+ Warning: Once you make these MCP servers public, + anyone who can go to the /ui/model_hub_table will be + able to know they exist on the proxy. +

- MCP Servers to be made public: -
+

MCP Servers to be made public:

+
{Array.from(selectedServers).map((serverId) => { - const server = mcpHubData.find((s) => s.server_id === serverId); + const server = mcpHubData.find( + (s) => s.server_id === serverId, + ); return ( -
+
-
- {server?.server_name || serverId} +
+ + {server?.server_name || serverId} + {server && ( <> - + {server.transport} {server.status || "unknown"} )}
- {server?.description && {server.description}} - {server?.url && {server.url}} + {server?.description && ( +

+ {server.description} +

+ )} + {server?.url && ( +

+ {server.url} +

+ )}
); @@ -259,11 +322,11 @@ const MakeMCPPublicForm: React.FC = ({
-
- - Total: {selectedServers.size} MCP server{selectedServers.size !== 1 ? "s" : ""} will be - made public - +
+

+ Total: {selectedServers.size} MCP server + {selectedServers.size !== 1 ? "s" : ""} will be made public +

); @@ -283,7 +346,10 @@ const MakeMCPPublicForm: React.FC = ({ const renderStepButtons = () => { return (
- @@ -295,8 +361,8 @@ const MakeMCPPublicForm: React.FC = ({ )} {currentStep === 1 && ( - )}
@@ -305,24 +371,25 @@ const MakeMCPPublicForm: React.FC = ({ }; return ( - (!o ? handleClose() : undefined)} > -
- - - - + + + Make MCP Servers Public + + + + + + - {renderStepContent()} - {renderStepButtons()} - -
+ {renderStepContent()} + {renderStepButtons()} + + + ); };