diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx
index a7190d49a3b..3e96b84f8fc 100644
--- a/ui/litellm-dashboard/src/components/networking.tsx
+++ b/ui/litellm-dashboard/src/components/networking.tsx
@@ -5740,9 +5740,12 @@ export const uiAuditLogsCall = async (
export const getRemainingUsers = async (
accessToken: string
): Promise<{
- total_users: number;
+ total_users: number | null;
total_users_used: number;
- total_users_remaining: number;
+ total_users_remaining: number | null;
+ total_teams: number | null;
+ total_teams_used: number;
+ total_teams_remaining: number | null;
} | null> => {
try {
const url = proxyBaseUrl
diff --git a/ui/litellm-dashboard/src/components/usage_indicator.tsx b/ui/litellm-dashboard/src/components/usage_indicator.tsx
index dc5be0571d2..093caf85565 100644
--- a/ui/litellm-dashboard/src/components/usage_indicator.tsx
+++ b/ui/litellm-dashboard/src/components/usage_indicator.tsx
@@ -1,6 +1,6 @@
import { useState, useEffect } from "react"
import { Badge } from "@tremor/react"
-import { AlertTriangle, Users, TrendingUp, Loader2, ChevronDown, ChevronUp, Minus } from "lucide-react"
+import { AlertTriangle, Users, TrendingUp, Loader2, ChevronDown, ChevronUp, Minus, UserCheck } from "lucide-react"
import { getRemainingUsers } from "./networking"
// Simple utility function to combine class names
@@ -17,6 +17,9 @@ interface UsageData {
total_users: number | null
total_users_used: number
total_users_remaining: number | null
+ total_teams: number | null
+ total_teams_used: number
+ total_teams_remaining: number | null
}
export default function UsageIndicator({accessToken, width = 220}: UsageIndicatorProps) {
@@ -54,18 +57,53 @@ export default function UsageIndicator({accessToken, width = 220}: UsageIndicato
return {
isOverLimit: false,
isNearLimit: false,
- usagePercentage: 0
+ usagePercentage: 0,
+ userMetrics: {
+ isOverLimit: false,
+ isNearLimit: false,
+ usagePercentage: 0
+ },
+ teamMetrics: {
+ isOverLimit: false,
+ isNearLimit: false,
+ usagePercentage: 0
+ }
}
}
- const isOverLimit = data.total_users_remaining ? data.total_users_remaining <= 0 : false
- const isNearLimit = data.total_users_remaining ? data.total_users_remaining <= 5 && data.total_users_remaining > 0 : false
- const usagePercentage = data.total_users ? (data.total_users_used / data.total_users) * 100 : 0
+ // User metrics
+ const userIsOverLimit = data.total_users_remaining ? data.total_users_remaining <= 0 : false
+ const userIsNearLimit = data.total_users_remaining ? data.total_users_remaining <= 5 && data.total_users_remaining > 0 : false
+ const userUsagePercentage = data.total_users ? (data.total_users_used / data.total_users) * 100 : 0
- return { isOverLimit, isNearLimit, usagePercentage }
+ // Team metrics
+ const teamIsOverLimit = data.total_teams_remaining ? data.total_teams_remaining <= 0 : false
+ const teamIsNearLimit = data.total_teams_remaining ? data.total_teams_remaining <= 5 && data.total_teams_remaining > 0 : false
+ const teamUsagePercentage = data.total_teams ? (data.total_teams_used / data.total_teams) * 100 : 0
+
+ // Combined status (worst case scenario)
+ const isOverLimit = userIsOverLimit || teamIsOverLimit
+ const isNearLimit = (userIsNearLimit || teamIsNearLimit) && !isOverLimit
+ const usagePercentage = Math.max(userUsagePercentage, teamUsagePercentage)
+
+ return {
+ isOverLimit,
+ isNearLimit,
+ usagePercentage,
+ userMetrics: {
+ isOverLimit: userIsOverLimit,
+ isNearLimit: userIsNearLimit,
+ usagePercentage: userUsagePercentage
+ },
+ teamMetrics: {
+ isOverLimit: teamIsOverLimit,
+ isNearLimit: teamIsNearLimit,
+ usagePercentage: teamUsagePercentage
+ }
+ }
}
- const { isOverLimit, isNearLimit, usagePercentage } = getUsageMetrics(data)
+ const { isOverLimit, isNearLimit, usagePercentage, userMetrics, teamMetrics } = getUsageMetrics(data)
const getStatusColor = () => {
if (isOverLimit) return "red"
@@ -105,7 +143,17 @@ export default function UsageIndicator({accessToken, width = 220}: UsageIndicato
>