A quick vibe-coded site to test response times of PLC.directory mirrors (over 3 attempts)
1import { BenchmarkResult } from "@/types/benchmark";
2import {
3 Table,
4 TableBody,
5 TableCell,
6 TableHead,
7 TableHeader,
8 TableRow,
9} from "@/components/ui/table";
10import { Badge } from "@/components/ui/badge";
11import { CheckCircle2, XCircle } from "lucide-react";
12
13interface BenchmarkTableProps {
14 results: BenchmarkResult[];
15}
16
17export const BenchmarkTable = ({ results }: BenchmarkTableProps) => {
18 // Sort by average response time (fastest first)
19 const sortedResults = [...results].sort((a, b) => {
20 if (a.status === "error" && b.status === "success") return 1;
21 if (a.status === "success" && b.status === "error") return -1;
22 return a.avgResponseTime - b.avgResponseTime;
23 });
24
25 // Calculate overall average across all successful attempts
26 const allSuccessfulAttempts = sortedResults.flatMap((r) =>
27 r.attempts.filter((a) => a.status === "success")
28 );
29 const overallAvg =
30 allSuccessfulAttempts.length > 0
31 ? allSuccessfulAttempts.reduce((sum, a) => sum + a.responseTime, 0) /
32 allSuccessfulAttempts.length
33 : 0;
34
35 return (
36 <div className="space-y-4">
37 {/* Overall Average */}
38 {overallAvg > 0 && (
39 <div className="bg-primary/5 border border-primary/20 rounded-lg p-4 flex items-center justify-between">
40 <span className="font-semibold text-foreground">
41 Overall Average Response Time
42 </span>
43 <span className="text-2xl font-bold font-mono text-primary">
44 {overallAvg.toFixed(0)}ms
45 </span>
46 </div>
47 )}
48
49 {/* Results Table */}
50 <div className="rounded-lg border border-border bg-card overflow-hidden">
51 <Table>
52 <TableHeader>
53 <TableRow className="bg-muted/50">
54 <TableHead className="font-semibold">Implementation</TableHead>
55 <TableHead className="font-semibold text-center">Attempt 1</TableHead>
56 <TableHead className="font-semibold text-center">Attempt 2</TableHead>
57 <TableHead className="font-semibold text-center">Attempt 3</TableHead>
58 <TableHead className="font-semibold text-center">Average</TableHead>
59 <TableHead className="font-semibold">Status</TableHead>
60 </TableRow>
61 </TableHeader>
62 <TableBody>
63 {sortedResults.map((result, index) => (
64 <TableRow key={index} className="hover:bg-muted/30 transition-colors">
65 <TableCell className="font-mono text-sm font-medium">
66 {result.mirrorUrl}
67 </TableCell>
68 {result.attempts.map((attempt, attemptIndex) => (
69 <TableCell key={attemptIndex} className="text-center font-mono text-sm">
70 {attempt.status === "success" ? (
71 <span className="text-foreground">
72 {attempt.responseTime.toFixed(0)}ms
73 </span>
74 ) : (
75 <span className="text-destructive">
76 <XCircle className="w-4 h-4 inline" />
77 </span>
78 )}
79 </TableCell>
80 ))}
81 <TableCell className="text-center font-mono text-sm">
82 {result.status === "success" ? (
83 <span className="font-bold text-primary text-base">
84 {result.avgResponseTime.toFixed(0)}ms
85 </span>
86 ) : (
87 <span className="text-muted-foreground">—</span>
88 )}
89 </TableCell>
90 <TableCell>
91 {result.status === "success" ? (
92 <Badge
93 variant="outline"
94 className="bg-success/10 text-success border-success/20 gap-1"
95 >
96 <CheckCircle2 className="w-3 h-3" />
97 Success
98 </Badge>
99 ) : (
100 <Badge
101 variant="outline"
102 className="bg-destructive/10 text-destructive border-destructive/20 gap-1"
103 >
104 <XCircle className="w-3 h-3" />
105 Error
106 </Badge>
107 )}
108 </TableCell>
109 </TableRow>
110 ))}
111 </TableBody>
112 </Table>
113 {sortedResults.length === 0 && (
114 <div className="text-center py-12 text-muted-foreground">
115 No results yet. Enter a DID and run the benchmark.
116 </div>
117 )}
118 </div>
119 </div>
120 );
121};