forked from phoenix/litellm-mirror
213 lines
6.9 KiB
TypeScript
213 lines
6.9 KiB
TypeScript
import React, { useState, useEffect } from "react";
|
||
import {
|
||
Card,
|
||
Title,
|
||
Subtitle,
|
||
Table,
|
||
TableHead,
|
||
TableHeaderCell,
|
||
TableRow,
|
||
TableCell,
|
||
TableBody,
|
||
Tab,
|
||
Text,
|
||
TabGroup,
|
||
TabList,
|
||
TabPanels,
|
||
Metric,
|
||
Grid,
|
||
TabPanel,
|
||
Select,
|
||
SelectItem,
|
||
} from "@tremor/react";
|
||
import { userInfoCall, adminTopEndUsersCall } from "./networking";
|
||
import { Badge, BadgeDelta, Button } from "@tremor/react";
|
||
import RequestAccess from "./request_model_access";
|
||
import CreateUser from "./create_user_button";
|
||
import Paragraph from "antd/es/skeleton/Paragraph";
|
||
|
||
interface ViewUserDashboardProps {
|
||
accessToken: string | null;
|
||
token: string | null;
|
||
userRole: string | null;
|
||
userID: string | null;
|
||
}
|
||
|
||
const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
|
||
accessToken,
|
||
token,
|
||
userRole,
|
||
userID,
|
||
}) => {
|
||
const [userData, setUserData] = useState<null | any[]>(null);
|
||
const [endUsers, setEndUsers] = useState<null | any[]>(null);
|
||
const [currentPage, setCurrentPage] = useState(1);
|
||
const defaultPageSize = 25;
|
||
|
||
useEffect(() => {
|
||
if (!accessToken || !token || !userRole || !userID) {
|
||
return;
|
||
}
|
||
const fetchData = async () => {
|
||
try {
|
||
// Replace with your actual API call for model data
|
||
const userDataResponse = await userInfoCall(
|
||
accessToken,
|
||
null,
|
||
userRole,
|
||
true
|
||
);
|
||
console.log("user data response:", userDataResponse);
|
||
setUserData(userDataResponse);
|
||
} catch (error) {
|
||
console.error("There was an error fetching the model data", error);
|
||
}
|
||
};
|
||
|
||
if (accessToken && token && userRole && userID && !userData) {
|
||
fetchData();
|
||
}
|
||
|
||
const fetchEndUserSpend = async () => {
|
||
try {
|
||
const topEndUsers = await adminTopEndUsersCall(accessToken);
|
||
console.log("user data response:", topEndUsers);
|
||
setEndUsers(topEndUsers);
|
||
} catch (error) {
|
||
console.error("There was an error fetching the model data", error);
|
||
}
|
||
};
|
||
if (
|
||
userRole &&
|
||
(userRole == "Admin" || userRole == "Admin Viewer") &&
|
||
!endUsers
|
||
) {
|
||
fetchEndUserSpend();
|
||
}
|
||
}, [accessToken, token, userRole, userID]);
|
||
|
||
if (!userData) {
|
||
return <div>Loading...</div>;
|
||
}
|
||
|
||
if (!accessToken || !token || !userRole || !userID) {
|
||
return <div>Loading...</div>;
|
||
}
|
||
|
||
function renderPagination() {
|
||
if (!userData) return null;
|
||
|
||
const totalPages = Math.ceil(userData.length / defaultPageSize);
|
||
const startItem = (currentPage - 1) * defaultPageSize + 1;
|
||
const endItem = Math.min(currentPage * defaultPageSize, userData.length);
|
||
|
||
return (
|
||
<div className="flex justify-between items-center">
|
||
<div>
|
||
Showing {startItem} – {endItem} of {userData.length}
|
||
</div>
|
||
<div className="flex">
|
||
<button
|
||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-l focus:outline-none"
|
||
disabled={currentPage === 1}
|
||
onClick={() => setCurrentPage(currentPage - 1)}
|
||
>
|
||
← Prev
|
||
</button>
|
||
<button
|
||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-r focus:outline-none"
|
||
disabled={currentPage === totalPages}
|
||
onClick={() => setCurrentPage(currentPage + 1)}
|
||
>
|
||
Next →
|
||
</button>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div style={{ width: "100%" }}>
|
||
<Grid className="gap-2 p-10 h-[75vh] w-full">
|
||
<CreateUser userID={userID} accessToken={accessToken} />
|
||
<Card className="w-full mx-auto flex-auto overflow-y-auto max-h-[50vh] mb-4">
|
||
<TabGroup>
|
||
<TabList variant="line" defaultValue="1">
|
||
<Tab value="1">Key Owners</Tab>
|
||
<Tab value="2">End-Users</Tab>
|
||
</TabList>
|
||
<TabPanels>
|
||
<TabPanel>
|
||
<Table className="mt-5">
|
||
<TableHead>
|
||
<TableRow>
|
||
<TableHeaderCell>User ID</TableHeaderCell>
|
||
<TableHeaderCell>User Role</TableHeaderCell>
|
||
<TableHeaderCell>User Models</TableHeaderCell>
|
||
<TableHeaderCell>User Spend ($ USD)</TableHeaderCell>
|
||
<TableHeaderCell>User Max Budget ($ USD)</TableHeaderCell>
|
||
</TableRow>
|
||
</TableHead>
|
||
<TableBody>
|
||
{userData.map((user: any) => (
|
||
<TableRow key={user.user_id}>
|
||
<TableCell>{user.user_id}</TableCell>
|
||
<TableCell>
|
||
{user.user_role ? user.user_role : "app_owner"}
|
||
</TableCell>
|
||
<TableCell>
|
||
{user.models && user.models.length > 0
|
||
? user.models
|
||
: "All Models"}
|
||
</TableCell>
|
||
<TableCell>{user.spend ? user.spend : 0}</TableCell>
|
||
<TableCell>
|
||
{user.max_budget ? user.max_budget : "Unlimited"}
|
||
</TableCell>
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</TabPanel>
|
||
<TabPanel>
|
||
<div className="flex items-center">
|
||
<div className="flex-1"></div>
|
||
<div className="flex-1 flex justify-between items-center">
|
||
<Text className="w-1/4 mr-2 text-right">Key</Text>
|
||
<Select defaultValue="1" className="w-3/4">
|
||
<SelectItem value="1">Option One</SelectItem>
|
||
<SelectItem value="2">Option Two</SelectItem>
|
||
<SelectItem value="3">Option Three</SelectItem>
|
||
</Select>
|
||
</div>
|
||
</div>
|
||
<Table>
|
||
<TableHead>
|
||
<TableRow>
|
||
<TableHeaderCell>End User</TableHeaderCell>
|
||
<TableHeaderCell>Spend</TableHeaderCell>
|
||
<TableHeaderCell>Total Events</TableHeaderCell>
|
||
</TableRow>
|
||
</TableHead>
|
||
|
||
<TableBody>
|
||
{endUsers?.map((user: any, index: number) => (
|
||
<TableRow key={index}>
|
||
<TableCell>{user.end_user}</TableCell>
|
||
<TableCell>{user.total_spend}</TableCell>
|
||
<TableCell>{user.total_events}</TableCell>
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</TabPanel>
|
||
</TabPanels>
|
||
</TabGroup>
|
||
</Card>
|
||
{renderPagination()}
|
||
</Grid>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default ViewUserDashboard;
|