Merge branch 'main' into litellm_daily_metrics

This commit is contained in:
Ishaan Jaff 2024-02-27 20:33:35 -08:00 committed by GitHub
commit 990439c49c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 366 additions and 380 deletions

View file

@ -15,6 +15,7 @@ const CreateKeyPage = () => {
const [userRole, setUserRole] = useState("");
const [userEmail, setUserEmail] = useState<null | string>(null);
const [teams, setTeams] = useState<null | any[]>(null);
const [showSSOBanner, setShowSSOBanner] = useState<boolean>(true);
const searchParams = useSearchParams();
const userID = searchParams.get("userID");
@ -48,6 +49,14 @@ const CreateKeyPage = () => {
} else {
console.log(`User Email is not set ${decoded}`);
}
if (decoded.login_method) {
setShowSSOBanner(
decoded.login_method == "username_password" ? true : false
);
} else {
console.log(`User Email is not set ${decoded}`);
}
}
}
}, [token]);
@ -74,7 +83,12 @@ const CreateKeyPage = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<div className="flex flex-col min-h-screen">
<Navbar userID={userID} userRole={userRole} userEmail={userEmail} />
<Navbar
userID={userID}
userRole={userRole}
userEmail={userEmail}
showSSOBanner={showSSOBanner}
/>
<div className="flex flex-1 overflow-auto">
<Sidebar
setPage={setPage}

View file

@ -1,149 +0,0 @@
"use client";
import React, { Suspense, useEffect, useState } from "react";
import { useSearchParams } from "next/navigation";
import Navbar from "../../components/navbar";
import Sidebar from "../../components/leftnav";
import { jwtDecode } from "jwt-decode";
import Link from "next/link";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeaderCell,
TableRow,
Card,
Icon,
Button,
Col,
Grid,
} from "@tremor/react";
import { CogIcon } from "@heroicons/react/outline";
const TeamSettingsPage = () => {
const [userRole, setUserRole] = useState("");
const [userEmail, setUserEmail] = useState<null | string>(null);
const [teams, setTeams] = useState<null | string[]>(null);
const searchParams = useSearchParams();
const userID = searchParams.get("userID");
const token = searchParams.get("token");
const [page, setPage] = useState("team");
const [accessToken, setAccessToken] = useState<string | null>(null);
useEffect(() => {
if (token) {
const decoded = jwtDecode(token) as { [key: string]: any };
if (decoded) {
// cast decoded to dictionary
console.log("Decoded token:", decoded);
console.log("Decoded key:", decoded.key);
// set accessToken
setAccessToken(decoded.key);
// check if userRole is defined
if (decoded.user_role) {
const formattedUserRole = formatUserRole(decoded.user_role);
console.log("Decoded user_role:", formattedUserRole);
setUserRole(formattedUserRole);
} else {
console.log("User role not defined");
}
if (decoded.user_email) {
setUserEmail(decoded.user_email);
} else {
console.log(`User Email is not set ${decoded}`);
}
}
}
}, [token]);
function formatUserRole(userRole: string) {
if (!userRole) {
return "Undefined Role";
}
console.log(`Received user role: ${userRole}`);
switch (userRole.toLowerCase()) {
case "app_owner":
return "App Owner";
case "demo_app_owner":
return "App Owner";
case "app_admin":
return "Admin";
case "app_user":
return "App User";
default:
return "Unknown Role";
}
}
return (
<Suspense fallback={<div>Loading...</div>}>
<div className="flex flex-col min-h-screen">
<Navbar userID={userID} userRole={userRole} userEmail={userEmail} />
<div className="flex flex-1 overflow-auto">
<Grid numItems={1} className="gap-0 p-10 h-[75vh] w-full">
<Col numColSpan={1}>
<Card className="w-full mx-auto flex-auto overflow-y-auto max-h-[50vh]">
<Table>
<TableHead>
<TableRow>
<TableHeaderCell>Team Name</TableHeaderCell>
<TableHeaderCell>Spend (USD)</TableHeaderCell>
<TableHeaderCell>Budget (USD)</TableHeaderCell>
<TableHeaderCell>TPM / RPM Limits</TableHeaderCell>
<TableHeaderCell>Settings</TableHeaderCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>Wilhelm Tell</TableCell>
<TableCell className="text-right">1</TableCell>
<TableCell>Uri, Schwyz, Unterwalden</TableCell>
<TableCell>National Hero</TableCell>
<TableCell>
<Icon icon={CogIcon} size="sm" />
</TableCell>
</TableRow>
<TableRow>
<TableCell>The Witcher</TableCell>
<TableCell className="text-right">129</TableCell>
<TableCell>Kaedwen</TableCell>
<TableCell>Legend</TableCell>
<TableCell>
<Icon icon={CogIcon} size="sm" />
</TableCell>
</TableRow>
<TableRow>
<TableCell>Mizutsune</TableCell>
<TableCell className="text-right">82</TableCell>
<TableCell>Japan</TableCell>
<TableCell>N/A</TableCell>
<TableCell>
<Icon icon={CogIcon} size="sm" />
</TableCell>
</TableRow>
</TableBody>
</Table>
</Card>
</Col>
<Col numColSpan={1}>
<Link
href={`/team?userID=${searchParams.get(
"userID"
)}&token=${searchParams.get("token")}`}
>
<Button className="mx-auto">+ Create New Team</Button>
</Link>
</Col>
</Grid>
</div>
</div>
</Suspense>
);
};
export default TeamSettingsPage;

View file

@ -20,8 +20,14 @@ interface NavbarProps {
userID: string | null;
userRole: string | null;
userEmail: string | null;
showSSOBanner: boolean;
}
const Navbar: React.FC<NavbarProps> = ({ userID, userRole, userEmail }) => {
const Navbar: React.FC<NavbarProps> = ({
userID,
userRole,
userEmail,
showSSOBanner,
}) => {
console.log("User ID:", userID);
console.log("userEmail:", userEmail);
@ -46,8 +52,20 @@ const Navbar: React.FC<NavbarProps> = ({ userID, userRole, userEmail }) => {
</Link>
</div>
</div>
<div className="text-right mx-4 my-2 absolute top-0 right-0">
<Button variant="secondary">
<div className="text-right mx-4 my-2 absolute top-0 right-0 flex items-center justify-end space-x-2">
{showSSOBanner ? (
<a
href="https://docs.litellm.ai/docs/proxy/ui#setup-ssoauth-for-ui"
target="_blank"
className="mr-2"
>
<Button variant="primary" size="lg">
Enable SSO
</Button>
</a>
) : null}
<Button variant="secondary" size="lg">
{userEmail}
<p>Role: {userRole}</p>
<p>ID: {userID}</p>

View file

@ -95,7 +95,7 @@ const Team: React.FC<TeamProps> = ({
const user_role: Member = {
role: "user",
user_email: formValues.user_email,
user_id: null,
user_id: formValues.user_id,
};
const response: any = await teamMemberAddCall(
accessToken,
@ -313,8 +313,18 @@ const Team: React.FC<TeamProps> = ({
labelAlign="left"
>
<>
<Form.Item label="Email" name="user_email">
<Input />
<Form.Item label="Email" name="user_email" className="mb-4">
<Input
name="user_email"
className="px-3 py-2 border rounded-md w-full"
/>
</Form.Item>
<div className="text-center mb-4">OR</div>
<Form.Item label="User ID" name="user_id" className="mb-4">
<Input
name="user_id"
className="px-3 py-2 border rounded-md w-full"
/>
</Form.Item>
</>
<div style={{ textAlign: "right", marginTop: "10px" }}>

View file

@ -6,9 +6,6 @@ import CreateKey from "./create_key_button";
import ViewKeyTable from "./view_key_table";
import ViewUserSpend from "./view_user_spend";
import DashboardTeam from "./dashboard_default_team";
import EnterProxyUrl from "./enter_proxy_url";
import { message } from "antd";
import Navbar from "./navbar";
import { useSearchParams, useRouter } from "next/navigation";
import { jwtDecode } from "jwt-decode";
@ -83,6 +80,7 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
}
}
// console.log(`selectedTeam: ${Object.entries(selectedTeam)}`);
// Moved useEffect inside the component and used a condition to run fetch only if the params are available
useEffect(() => {
if (token) {
@ -127,6 +125,7 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
setUserSpendData(response["user_info"]);
setData(response["keys"]); // Assuming this is the correct path to your data
setTeams(response["teams"]);
setSelectedTeam(response["teams"] ? response["teams"][0] : null);
sessionStorage.setItem(
"userData" + userID,
JSON.stringify(response["keys"])