diff --git a/ui/litellm-dashboard/src/components/chat/OAuthConnectModal.tsx b/ui/litellm-dashboard/src/components/chat/OAuthConnectModal.tsx deleted file mode 100644 index fb9568463bd..00000000000 --- a/ui/litellm-dashboard/src/components/chat/OAuthConnectModal.tsx +++ /dev/null @@ -1,239 +0,0 @@ -"use client"; - -/** - * OAuthConnectModal - * - * Step-by-step OAuth2 connect modal for users connecting an OpenAPI MCP server - * from the Chat Apps panel. Mirrors the UX of ByokCredentialModal but initiates - * a browser-based OAuth2 PKCE redirect instead of asking for an API key. - */ - -import React, { useEffect, useState } from "react"; -import { Modal } from "antd"; -import { - ArrowRightOutlined, - ArrowLeftOutlined, - CloseOutlined, - CheckOutlined, - LinkOutlined, - LoadingOutlined, -} from "@ant-design/icons"; -import { MCPServer } from "../mcp_tools/types"; -import { useUserMcpOAuthFlow } from "@/hooks/useUserMcpOAuthFlow"; - -interface OAuthConnectModalProps { - server: MCPServer; - open: boolean; - accessToken: string; - onClose: () => void; - onSuccess: (serverId: string) => void; -} - -// Built-in permission descriptions for known providers -const GITHUB_PERMISSIONS = [ - "Read your repositories and code", - "Manage issues and pull requests", - "Access your profile information", -]; - -function getDefaultPermissions(server: MCPServer): string[] { - const name = (server.server_name || server.alias || "").toLowerCase(); - if (name.includes("github")) return GITHUB_PERMISSIONS; - if (server.mcp_info?.description) return [server.mcp_info.description]; - return ["Access this service on your behalf"]; -} - -export const OAuthConnectModal: React.FC = ({ - server, - open, - accessToken, - onClose, - onSuccess, -}) => { - const [step, setStep] = useState<1 | 2>(1); - - const displayName = server.alias || server.server_name || "Service"; - const firstLetter = displayName.charAt(0).toUpperCase(); - const permissions = getDefaultPermissions(server); - - // Extract scopes from credentials if present (stored as array on the server record) - const scopes: string[] | undefined = undefined; // server-level scopes not exposed to UI - - const { startOAuthFlow, status, error } = useUserMcpOAuthFlow({ - accessToken, - serverId: server.server_id, - serverAlias: displayName, - scopes, - onSuccess: () => { - onSuccess(server.server_id); - // handleClose is invoked by the useEffect below to avoid calling it twice. - }, - }); - - // Close the modal whenever the flow reaches "success" — covers both the - // in-page path (status set directly) and the post-redirect resume path. - useEffect(() => { - if (status === "success") { - handleClose(); - } - }, [status]); - - const handleClose = () => { - setStep(1); - onClose(); - }; - - const isLoading = status === "authorizing" || status === "exchanging"; - - const logoUrl = server.mcp_info?.logo_url; - - return ( - -
- {/* Step dots + close */} -
- {step === 2 ? ( - - ) : ( -
- )} -
-
-
-
- -
- - {step === 1 ? ( -
- {/* Logos */} -
-
- L -
- -
- {logoUrl ? ( - {displayName} - ) : ( - {firstLetter} - )} -
-
- -

Connect {displayName}

-

- LiteLLM will connect to {displayName} on your behalf so you can use its tools in chat. -

- - {/* How it works */} -
-
-
- -
-
-

Secure OAuth 2.0

-

- You'll be redirected to {displayName} to authorize access. LiteLLM never sees your password. -

-
-
-
- - {/* Requested permissions */} -
-

- Requested Access -

-
    - {permissions.map((perm, i) => ( -
  • - - {perm} -
  • - ))} -
-
- - - -
- ) : ( -
- {/* Provider logo */} -
- {logoUrl ? ( - {displayName} - ) : ( - {firstLetter} - )} -
- -

Authorize {displayName}

-

- Click below to be redirected to {displayName} where you can authorize access. - You'll be brought back here automatically. -

- - {error && ( -
- {error} -
- )} - - - -
- )} -
- - ); -}; - -export default OAuthConnectModal; diff --git a/ui/litellm-dashboard/tsconfig.json b/ui/litellm-dashboard/tsconfig.json index d24bdd340f7..5b0352feb98 100644 --- a/ui/litellm-dashboard/tsconfig.json +++ b/ui/litellm-dashboard/tsconfig.json @@ -14,7 +14,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "react-jsx", + "jsx": "preserve", "incremental": true, "plugins": [ {