import React, { useState, useEffect } from "react"; import { Card, Title, Text, TextInput, Tab, TabList, TabGroup, TabPanel, TabPanels, Grid, Badge, Table, TableHead, TableRow, TableHeaderCell, TableBody, TableCell, Button as TremorButton, Icon } from "@tremor/react"; import NumericalInput from "../shared/numerical_input"; import { Button, Form, Input, Select, message, Tooltip } from "antd"; import { InfoCircleOutlined } from '@ant-design/icons'; import { PencilAltIcon, TrashIcon } from "@heroicons/react/outline"; import { getModelDisplayName } from "../key_team_helpers/fetch_available_models_team_key"; import { Member, Organization, organizationInfoCall, organizationMemberAddCall, organizationMemberUpdateCall, organizationMemberDeleteCall, organizationUpdateCall } from "../networking"; import UserSearchModal from "../common_components/user_search_modal"; import MemberModal from "../team/edit_membership"; interface OrganizationInfoProps { organizationId: string; onClose: () => void; accessToken: string | null; is_org_admin: boolean; is_proxy_admin: boolean; userModels: string[]; editOrg: boolean; } const OrganizationInfoView: React.FC = ({ organizationId, onClose, accessToken, is_org_admin, is_proxy_admin, userModels, editOrg }) => { const [orgData, setOrgData] = useState(null); const [loading, setLoading] = useState(true); const [form] = Form.useForm(); const [isEditing, setIsEditing] = useState(false); const [isAddMemberModalVisible, setIsAddMemberModalVisible] = useState(false); const [isEditMemberModalVisible, setIsEditMemberModalVisible] = useState(false); const [selectedEditMember, setSelectedEditMember] = useState(null); const canEditOrg = is_org_admin || is_proxy_admin; const fetchOrgInfo = async () => { try { setLoading(true); if (!accessToken) return; const response = await organizationInfoCall(accessToken, organizationId); setOrgData(response); } catch (error) { message.error("Failed to load organization information"); console.error("Error fetching organization info:", error); } finally { setLoading(false); } }; useEffect(() => { fetchOrgInfo(); }, [organizationId, accessToken]); const handleMemberAdd = async (values: any) => { try { if (accessToken == null) { return; } const member: Member = { user_email: values.user_email, user_id: values.user_id, role: values.role, } const response = await organizationMemberAddCall(accessToken, organizationId, member); message.success("Organization member added successfully"); setIsAddMemberModalVisible(false); form.resetFields(); fetchOrgInfo(); } catch (error) { message.error("Failed to add organization member"); console.error("Error adding organization member:", error); } }; const handleMemberUpdate = async (values: any) => { try { if (!accessToken) return; const member: Member = { user_email: values.user_email, user_id: values.user_id, role: values.role, } const response = await organizationMemberUpdateCall(accessToken, organizationId, member); message.success("Organization member updated successfully"); setIsEditMemberModalVisible(false); form.resetFields(); fetchOrgInfo(); } catch (error) { message.error("Failed to update organization member"); console.error("Error updating organization member:", error); } }; const handleMemberDelete = async (values: any) => { try { if (!accessToken) return; await organizationMemberDeleteCall(accessToken, organizationId, values.user_id); message.success("Organization member deleted successfully"); setIsEditMemberModalVisible(false); form.resetFields(); fetchOrgInfo(); } catch (error) { message.error("Failed to delete organization member"); console.error("Error deleting organization member:", error); } }; const handleOrgUpdate = async (values: any) => { try { if (!accessToken) return; const updateData = { organization_id: organizationId, organization_alias: values.organization_alias, models: values.models, litellm_budget_table: { tpm_limit: values.tpm_limit, rpm_limit: values.rpm_limit, max_budget: values.max_budget, budget_duration: values.budget_duration, }, metadata: values.metadata ? JSON.parse(values.metadata) : null, }; const response = await organizationUpdateCall(accessToken, updateData); message.success("Organization settings updated successfully"); setIsEditing(false); fetchOrgInfo(); } catch (error) { message.error("Failed to update organization settings"); console.error("Error updating organization:", error); } }; if (loading) { return
Loading...
; } if (!orgData) { return
Organization not found
; } return (
{orgData.organization_alias} {orgData.organization_id}
Overview Members Settings {/* Overview Panel */} Organization Details
Created: {new Date(orgData.created_at).toLocaleDateString()} Updated: {new Date(orgData.updated_at).toLocaleDateString()} Created By: {orgData.created_by}
Budget Status
${orgData.spend.toFixed(6)} of {orgData.litellm_budget_table.max_budget === null ? "Unlimited" : `$${orgData.litellm_budget_table.max_budget}`} {orgData.litellm_budget_table.budget_duration && ( Reset: {orgData.litellm_budget_table.budget_duration} )}
Rate Limits
TPM: {orgData.litellm_budget_table.tpm_limit || 'Unlimited'} RPM: {orgData.litellm_budget_table.rpm_limit || 'Unlimited'} {orgData.litellm_budget_table.max_parallel_requests && ( Max Parallel Requests: {orgData.litellm_budget_table.max_parallel_requests} )}
Models
{orgData.models.map((model, index) => ( {model} ))}
{/* Budget Panel */}
User ID Role Spend Created At {orgData.members?.map((member, index) => ( {member.user_id} {member.user_role} ${member.spend.toFixed(6)} {new Date(member.created_at).toLocaleString()} {canEditOrg && ( <> { setSelectedEditMember({ "role": member.user_role, "user_email": member.user_email, "user_id": member.user_id }); setIsEditMemberModalVisible(true); }} /> { handleMemberDelete(member); }} /> )} ))}
{canEditOrg && ( { setIsAddMemberModalVisible(true); }}> Add Member )}
{/* Settings Panel */}
Organization Settings {(canEditOrg && !isEditing) && ( setIsEditing(true)} > Edit Settings )}
{isEditing ? (
Save Changes
) : (
Organization Name
{orgData.organization_alias}
Organization ID
{orgData.organization_id}
Created At
{new Date(orgData.created_at).toLocaleString()}
Models
{orgData.models.map((model, index) => ( {model} ))}
Rate Limits
TPM: {orgData.litellm_budget_table.tpm_limit || 'Unlimited'}
RPM: {orgData.litellm_budget_table.rpm_limit || 'Unlimited'}
Budget
Max: {orgData.litellm_budget_table.max_budget !== null ? `$${orgData.litellm_budget_table.max_budget}` : 'No Limit'}
Reset: {orgData.litellm_budget_table.budget_duration || 'Never'}
)}
setIsAddMemberModalVisible(false)} onSubmit={handleMemberAdd} accessToken={accessToken} title="Add Organization Member" roles={[ { label: "org_admin", value: "org_admin", description: "Can add and remove members, and change their roles." }, { label: "internal_user", value: "internal_user", description: "Can view/create keys for themselves within organization." }, { label: "internal_user_viewer", value: "internal_user_viewer", description: "Can only view their keys within organization." } ]} defaultRole="internal_user" /> setIsEditMemberModalVisible(false)} onSubmit={handleMemberUpdate} initialData={selectedEditMember} mode="edit" config={{ title: "Edit Member", showEmail: true, showUserId: true, roleOptions: [ { label: "Org Admin", value: "org_admin" }, { label: "Internal User", value: "internal_user" }, { label: "Internal User Viewer", value: "internal_user_viewer" } ] }} />
); }; export default OrganizationInfoView;