import { Badge } from "@/components/ui/badge";
import { CardHeader, CardTitle } from "@/components/ui/card";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { resetDurationLabels } from "@/lib/constants/governance";
import { useGetProviderGovernanceQuery } from "@/lib/store";
import { ModelProvider } from "@/lib/types/config";
import { cn } from "@/lib/utils";
import { formatCurrency } from "@/lib/utils/governance";
import { RbacOperation, RbacResource, useRbac } from "@enterprise/lib";
interface Props {
className?: string;
provider: ModelProvider;
}
// Helper to format reset duration for display
const formatResetDuration = (duration: string) => {
return resetDurationLabels[duration] || duration;
};
// Circular progress component
function CircularProgress({
value,
max,
size = 80,
strokeWidth = 6,
isExhausted = false,
}: {
value: number;
max: number;
size?: number;
strokeWidth?: number;
isExhausted?: boolean;
}) {
const percentage = max > 0 ? Math.min((value / max) * 100, 100) : 0;
const radius = (size - strokeWidth) / 2;
const circumference = radius * 2 * Math.PI;
const strokeDashoffset = circumference - (percentage / 100) * circumference;
return (
80 ? "text-amber-500/70" : "text-foreground")}
>
{Math.round(percentage)}%
);
}
// Metric card component
function MetricCard({
title,
value,
max,
unit,
resetDuration,
isExhausted,
}: {
title: string;
value: number;
max: number;
unit: string;
resetDuration: string;
isExhausted: boolean;
}) {
// Compute safe percentage to avoid division by zero
const percentage = max > 0 ? Math.round((value / max) * 100) : 0;
const clampedPercentage = Math.max(0, Math.min(100, percentage));
return (
{/* Subtle gradient overlay */}
{title}
{isExhausted && (
Exhausted
)}
{unit === "$" ? formatCurrency(value) : value.toLocaleString()}
/ {unit === "$" ? formatCurrency(max) : `${max.toLocaleString()} ${unit}`}
Resets {formatResetDuration(resetDuration)}
{clampedPercentage}% of {title.toLowerCase()} used
);
}
export default function ProviderGovernanceTable({ provider, className }: Props) {
const hasViewAccess = useRbac(RbacResource.Governance, RbacOperation.View);
const { data: providerGovernanceData, isLoading } = useGetProviderGovernanceQuery(undefined, {
skip: !hasViewAccess,
pollingInterval: 5000,
});
// Find governance data for this provider
const providerGovernance = providerGovernanceData?.providers?.find((p) => p.provider === provider.name);
// Check if any governance is configured
const hasGovernance = providerGovernance?.budget || providerGovernance?.rate_limit;
if (isLoading) {
return (
);
}
// Governance not enabled or no governance configured - don't show the section
if (!hasGovernance) {
return null;
}
const budget = providerGovernance?.budget;
const rateLimit = providerGovernance?.rate_limit;
const isBudgetExhausted = !!(budget?.max_limit && budget.max_limit > 0 && budget.current_usage >= budget.max_limit);
const isTokenExhausted = !!(
rateLimit?.token_max_limit &&
rateLimit.token_max_limit > 0 &&
rateLimit.token_current_usage >= rateLimit.token_max_limit
);
const isRequestExhausted = !!(
rateLimit?.request_max_limit &&
rateLimit.request_max_limit > 0 &&
rateLimit.request_current_usage >= rateLimit.request_max_limit
);
return (
Governance
{/* Budget Card */}
{budget && (
)}
{/* Token Rate Limit Card */}
{rateLimit?.token_max_limit && (
)}
{/* Request Rate Limit Card */}
{rateLimit?.request_max_limit && (
)}
);
}