From c2e9519d0265403174b7fc06060ffc1deb249edf Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 23 Apr 2026 20:58:02 +0000 Subject: [PATCH] feat(ui): Settings/AdminSettings/SSOSettings/SSOSettings to shadcn - antd Button/Card/Descriptions/Space/Tag/Typography \u2192 shadcn Badge/Button/Card + native flex layout + DescRow helper replacing antd Descriptions. - Typography.Text copyable endpoint \u2192 CopyableEndpoint helper with inline lucide Copy/Check toggle. Inline style={{...}} on provider logo replaced with Tailwind utilities. Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang --- .../AdminSettings/SSOSettings/SSOSettings.tsx | 275 +++++++++++++----- 1 file changed, 196 insertions(+), 79 deletions(-) diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettings.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettings.tsx index fdeda0ece3e..abe3354cea5 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettings.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/SSOSettings.tsx @@ -1,8 +1,14 @@ "use client"; -import { useSSOSettings, type SSOSettingsValues } from "@/app/(dashboard)/hooks/sso/useSSOSettings"; -import { Button, Card, Descriptions, Space, Tag, Typography } from "antd"; -import { Edit, Shield, Trash2 } from "lucide-react"; +import { + useSSOSettings, + type SSOSettingsValues, +} from "@/app/(dashboard)/hooks/sso/useSSOSettings"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { cn } from "@/lib/utils"; +import { Check, Copy, Edit, Shield, Trash2 } from "lucide-react"; import { useState } from "react"; import { ssoProviderDisplayNames, ssoProviderLogoMap } from "./constants"; import AddSSOSettingsModal from "./Modals/AddSSOSettingsModal"; @@ -14,7 +20,57 @@ import SSOSettingsEmptyPlaceholder from "./SSOSettingsEmptyPlaceholder"; import SSOSettingsLoadingSkeleton from "./SSOSettingsLoadingSkeleton"; import { detectSSOProvider } from "./utils"; -const { Title, Text } = Typography; +const CopyableEndpoint: React.FC<{ value?: string | null }> = ({ value }) => { + const [copied, setCopied] = useState(false); + if (!value) { + return ( + - + ); + } + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(value); + setCopied(true); + setTimeout(() => setCopied(false), 1500); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (_e) { + /* noop */ + } + }; + return ( + + {value} + + + ); +}; + +const DescRow: React.FC<{ + label: string; + children: React.ReactNode; + first?: boolean; +}> = ({ label, children, first }) => ( +
+
{label}
+
{children}
+
+); export default function SSOSettings() { const { data: ssoSettings, refetch, isLoading } = useSSOSettings(); @@ -26,52 +82,51 @@ export default function SSOSettings() { Boolean(ssoSettings?.values.microsoft_client_id) || Boolean(ssoSettings?.values.generic_client_id); - const selectedProvider = ssoSettings?.values ? detectSSOProvider(ssoSettings.values) : null; - const isRoleMappingsEnabled = Boolean(ssoSettings?.values.role_mappings); + const selectedProvider = ssoSettings?.values + ? detectSSOProvider(ssoSettings.values) + : null; const isTeamMappingsEnabled = Boolean(ssoSettings?.values.team_mappings); - - const renderEndpointValue = (value?: string | null) => ( - - {value || "-"} - - ); + const isRoleMappingsEnabled = Boolean(ssoSettings?.values.role_mappings); const renderSimpleValue = (value?: string | null) => - value ? value : Not configured; + value ? ( + {value} + ) : ( + Not configured + ); const renderTeamMappingsField = (values: SSOSettingsValues) => { if (!values.team_mappings?.team_ids_jwt_field) { - return Not configured; + return ( + Not configured + ); } return ( - {values.team_mappings.team_ids_jwt_field} + {values.team_mappings.team_ids_jwt_field} ); }; - const descriptionsConfig = { - column: { - xxl: 1, - xl: 1, - lg: 1, - md: 1, - sm: 1, - xs: 1, - }, - }; - const providerConfigs = { google: { providerText: ssoProviderDisplayNames.google, fields: [ { label: "Client ID", - render: (values: SSOSettingsValues) => , + render: (values: SSOSettingsValues) => ( + + ), }, { label: "Client Secret", - render: (values: SSOSettingsValues) => , + render: (values: SSOSettingsValues) => ( + + ), + }, + { + label: "Proxy Base URL", + render: (values: SSOSettingsValues) => + renderSimpleValue(values.proxy_base_url), }, - { label: "Proxy Base URL", render: (values: SSOSettingsValues) => renderSimpleValue(values.proxy_base_url) }, ], }, microsoft: { @@ -79,14 +134,26 @@ export default function SSOSettings() { fields: [ { label: "Client ID", - render: (values: SSOSettingsValues) => , + render: (values: SSOSettingsValues) => ( + + ), }, { label: "Client Secret", - render: (values: SSOSettingsValues) => , + render: (values: SSOSettingsValues) => ( + + ), + }, + { + label: "Tenant", + render: (values: SSOSettingsValues) => + renderSimpleValue(values.microsoft_tenant), + }, + { + label: "Proxy Base URL", + render: (values: SSOSettingsValues) => + renderSimpleValue(values.proxy_base_url), }, - { label: "Tenant", render: (values: any) => renderSimpleValue(values.microsoft_tenant) }, - { label: "Proxy Base URL", render: (values: SSOSettingsValues) => renderSimpleValue(values.proxy_base_url) }, ], }, okta: { @@ -94,29 +161,46 @@ export default function SSOSettings() { fields: [ { label: "Client ID", - render: (values: SSOSettingsValues) => , + render: (values: SSOSettingsValues) => ( + + ), }, { label: "Client Secret", - render: (values: SSOSettingsValues) => , + render: (values: SSOSettingsValues) => ( + + ), }, { label: "Authorization Endpoint", - render: (values: SSOSettingsValues) => renderEndpointValue(values.generic_authorization_endpoint), + render: (values: SSOSettingsValues) => ( + + ), }, { label: "Token Endpoint", - render: (values: SSOSettingsValues) => renderEndpointValue(values.generic_token_endpoint), + render: (values: SSOSettingsValues) => ( + + ), }, { label: "User Info Endpoint", - render: (values: SSOSettingsValues) => renderEndpointValue(values.generic_userinfo_endpoint), + render: (values: SSOSettingsValues) => ( + + ), }, - { label: "Proxy Base URL", render: (values: SSOSettingsValues) => renderSimpleValue(values.proxy_base_url) }, - isTeamMappingsEnabled ? { - label: "Team IDs JWT Field", - render: (values: SSOSettingsValues) => renderTeamMappingsField(values), - } : null, + { + label: "Proxy Base URL", + render: (values: SSOSettingsValues) => + renderSimpleValue(values.proxy_base_url), + }, + isTeamMappingsEnabled + ? { + label: "Team IDs JWT Field", + render: (values: SSOSettingsValues) => + renderTeamMappingsField(values), + } + : null, ], }, generic: { @@ -124,29 +208,46 @@ export default function SSOSettings() { fields: [ { label: "Client ID", - render: (values: SSOSettingsValues) => , + render: (values: SSOSettingsValues) => ( + + ), }, { label: "Client Secret", - render: (values: SSOSettingsValues) => , + render: (values: SSOSettingsValues) => ( + + ), }, { label: "Authorization Endpoint", - render: (values: SSOSettingsValues) => renderEndpointValue(values.generic_authorization_endpoint), + render: (values: SSOSettingsValues) => ( + + ), }, { label: "Token Endpoint", - render: (values: SSOSettingsValues) => renderEndpointValue(values.generic_token_endpoint), + render: (values: SSOSettingsValues) => ( + + ), }, { label: "User Info Endpoint", - render: (values: SSOSettingsValues) => renderEndpointValue(values.generic_userinfo_endpoint), + render: (values: SSOSettingsValues) => ( + + ), }, - { label: "Proxy Base URL", render: (values: SSOSettingsValues) => renderSimpleValue(values.proxy_base_url) }, - isTeamMappingsEnabled ? { - label: "Team IDs JWT Field", - render: (values: SSOSettingsValues) => renderTeamMappingsField(values), - } : null, + { + label: "Proxy Base URL", + render: (values: SSOSettingsValues) => + renderSimpleValue(values.proxy_base_url), + }, + isTeamMappingsEnabled + ? { + label: "Team IDs JWT Field", + render: (values: SSOSettingsValues) => + renderTeamMappingsField(values), + } + : null, ], }, }; @@ -155,30 +256,35 @@ export default function SSOSettings() { if (!ssoSettings?.values || !selectedProvider) return null; const { values } = ssoSettings; - const config = providerConfigs[selectedProvider as keyof typeof providerConfigs]; + const config = + providerConfigs[selectedProvider as keyof typeof providerConfigs]; if (!config) return null; return ( - - -
+
+ +
{ssoProviderLogoMap[selectedProvider] && ( + // eslint-disable-next-line @next/next/no-img-element {selectedProvider} )} {config.providerText}
- - {config.fields.map((field, index) => field && ( - - {field.render(values)} - - ))} - +
+ {config.fields.map( + (field, index) => + field && ( + + {field.render(values)} + + ), + )} +
); }; @@ -187,30 +293,37 @@ export default function SSOSettings() { {isLoading ? ( ) : ( - - - - {/* Header Section */} +
+ +
- +
- SSO Configuration - Manage Single Sign-On authentication settings +

+ SSO Configuration +

+

+ Manage Single Sign-On authentication settings +

{isSSOConfigured && ( <> - @@ -221,12 +334,16 @@ export default function SSOSettings() { {isSSOConfigured ? ( renderSSOSettings() ) : ( - setIsAddModalVisible(true)} /> + setIsAddModalVisible(true)} + /> )} - +
- {isRoleMappingsEnabled && } - + {isRoleMappingsEnabled && ( + + )} +
)}