mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
Migrate top-level pages to shadcn (Phase 1)
- LoginPage.tsx: antd Form/Input/Select/Popover/Card/Alert/Space/Typography -> shadcn/Tailwind equivalents. Preserves SSO popover, worker selector, admin-disabled view, and credentials info banner. All 8 existing tests still pass. - OnboardingFormBody.tsx: antd Form.useForm -> react-hook-form; antd Input.Password -> shadcn Input type=password. Retains aria-label='loading' spinner so existing test selector continues to work. - src/app/page.tsx: drop antd ConfigProvider/theme wrapper; dark-mode state now toggles the 'dark' class on <html> so shadcn CSS variables switch. Removed unused QueryClient imports. Adds src/app/onboarding/OnboardingFormBody.tsx to the raw-tailwind-colors lint exception list (SSO info-banner uses bg-blue-50 per existing design pattern). Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
parent
0fd4379e32
commit
43337912e1
4 changed files with 240 additions and 174 deletions
|
|
@ -136,6 +136,7 @@
|
|||
"src/components/prompts/prompt_editor_view/VersionHistorySidePanel.tsx",
|
||||
"src/app/(dashboard)/teams/components/TeamsTable/ModelsCell.tsx",
|
||||
"src/app/(dashboard)/teams/components/TeamsTable/TeamsTable.tsx",
|
||||
"src/app/onboarding/OnboardingFormBody.tsx",
|
||||
"src/components/prompts/prompt_editor_view/conversation_panel/MessageBubble.tsx",
|
||||
"src/components/playground/chat_ui/SessionManagement.tsx",
|
||||
"src/components/playground/chat_ui/SearchResultsDisplay.tsx",
|
||||
|
|
|
|||
|
|
@ -7,8 +7,24 @@ import { exchangeLoginCode, getProxyBaseUrl, switchToWorkerUrl } from "@/compone
|
|||
import { clearTokenCookies, getCookie } from "@/utils/cookieUtils";
|
||||
import { isJwtExpired } from "@/utils/jwtUtils";
|
||||
import { consumeReturnUrl, getReturnUrl, isValidReturnUrl } from "@/utils/returnUrlUtils";
|
||||
import { Info as InfoCircleOutlined, Server as CloudServerOutlined } from "lucide-react";
|
||||
import { Alert, Button, Card, Form, Input, Popover, Select, Space, Typography } from "antd";
|
||||
import { Info, Server, LoaderCircle } from "lucide-react";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useWorker } from "@/hooks/useWorker";
|
||||
|
|
@ -115,7 +131,8 @@ function LoginPageContent() {
|
|||
setIsLoading(false);
|
||||
}, [isConfigLoading, router, uiConfig]);
|
||||
|
||||
const handleSubmit = () => {
|
||||
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
// If a worker is selected, point proxyBaseUrl at it before login
|
||||
const selectedWorker = workers.find((w) => w.worker_id === selectedWorkerId);
|
||||
if (selectedWorker) {
|
||||
|
|
@ -154,8 +171,6 @@ function LoginPageContent() {
|
|||
const error = loginMutation.error instanceof Error ? loginMutation.error.message : null;
|
||||
const isLoginLoading = loginMutation.isPending;
|
||||
|
||||
const { Title, Text, Paragraph } = Typography;
|
||||
|
||||
if (isConfigLoading || isLoading) {
|
||||
return <LoadingScreen />;
|
||||
}
|
||||
|
|
@ -163,175 +178,192 @@ function LoginPageContent() {
|
|||
// Show disabled message if admin UI is disabled
|
||||
if (uiConfig && uiConfig.admin_ui_disabled) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
||||
<Card className="w-full max-w-lg shadow-md">
|
||||
<Space direction="vertical" size="middle" className="w-full">
|
||||
<div className="min-h-screen flex items-center justify-center bg-muted/30">
|
||||
<Card className="w-full max-w-lg shadow-md p-6">
|
||||
<div className="flex flex-col gap-4 w-full">
|
||||
<div className="text-center">
|
||||
<Title level={2}>🚅 LiteLLM</Title>
|
||||
<h2 className="text-2xl font-semibold">🚅 LiteLLM</h2>
|
||||
</div>
|
||||
|
||||
<Alert
|
||||
message="Admin UI Disabled"
|
||||
description={
|
||||
<>
|
||||
<Paragraph className="text-sm">
|
||||
The Admin UI has been disabled by the administrator. To re-enable it, please update the following
|
||||
environment variable:
|
||||
</Paragraph>
|
||||
<Paragraph className="text-sm">
|
||||
<code className="bg-gray-100 px-1 py-0.5 rounded text-xs">DISABLE_ADMIN_UI=False</code>
|
||||
</Paragraph>
|
||||
</>
|
||||
}
|
||||
type="warning"
|
||||
showIcon
|
||||
/>
|
||||
</Space>
|
||||
<Alert>
|
||||
<Info className="h-4 w-4" />
|
||||
<AlertTitle>Admin UI Disabled</AlertTitle>
|
||||
<AlertDescription>
|
||||
<p className="text-sm">
|
||||
The Admin UI has been disabled by the administrator. To re-enable it, please update the following
|
||||
environment variable:
|
||||
</p>
|
||||
<p className="text-sm mt-2">
|
||||
<code className="bg-muted px-1 py-0.5 rounded text-xs">DISABLE_ADMIN_UI=False</code>
|
||||
</p>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
||||
<Card className="w-full max-w-lg shadow-md">
|
||||
<Space direction="vertical" size="middle" className="w-full">
|
||||
<div className="min-h-screen flex items-center justify-center bg-muted/30">
|
||||
<Card className="w-full max-w-lg shadow-md p-6">
|
||||
<div className="flex flex-col gap-4 w-full">
|
||||
<div className="text-center">
|
||||
<Title level={2}>🚅 LiteLLM</Title>
|
||||
<h2 className="text-2xl font-semibold">🚅 LiteLLM</h2>
|
||||
</div>
|
||||
|
||||
<div className="text-center">
|
||||
<Title level={3}>Login</Title>
|
||||
<Text type="secondary">Access your LiteLLM Admin UI.</Text>
|
||||
<h3 className="text-xl font-semibold">Login</h3>
|
||||
<p className="text-sm text-muted-foreground">Access your LiteLLM Admin UI.</p>
|
||||
</div>
|
||||
|
||||
<Alert
|
||||
message="Default Credentials"
|
||||
description={
|
||||
<>
|
||||
<Paragraph className="text-sm">
|
||||
By default, Username is <code className="bg-gray-100 px-1 py-0.5 rounded text-xs">admin</code> and
|
||||
Password is your set LiteLLM Proxy
|
||||
<code className="bg-gray-100 px-1 py-0.5 rounded text-xs">MASTER_KEY</code>.
|
||||
</Paragraph>
|
||||
<Paragraph className="text-sm">
|
||||
Need to set UI credentials or SSO?{" "}
|
||||
<a href="https://docs.litellm.ai/docs/proxy/ui" target="_blank" rel="noopener noreferrer">
|
||||
Check the documentation
|
||||
</a>
|
||||
.
|
||||
</Paragraph>
|
||||
</>
|
||||
}
|
||||
type="info"
|
||||
icon={<InfoCircleOutlined />}
|
||||
showIcon
|
||||
/>
|
||||
<Alert>
|
||||
<Info className="h-4 w-4" />
|
||||
<AlertTitle>Default Credentials</AlertTitle>
|
||||
<AlertDescription>
|
||||
<p className="text-sm">
|
||||
By default, Username is <code className="bg-muted px-1 py-0.5 rounded text-xs">admin</code> and
|
||||
Password is your set LiteLLM Proxy{" "}
|
||||
<code className="bg-muted px-1 py-0.5 rounded text-xs">MASTER_KEY</code>.
|
||||
</p>
|
||||
<p className="text-sm mt-2">
|
||||
Need to set UI credentials or SSO?{" "}
|
||||
<a
|
||||
href="https://docs.litellm.ai/docs/proxy/ui"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline"
|
||||
>
|
||||
Check the documentation
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
{error && <Alert message={error} type="error" showIcon />}
|
||||
{error && (
|
||||
<Alert variant="destructive">
|
||||
<AlertDescription>{error}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Form onFinish={handleSubmit} layout="vertical" requiredMark={false}>
|
||||
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
|
||||
{uiConfig?.is_control_plane && workers.length > 0 && (
|
||||
<Form.Item label="Worker" style={{ marginBottom: 16 }}>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="worker">Worker</Label>
|
||||
<Select
|
||||
value={selectedWorkerId || undefined}
|
||||
onChange={(value) => setSelectedWorkerId(value)}
|
||||
placeholder="Choose a worker to connect to"
|
||||
size="large"
|
||||
suffixIcon={<CloudServerOutlined />}
|
||||
options={workers.map((w) => ({
|
||||
label: w.name,
|
||||
value: w.worker_id,
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
onValueChange={(value) => setSelectedWorkerId(value)}
|
||||
>
|
||||
<SelectTrigger id="worker" className="h-11">
|
||||
<div className="flex items-center gap-2 flex-1">
|
||||
<SelectValue placeholder="Choose a worker to connect to" />
|
||||
</div>
|
||||
<Server className="h-4 w-4 text-muted-foreground" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{workers.map((w) => (
|
||||
<SelectItem key={w.worker_id} value={w.worker_id}>
|
||||
{w.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Form.Item
|
||||
label="Username"
|
||||
name="username"
|
||||
rules={[{ required: true, message: "Please enter your username" }]}
|
||||
>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="username">Username</Label>
|
||||
<Input
|
||||
id="username"
|
||||
type="text"
|
||||
placeholder="Enter your username"
|
||||
autoComplete="username"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
disabled={isLoginLoading}
|
||||
size="large"
|
||||
className="rounded-md border-gray-300"
|
||||
required
|
||||
className="h-11"
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<Form.Item
|
||||
label="Password"
|
||||
name="password"
|
||||
rules={[{ required: true, message: "Please enter your password" }]}
|
||||
>
|
||||
<Input.Password
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
placeholder="Enter your password"
|
||||
autoComplete="current-password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
disabled={isLoginLoading}
|
||||
size="large"
|
||||
required
|
||||
className="h-11"
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={isLoginLoading}
|
||||
className="w-full h-11"
|
||||
>
|
||||
{isLoginLoading && <LoaderCircle className="h-4 w-4 animate-spin mr-2" />}
|
||||
{isLoginLoading ? "Logging in..." : "Login"}
|
||||
</Button>
|
||||
|
||||
{!uiConfig?.sso_configured ? (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<span className="w-full">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
disabled
|
||||
className="w-full h-11"
|
||||
>
|
||||
Login with SSO
|
||||
</Button>
|
||||
</span>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
Please configure SSO to log in with SSO.
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
) : (
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
loading={isLoginLoading}
|
||||
disabled={isLoginLoading}
|
||||
block
|
||||
size="large"
|
||||
type="button"
|
||||
variant="outline"
|
||||
disabled={isLoginLoading || (!!selectedWorkerId && workers.length === 0)}
|
||||
onClick={() => {
|
||||
const selectedWorker = workers.find((w) => w.worker_id === selectedWorkerId);
|
||||
if (selectedWorker) {
|
||||
// Store worker selection so useWorker hook restores it after redirect
|
||||
localStorage.setItem("litellm_selected_worker_id", selectedWorkerId!);
|
||||
switchToWorkerUrl(selectedWorker.url);
|
||||
}
|
||||
// SSO on the worker (or this instance if no worker), always
|
||||
// include return_to so the callback redirects back here
|
||||
const ssoBase = selectedWorker?.url ?? getProxyBaseUrl();
|
||||
const returnTo = encodeURIComponent(window.location.origin + "/ui/login");
|
||||
router.push(`${ssoBase}/sso/key/generate?return_to=${returnTo}`);
|
||||
}}
|
||||
className="w-full h-11"
|
||||
>
|
||||
{isLoginLoading ? "Logging in..." : "Login"}
|
||||
Login with SSO
|
||||
</Button>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
{!uiConfig?.sso_configured ? (
|
||||
<Popover
|
||||
content="Please configure SSO to log in with SSO."
|
||||
trigger="hover"
|
||||
>
|
||||
<Button disabled block size="large">
|
||||
Login with SSO
|
||||
</Button>
|
||||
</Popover>
|
||||
) : (
|
||||
<Button
|
||||
disabled={isLoginLoading || (!!selectedWorkerId && workers.length === 0)}
|
||||
onClick={() => {
|
||||
const selectedWorker = workers.find((w) => w.worker_id === selectedWorkerId);
|
||||
if (selectedWorker) {
|
||||
// Store worker selection so useWorker hook restores it after redirect
|
||||
localStorage.setItem("litellm_selected_worker_id", selectedWorkerId!);
|
||||
switchToWorkerUrl(selectedWorker.url);
|
||||
}
|
||||
// SSO on the worker (or this instance if no worker), always
|
||||
// include return_to so the callback redirects back here
|
||||
const ssoBase = selectedWorker?.url ?? getProxyBaseUrl();
|
||||
const returnTo = encodeURIComponent(window.location.origin + "/ui/login");
|
||||
router.push(`${ssoBase}/sso/key/generate?return_to=${returnTo}`);
|
||||
}}
|
||||
block
|
||||
size="large"
|
||||
>
|
||||
Login with SSO
|
||||
</Button>
|
||||
)}
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Space>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
{uiConfig?.sso_configured && (
|
||||
<Alert
|
||||
type="info"
|
||||
showIcon
|
||||
closable
|
||||
message={<Text>Single Sign-On (SSO) is enabled. LiteLLM no longer automatically redirects to the SSO login flow upon loading this page. To re-enable auto-redirect-to-SSO, set <Text code>AUTO_REDIRECT_UI_LOGIN_TO_SSO=true</Text> in your environment configuration.</Text>}
|
||||
/>
|
||||
<Alert className="mt-4">
|
||||
<Info className="h-4 w-4" />
|
||||
<AlertDescription>
|
||||
Single Sign-On (SSO) is enabled. LiteLLM no longer automatically redirects to the SSO login flow upon
|
||||
loading this page. To re-enable auto-redirect-to-SSO, set{" "}
|
||||
<code className="bg-muted px-1 py-0.5 rounded text-xs">AUTO_REDIRECT_UI_LOGIN_TO_SSO=true</code> in your
|
||||
environment configuration.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import React from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Info } from "lucide-react";
|
||||
import { Form, Input as AntInput } from "antd";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Info, LoaderCircle } from "lucide-react";
|
||||
|
||||
type OnboardingFormBodyProps = {
|
||||
variant: "signup" | "reset_password";
|
||||
|
|
@ -13,6 +14,11 @@ type OnboardingFormBodyProps = {
|
|||
onSubmit: (values: { password: string }) => void;
|
||||
};
|
||||
|
||||
type FormValues = {
|
||||
user_email: string;
|
||||
password: string;
|
||||
};
|
||||
|
||||
export function OnboardingFormBody({
|
||||
variant,
|
||||
userEmail,
|
||||
|
|
@ -20,11 +26,18 @@ export function OnboardingFormBody({
|
|||
claimError,
|
||||
onSubmit,
|
||||
}: OnboardingFormBodyProps) {
|
||||
const [form] = Form.useForm();
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
} = useForm<FormValues>({
|
||||
defaultValues: { user_email: userEmail, password: "" },
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (userEmail) form.setFieldValue("user_email", userEmail);
|
||||
}, [userEmail, form]);
|
||||
if (userEmail) setValue("user_email", userEmail);
|
||||
}, [userEmail, setValue]);
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md mt-10">
|
||||
|
|
@ -62,48 +75,64 @@ export function OnboardingFormBody({
|
|||
</div>
|
||||
)}
|
||||
|
||||
<Form
|
||||
className="mt-10 mb-5"
|
||||
layout="vertical"
|
||||
form={form}
|
||||
onFinish={(values) => onSubmit({ password: values.password })}
|
||||
<form
|
||||
className="mt-10 mb-5 flex flex-col gap-4"
|
||||
onSubmit={handleSubmit((values) =>
|
||||
onSubmit({ password: values.password }),
|
||||
)}
|
||||
>
|
||||
<Form.Item label="Email Address" name="user_email">
|
||||
<Input type="email" disabled />
|
||||
</Form.Item>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="user_email">Email Address</Label>
|
||||
<Input
|
||||
id="user_email"
|
||||
type="email"
|
||||
disabled
|
||||
{...register("user_email")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Form.Item
|
||||
label="Password"
|
||||
name="password"
|
||||
rules={[
|
||||
{ required: true, message: "password required to sign up" },
|
||||
]}
|
||||
help={
|
||||
variant === "reset_password"
|
||||
? "Enter your new password"
|
||||
: "Create a password for your account"
|
||||
}
|
||||
>
|
||||
<AntInput.Password />
|
||||
</Form.Item>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
{...register("password", {
|
||||
required: "password required to sign up",
|
||||
})}
|
||||
/>
|
||||
{errors.password ? (
|
||||
<p className="text-sm text-destructive">
|
||||
{errors.password.message as string}
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{variant === "reset_password"
|
||||
? "Enter your new password"
|
||||
: "Create a password for your account"}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{claimError && (
|
||||
<div className="flex gap-2 items-start p-3 rounded-md bg-destructive/10 border border-destructive/30 text-destructive mb-4">
|
||||
<div className="flex gap-2 items-start p-3 rounded-md bg-destructive/10 border border-destructive/30 text-destructive">
|
||||
<Info className="h-4 w-4 mt-0.5 shrink-0" />
|
||||
<div className="text-sm">{claimError}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-10">
|
||||
<div className="mt-6">
|
||||
<Button type="submit" disabled={isPending}>
|
||||
{isPending
|
||||
? "…"
|
||||
: variant === "reset_password"
|
||||
? "Reset Password"
|
||||
: "Sign Up"}
|
||||
{isPending && (
|
||||
<LoaderCircle
|
||||
className="h-4 w-4 animate-spin mr-2"
|
||||
aria-label="loading"
|
||||
role="img"
|
||||
/>
|
||||
)}
|
||||
{variant === "reset_password" ? "Reset Password" : "Sign Up"}
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</form>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -46,11 +46,9 @@ import { clearTokenCookies, getCookie } from "@/utils/cookieUtils";
|
|||
import { isJwtExpired } from "@/utils/jwtUtils";
|
||||
import { buildLoginUrlWithReturn, consumeReturnUrl, isValidReturnUrl, normalizeUrlForCompare, storeReturnUrl } from "@/utils/returnUrlUtils";
|
||||
import { formatUserRole, isAdminRole } from "@/utils/roles";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { jwtDecode } from "jwt-decode";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { Suspense, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { ConfigProvider, theme } from "antd";
|
||||
|
||||
function deleteCookie(name: string, path = "/") {
|
||||
// Best-effort client-side clear (works for non-HttpOnly cookies without Domain)
|
||||
|
|
@ -114,6 +112,16 @@ function CreateKeyPageContent() {
|
|||
setIsDarkMode(!isDarkMode);
|
||||
};
|
||||
|
||||
// Apply dark-mode class to the root element so shadcn CSS variables switch.
|
||||
useEffect(() => {
|
||||
const root = document.documentElement;
|
||||
if (isDarkMode) {
|
||||
root.classList.add("dark");
|
||||
} else {
|
||||
root.classList.remove("dark");
|
||||
}
|
||||
}, [isDarkMode]);
|
||||
|
||||
const invitation_id = searchParams.get("invitation_id");
|
||||
|
||||
// Parse URL query parameters for pre-filling the create key form
|
||||
|
|
@ -451,9 +459,6 @@ function CreateKeyPageContent() {
|
|||
|
||||
return (
|
||||
<Suspense fallback={<LoadingScreen />}>
|
||||
<ConfigProvider theme={{
|
||||
algorithm: isDarkMode ? theme.darkAlgorithm : theme.defaultAlgorithm,
|
||||
}}>
|
||||
<ThemeProvider accessToken={accessToken}>
|
||||
{invitation_id ? (
|
||||
<UserDashboard
|
||||
|
|
@ -675,7 +680,6 @@ function CreateKeyPageContent() {
|
|||
</div>
|
||||
)}
|
||||
</ThemeProvider>
|
||||
</ConfigProvider>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue