|
"use client"; |
|
import React, { useEffect, useState } from "react"; |
|
import { keyDeleteCall, getTotalSpendCall } from "./networking"; |
|
import { StatusOnlineIcon, TrashIcon } from "@heroicons/react/outline"; |
|
import { Accordion, AccordionHeader, AccordionList, DonutChart } from "@tremor/react"; |
|
import { |
|
Badge, |
|
Card, |
|
Table, |
|
Metric, |
|
TableBody, |
|
TableCell, |
|
TableHead, |
|
TableHeaderCell, |
|
TableRow, |
|
Text, |
|
Title, |
|
Icon, |
|
AccordionBody, |
|
List, |
|
ListItem, |
|
|
|
} from "@tremor/react"; |
|
import { Statistic } from "antd" |
|
import { spendUsersCall, modelAvailableCall } from "./networking"; |
|
const isLocal = process.env.NODE_ENV === "development"; |
|
const proxyBaseUrl = isLocal ? "http://localhost:4000" : null; |
|
if (isLocal != true) { |
|
console.log = function() {}; |
|
} |
|
|
|
|
|
interface UserSpendData { |
|
spend: number; |
|
max_budget?: number | null; |
|
|
|
} |
|
interface ViewUserSpendProps { |
|
userID: string | null; |
|
userRole: string | null; |
|
accessToken: string | null; |
|
userSpend: number | null; |
|
userMaxBudget: number | null; |
|
selectedTeam: any | null; |
|
} |
|
const ViewUserSpend: React.FC<ViewUserSpendProps> = ({ userID, userRole, accessToken, userSpend, userMaxBudget, selectedTeam }) => { |
|
console.log(`userSpend: ${userSpend}`) |
|
let [spend, setSpend] = useState(userSpend !== null ? userSpend : 0.0); |
|
const [maxBudget, setMaxBudget] = useState(selectedTeam ? selectedTeam.max_budget : null); |
|
useEffect(() => { |
|
if (selectedTeam) { |
|
if (selectedTeam.team_alias === "Default Team") { |
|
setMaxBudget(userMaxBudget); |
|
} else { |
|
let setMaxBudgetFlag = false; |
|
if (selectedTeam.team_memberships) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const member of selectedTeam.team_memberships) { |
|
if (member.user_id === userID && "max_budget" in member.litellm_budget_table && member.litellm_budget_table.max_budget !== null) { |
|
setMaxBudget(member.litellm_budget_table.max_budget); |
|
setMaxBudgetFlag = true; |
|
} |
|
} |
|
} |
|
if (!setMaxBudgetFlag) { |
|
setMaxBudget(selectedTeam.max_budget); |
|
} |
|
} |
|
} |
|
}, [selectedTeam, userMaxBudget]); |
|
const [userModels, setUserModels] = useState([]); |
|
useEffect(() => { |
|
const fetchData = async () => { |
|
if (!accessToken || !userID || !userRole) { |
|
return; |
|
} |
|
}; |
|
const fetchUserModels = async () => { |
|
try { |
|
if (userID === null || userRole === null) { |
|
return; |
|
} |
|
|
|
if (accessToken !== null) { |
|
const model_available = await modelAvailableCall(accessToken, userID, userRole); |
|
let available_model_names = model_available["data"].map( |
|
(element: { id: string }) => element.id |
|
); |
|
console.log("available_model_names:", available_model_names); |
|
setUserModels(available_model_names); |
|
} |
|
} catch (error) { |
|
console.error("Error fetching user models:", error); |
|
} |
|
}; |
|
|
|
fetchUserModels(); |
|
fetchData(); |
|
}, [userRole, accessToken, userID]); |
|
|
|
useEffect(() => { |
|
if (userSpend !== null) { |
|
setSpend(userSpend) |
|
} |
|
}, [userSpend]) |
|
|
|
|
|
let modelsToDisplay = []; |
|
if (selectedTeam && selectedTeam.models) { |
|
modelsToDisplay = selectedTeam.models; |
|
} |
|
|
|
|
|
if (modelsToDisplay && modelsToDisplay.includes("all-proxy-models")) { |
|
console.log("user models:", userModels); |
|
modelsToDisplay = userModels; |
|
} else if (modelsToDisplay && modelsToDisplay.includes("all-team-models")) { |
|
modelsToDisplay = selectedTeam.models; |
|
} else if (modelsToDisplay && modelsToDisplay.length === 0) { |
|
modelsToDisplay = userModels; |
|
} |
|
|
|
|
|
const displayMaxBudget = maxBudget !== null ? `$${maxBudget} limit` : "No limit"; |
|
|
|
const roundedSpend = spend !== undefined ? spend.toFixed(4) : null; |
|
|
|
console.log(`spend in view user spend: ${spend}`) |
|
return ( |
|
<div className="flex items-center"> |
|
<div className="flex justify-between gap-x-6"> |
|
<div> |
|
<p className="text-tremor-default text-tremor-content dark:text-dark-tremor-content"> |
|
Total Spend |
|
</p> |
|
<p className="text-2xl text-tremor-content-strong dark:text-dark-tremor-content-strong font-semibold"> |
|
${roundedSpend} |
|
</p> |
|
</div> |
|
<div> |
|
<p className="text-tremor-default text-tremor-content dark:text-dark-tremor-content"> |
|
Max Budget |
|
</p> |
|
<p className="text-2xl text-tremor-content-strong dark:text-dark-tremor-content-strong font-semibold"> |
|
{displayMaxBudget} |
|
</p> |
|
</div> |
|
</div> |
|
{/* <div className="ml-auto"> |
|
<Accordion> |
|
<AccordionHeader><Text>Team Models</Text></AccordionHeader> |
|
<AccordionBody className="absolute right-0 z-10 bg-white p-2 shadow-lg max-w-xs"> |
|
<List> |
|
{modelsToDisplay.map((model: string) => ( |
|
<ListItem key={model}> |
|
<Text>{model}</Text> |
|
</ListItem> |
|
))} |
|
</List> |
|
</AccordionBody> |
|
</Accordion> |
|
</div> */} |
|
</div> |
|
); |
|
} |
|
|
|
export default ViewUserSpend; |
|
|
|
|