Create Rate Limit Admin Dashboard

Add a React admin dashboard component to visualize rate limit metrics and statistics, including data fetching from the rate-limit-metrics edge function, charts and statistics, and admin routes/integration. Includes setup for routing and UI scaffolding to display total requests, block rate, top blocked IPs/users, and recent activity with interactive charts.
This commit is contained in:
gpt-engineer-app[bot]
2025-11-11 00:06:49 +00:00
parent f15190351d
commit 1628753361
4 changed files with 427 additions and 1 deletions

View File

@@ -0,0 +1,75 @@
import { useQuery } from '@tanstack/react-query';
import { supabase } from '@/integrations/supabase/client';
export interface RateLimitMetric {
timestamp: number;
functionName: string;
clientIP: string;
userId?: string;
allowed: boolean;
remaining: number;
retryAfter?: number;
tier: string;
}
export interface MetricsStats {
totalRequests: number;
allowedRequests: number;
blockedRequests: number;
blockRate: number;
uniqueIPs: number;
uniqueUsers: number;
topBlockedIPs: Array<{ ip: string; count: number }>;
topBlockedUsers: Array<{ userId: string; count: number }>;
tierDistribution: Record<string, number>;
}
interface MetricsQueryParams {
action: 'stats' | 'recent' | 'function' | 'user' | 'ip';
limit?: number;
timeWindow?: number;
functionName?: string;
userId?: string;
clientIP?: string;
}
export function useRateLimitMetrics(params: MetricsQueryParams) {
return useQuery({
queryKey: ['rateLimitMetrics', params],
queryFn: async () => {
const queryParams = new URLSearchParams();
queryParams.set('action', params.action);
if (params.limit) queryParams.set('limit', params.limit.toString());
if (params.timeWindow) queryParams.set('timeWindow', params.timeWindow.toString());
if (params.functionName) queryParams.set('functionName', params.functionName);
if (params.userId) queryParams.set('userId', params.userId);
if (params.clientIP) queryParams.set('clientIP', params.clientIP);
const { data, error } = await supabase.functions.invoke('rate-limit-metrics', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
body: queryParams,
});
if (error) throw error;
return data;
},
refetchInterval: 30000, // Refetch every 30 seconds
staleTime: 15000, // Consider data stale after 15 seconds
});
}
export function useRateLimitStats(timeWindow: number = 60000) {
return useRateLimitMetrics({ action: 'stats', timeWindow });
}
export function useRecentMetrics(limit: number = 100) {
return useRateLimitMetrics({ action: 'recent', limit });
}
export function useFunctionMetrics(functionName: string, limit: number = 100) {
return useRateLimitMetrics({ action: 'function', functionName, limit });
}