mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-29 16:27:05 -05:00
The AI has implemented the Phase 3 plan, which includes adding approval failure monitoring to the existing error monitoring page, extending the ErrorAnalytics component with approval metrics, adding performance indexes, and creating the ApprovalFailureModal component.
178 lines
7.4 KiB
TypeScript
178 lines
7.4 KiB
TypeScript
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts';
|
|
import { AlertCircle, TrendingUp, Users, Zap, CheckCircle, XCircle } from 'lucide-react';
|
|
|
|
interface ErrorSummary {
|
|
error_type: string | null;
|
|
occurrence_count: number | null;
|
|
affected_users: number | null;
|
|
avg_duration_ms: number | null;
|
|
}
|
|
|
|
interface ApprovalMetric {
|
|
id: string;
|
|
success: boolean;
|
|
duration_ms: number | null;
|
|
created_at: string | null;
|
|
}
|
|
|
|
interface ErrorAnalyticsProps {
|
|
errorSummary: ErrorSummary[] | undefined;
|
|
approvalMetrics: ApprovalMetric[] | undefined;
|
|
}
|
|
|
|
export function ErrorAnalytics({ errorSummary, approvalMetrics }: ErrorAnalyticsProps) {
|
|
// Calculate error metrics
|
|
const totalErrors = errorSummary?.reduce((sum, item) => sum + (item.occurrence_count || 0), 0) || 0;
|
|
const totalAffectedUsers = errorSummary?.reduce((sum, item) => sum + (item.affected_users || 0), 0) || 0;
|
|
const avgErrorDuration = errorSummary?.length
|
|
? errorSummary.reduce((sum, item) => sum + (item.avg_duration_ms || 0), 0) / errorSummary.length
|
|
: 0;
|
|
const topErrors = errorSummary?.slice(0, 5) || [];
|
|
|
|
// Calculate approval metrics
|
|
const totalApprovals = approvalMetrics?.length || 0;
|
|
const failedApprovals = approvalMetrics?.filter(m => !m.success).length || 0;
|
|
const successRate = totalApprovals > 0 ? ((totalApprovals - failedApprovals) / totalApprovals) * 100 : 0;
|
|
const avgApprovalDuration = approvalMetrics?.length
|
|
? approvalMetrics.reduce((sum, m) => sum + (m.duration_ms || 0), 0) / approvalMetrics.length
|
|
: 0;
|
|
|
|
// Show message if no data available
|
|
if ((!errorSummary || errorSummary.length === 0) && (!approvalMetrics || approvalMetrics.length === 0)) {
|
|
return (
|
|
<Card>
|
|
<CardContent className="pt-6">
|
|
<p className="text-center text-muted-foreground">No analytics data available</p>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Error Metrics */}
|
|
{errorSummary && errorSummary.length > 0 && (
|
|
<>
|
|
<div>
|
|
<h3 className="text-lg font-semibold mb-3">Error Metrics</h3>
|
|
<div className="grid gap-4 md:grid-cols-4">
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Total Errors</CardTitle>
|
|
<AlertCircle className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{totalErrors}</div>
|
|
<p className="text-xs text-muted-foreground">Last 30 days</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Error Types</CardTitle>
|
|
<TrendingUp className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{errorSummary.length}</div>
|
|
<p className="text-xs text-muted-foreground">Unique error types</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Affected Users</CardTitle>
|
|
<Users className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{totalAffectedUsers}</div>
|
|
<p className="text-xs text-muted-foreground">Users impacted</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Avg Duration</CardTitle>
|
|
<Zap className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{Math.round(avgErrorDuration)}ms</div>
|
|
<p className="text-xs text-muted-foreground">Before error occurs</p>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Top 5 Errors</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<ResponsiveContainer width="100%" height={300}>
|
|
<BarChart data={topErrors}>
|
|
<XAxis dataKey="error_type" />
|
|
<YAxis />
|
|
<Tooltip />
|
|
<Bar dataKey="occurrence_count" fill="hsl(var(--destructive))" />
|
|
</BarChart>
|
|
</ResponsiveContainer>
|
|
</CardContent>
|
|
</Card>
|
|
</>
|
|
)}
|
|
|
|
{/* Approval Metrics */}
|
|
{approvalMetrics && approvalMetrics.length > 0 && (
|
|
<div>
|
|
<h3 className="text-lg font-semibold mb-3">Approval Metrics</h3>
|
|
<div className="grid gap-4 md:grid-cols-4">
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Total Approvals</CardTitle>
|
|
<CheckCircle className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{totalApprovals}</div>
|
|
<p className="text-xs text-muted-foreground">Last 24 hours</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Failures</CardTitle>
|
|
<XCircle className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold text-destructive">{failedApprovals}</div>
|
|
<p className="text-xs text-muted-foreground">Failed approvals</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Success Rate</CardTitle>
|
|
<TrendingUp className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{successRate.toFixed(1)}%</div>
|
|
<p className="text-xs text-muted-foreground">Overall success rate</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Avg Duration</CardTitle>
|
|
<Zap className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{Math.round(avgApprovalDuration)}ms</div>
|
|
<p className="text-xs text-muted-foreground">Approval time</p>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|