import React, { useState, useEffect } from "react"; import Link from "next/link"; import { Typography } from "antd"; import { teamDeleteCall, teamUpdateCall, teamInfoCall } from "./networking"; import TeamMemberModal from "@/components/team/edit_membership"; import { InformationCircleIcon, PencilAltIcon, PencilIcon, RefreshIcon, StatusOnlineIcon, TrashIcon, } from "@heroicons/react/outline"; import { Button as Button2, Modal, Form, Input, Select as Select2, InputNumber, message, Tooltip } from "antd"; import { fetchAvailableModelsForTeamOrKey, getModelDisplayName } from "./key_team_helpers/fetch_available_models_team_key"; import { Select, SelectItem } from "@tremor/react"; import { InfoCircleOutlined } from '@ant-design/icons'; import { getGuardrailsList } from "./networking"; import TeamInfoView from "@/components/team/team_info"; import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow, TextInput, Card, Icon, Button, Badge, Col, Text, Grid, Accordion, AccordionHeader, AccordionBody, TabGroup, TabList, TabPanel, TabPanels, Tab } from "@tremor/react"; import { CogIcon } from "@heroicons/react/outline"; import AvailableTeamsPanel from "@/components/team/available_teams"; const isLocal = process.env.NODE_ENV === "development"; const proxyBaseUrl = isLocal ? "http://localhost:4000" : null; if (isLocal != true) { console.log = function() {}; } interface TeamProps { teams: any[] | null; searchParams: any; accessToken: string | null; setTeams: React.Dispatch>; userID: string | null; userRole: string | null; } interface EditTeamModalProps { visible: boolean; onCancel: () => void; team: any; // Assuming TeamType is a type representing your team object onSubmit: (data: FormData) => void; // Assuming FormData is the type of data to be submitted } import { teamCreateCall, teamMemberAddCall, teamMemberUpdateCall, Member, modelAvailableCall, teamListCall } from "./networking"; const Team: React.FC = ({ teams, searchParams, accessToken, setTeams, userID, userRole, }) => { const [lastRefreshed, setLastRefreshed] = useState(""); const fetchTeams = async (accessToken: string, userID: string | null, userRole: string | null) => { let givenTeams; if (userRole != "Admin" && userRole != "Admin Viewer") { givenTeams = await teamListCall(accessToken, userID) } else { givenTeams = await teamListCall(accessToken) } console.log(`givenTeams: ${givenTeams}`) setTeams(givenTeams) } useEffect(() => { console.log(`inside useeffect - ${teams}`) if (teams === null && accessToken) { // Call your function here fetchTeams(accessToken, userID, userRole) } }, [teams]); useEffect(() => { console.log(`inside useeffect - ${lastRefreshed}`) if (accessToken) { // Call your function here fetchTeams(accessToken, userID, userRole) } handleRefreshClick() }, [lastRefreshed]); const [form] = Form.useForm(); const [memberForm] = Form.useForm(); const { Title, Paragraph } = Typography; const [value, setValue] = useState(""); const [editModalVisible, setEditModalVisible] = useState(false); const [selectedTeam, setSelectedTeam] = useState( null ); const [selectedTeamId, setSelectedTeamId] = useState(null); const [isTeamModalVisible, setIsTeamModalVisible] = useState(false); const [isAddMemberModalVisible, setIsAddMemberModalVisible] = useState(false); const [isEditMemberModalVisible, setIsEditMemberModalVisible] = useState(false); const [userModels, setUserModels] = useState([]); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [teamToDelete, setTeamToDelete] = useState(null); const [perTeamInfo, setPerTeamInfo] = useState>({}); // Add this state near the other useState declarations const [guardrailsList, setGuardrailsList] = useState([]); // Add this useEffect to fetch guardrails useEffect(() => { const fetchGuardrails = async () => { try { if (accessToken == null) { return; } const response = await getGuardrailsList(accessToken); const guardrailNames = response.guardrails.map( (g: { guardrail_name: string }) => g.guardrail_name ); setGuardrailsList(guardrailNames); } catch (error) { console.error("Failed to fetch guardrails:", error); } }; fetchGuardrails(); }, [accessToken]); const EditTeamModal: React.FC = ({ visible, onCancel, team, onSubmit, }) => { const [form] = Form.useForm(); // Extract existing guardrails from team metadata let existingGuardrails: string[] = []; try { existingGuardrails = team.metadata?.guardrails || []; } catch (error) { console.error("Error extracting guardrails:", error); } const handleOk = () => { form .validateFields() .then((values) => { const updatedValues = { ...values, team_id: team.team_id }; onSubmit(updatedValues); form.resetFields(); }) .catch((error) => { console.error("Validation failed:", error); }); }; return (
<> {"All Proxy Models"} {userModels && userModels.map((model) => ( {getModelDisplayName(model)} ))} daily weekly monthly Guardrails{' '} e.stopPropagation()} > } name="guardrails" className="mt-8" help="Select existing guardrails or enter new ones" > ({ value: name, label: name }))} />
Save
); }; const handleEditClick = (team: any) => { setSelectedTeam(team); setEditModalVisible(true); }; const handleEditCancel = () => { setEditModalVisible(false); setSelectedTeam(null); }; const handleEditSubmit = async (formValues: Record) => { // Call API to update team with teamId and values const teamId = formValues.team_id; // get team_id console.log("handleEditSubmit:", formValues); if (accessToken == null) { return; } // Create metadata object with guardrails if they exist formValues.metadata = { ...(formValues.metadata || {}), ...(formValues.guardrails ? { guardrails: formValues.guardrails } : {}) }; // Remove guardrails from top level since it's now in metadata delete formValues.guardrails; let newTeamValues = await teamUpdateCall(accessToken, formValues); // Update the teams state with the updated team data if (teams) { const updatedTeams = teams.map((team) => team.team_id === teamId ? newTeamValues.data : team ); setTeams(updatedTeams); } message.success("Team updated successfully"); setEditModalVisible(false); setSelectedTeam(null); }; const handleOk = () => { setIsTeamModalVisible(false); form.resetFields(); }; const handleMemberOk = () => { setIsAddMemberModalVisible(false); setIsEditMemberModalVisible(false); memberForm.resetFields(); }; const handleCancel = () => { setIsTeamModalVisible(false); form.resetFields(); }; const handleMemberCancel = () => { setIsAddMemberModalVisible(false); setIsEditMemberModalVisible(false); memberForm.resetFields(); }; const handleDelete = async (team_id: string) => { // Set the team to delete and open the confirmation modal setTeamToDelete(team_id); setIsDeleteModalOpen(true); }; const confirmDelete = async () => { if (teamToDelete == null || teams == null || accessToken == null) { return; } try { await teamDeleteCall(accessToken, teamToDelete); // Successfully completed the deletion. Update the state to trigger a rerender. const filteredData = teams.filter( (item) => item.team_id !== teamToDelete ); setTeams(filteredData); } catch (error) { console.error("Error deleting the team:", error); // Handle any error situations, such as displaying an error message to the user. } // Close the confirmation modal and reset the teamToDelete setIsDeleteModalOpen(false); setTeamToDelete(null); }; const cancelDelete = () => { // Close the confirmation modal and reset the teamToDelete setIsDeleteModalOpen(false); setTeamToDelete(null); }; useEffect(() => { const fetchUserModels = async () => { try { if (userID === null || userRole === null || accessToken === null) { return; } const models = await fetchAvailableModelsForTeamOrKey(userID, userRole, accessToken); if (models) { setUserModels(models); } } catch (error) { console.error("Error fetching user models:", error); } }; const fetchTeamInfo = async () => { try { if (userID === null || userRole === null || accessToken === null) { return; } if (teams === null) { return; } let _team_id_to_info: Record = {}; let teamList; if (userRole != "Admin" && userRole != "Admin Viewer") { teamList = await teamListCall(accessToken, userID) } else { teamList = await teamListCall(accessToken) } for (let i = 0; i < teamList.length; i++) { let team = teamList[i]; let _team_id = team.team_id; // Use the team info directly from the teamList if (team !== null) { _team_id_to_info = { ..._team_id_to_info, [_team_id]: team }; } } setPerTeamInfo(_team_id_to_info); } catch (error) { console.error("Error fetching team info:", error); } }; fetchUserModels(); fetchTeamInfo(); }, [accessToken, userID, userRole, teams]); const handleCreate = async (formValues: Record) => { try { console.log(`formValues: ${JSON.stringify(formValues)}`); if (accessToken != null) { const newTeamAlias = formValues?.team_alias; const existingTeamAliases = teams?.map((t) => t.team_alias) ?? []; let organizationId = formValues?.organization_id; if (organizationId === "" || typeof organizationId !== 'string') { formValues.organization_id = null; } else { formValues.organization_id = organizationId.trim(); } // Create metadata object with guardrails if they exist formValues.metadata = { ...(formValues.guardrails ? { guardrails: formValues.guardrails } : {}) }; // Remove guardrails from top level since it's now in metadata delete formValues.guardrails; if (existingTeamAliases.includes(newTeamAlias)) { throw new Error( `Team alias ${newTeamAlias} already exists, please pick another alias` ); } message.info("Creating Team"); const response: any = await teamCreateCall(accessToken, formValues); if (teams !== null) { setTeams([...teams, response]); } else { setTeams([response]); } console.log(`response for team create call: ${response}`); message.success("Team created"); setIsTeamModalVisible(false); } } catch (error) { console.error("Error creating the team:", error); message.error("Error creating the team: " + error, 20); } }; const is_team_admin = (team: any) => { if (team == null || team.members_with_roles == null) { return false; } for (let i = 0; i < team.members_with_roles.length; i++) { let member = team.members_with_roles[i]; if (member.user_id == userID && member.role == "admin") { return true; } } return false; } const handleRefreshClick = () => { // Update the 'lastRefreshed' state to the current date and time const currentDate = new Date(); setLastRefreshed(currentDate.toLocaleString()); }; return (
{selectedTeamId ? ( setSelectedTeamId(null)} accessToken={accessToken} is_team_admin={is_team_admin(teams?.find((team) => team.team_id === selectedTeamId))} is_proxy_admin={userRole == "Admin"} /> ) : (
Your Teams Available Teams
{lastRefreshed && Last Refreshed: {lastRefreshed}}
Click on “Team ID” to view team details and manage team members. Team Name Team ID Created Spend (USD) Budget (USD) Models TPM / RPM Limits Info {teams && teams.length > 0 ? teams .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()) .map((team: any) => ( {team["team_alias"]}
{team.created_at ? new Date(team.created_at).toLocaleDateString() : "N/A"} {team["spend"]} {team["max_budget"] !== null && team["max_budget"] !== undefined ? team["max_budget"] : "No limit"} {Array.isArray(team.models) ? (
{team.models.length === 0 ? ( All Proxy Models ) : ( team.models.map( (model: string, index: number) => model === "all-proxy-models" ? ( All Proxy Models ) : ( {model.length > 30 ? `${getModelDisplayName(model).slice(0, 30)}...` : getModelDisplayName(model)} ) ) )}
) : null}
TPM: {team.tpm_limit ? team.tpm_limit : "Unlimited"}{" "}

RPM:{" "} {team.rpm_limit ? team.rpm_limit : "Unlimited"}
{perTeamInfo && team.team_id && perTeamInfo[team.team_id] && perTeamInfo[team.team_id].keys && perTeamInfo[team.team_id].keys.length}{" "} Keys {perTeamInfo && team.team_id && perTeamInfo[team.team_id] && perTeamInfo[team.team_id].members_with_roles && perTeamInfo[team.team_id].members_with_roles.length}{" "} Members {userRole == "Admin" ? ( <> handleEditClick(team)} /> handleDelete(team.team_id)} icon={TrashIcon} size="sm" /> ) : null}
)) : null}
{isDeleteModalOpen && (
{/* Modal Panel */} {/* Confirmation Modal Content */}

Delete Team

Are you sure you want to delete this team ?

)}
{userRole == "Admin"? (
<> All Proxy Models {userModels.map((model) => ( {getModelDisplayName(model)} ))} daily weekly monthly Additional Settings { e.target.value = e.target.value.trim(); }} /> { e.target.value = e.target.value.trim(); }} /> Guardrails{' '} e.stopPropagation()} > } name="guardrails" className="mt-8" help="Select existing guardrails or enter new ones" > ({ value: name, label: name }))} />
Create Team
) : null}
)}
); }; export default Team;