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">URL</TableHead>
55 <TableHead className="font-semibold">Implementation</TableHead>
56 <TableHead className="font-semibold text-center">Attempt 1</TableHead>
57 <TableHead className="font-semibold text-center">Attempt 2</TableHead>
58 <TableHead className="font-semibold text-center">Attempt 3</TableHead>
59 <TableHead className="font-semibold text-center">Average</TableHead>
60 <TableHead className="font-semibold">Status</TableHead>
61 </TableRow>
62 </TableHeader>
63 <TableBody>
64 {sortedResults.map((result, index) => (
65 <TableRow key={index} className="hover:bg-muted/30 transition-colors">
66 <TableCell className="font-mono text-sm text-muted-foreground">
67 {result.mirrorUrl}
68 </TableCell>
69 <TableCell className="font-medium">
70 {result.implementation}
71 </TableCell>
72 {result.attempts.map((attempt, attemptIndex) => (
73 <TableCell key={attemptIndex} className="text-center font-mono text-sm">
74 {attempt.status === "success" ? (
75 <span className="text-foreground">
76 {attempt.responseTime.toFixed(0)}ms
77 </span>
78 ) : (
79 <span className="text-destructive">
80 <XCircle className="w-4 h-4 inline" />
81 </span>
82 )}
83 </TableCell>
84 ))}
85 <TableCell className="text-center font-mono text-sm">
86 {result.status === "success" ? (
87 <span className="font-bold text-primary text-base">
88 {result.avgResponseTime.toFixed(0)}ms
89 </span>
90 ) : (
91 <span className="text-muted-foreground">—</span>
92 )}
93 </TableCell>
94 <TableCell>
95 {result.status === "success" ? (
96 <Badge
97 variant="outline"
98 className="bg-success/10 text-success border-success/20 gap-1"
99 >
100 <CheckCircle2 className="w-3 h-3" />
101 Success
102 </Badge>
103 ) : (
104 <Badge
105 variant="outline"
106 className="bg-destructive/10 text-destructive border-destructive/20 gap-1"
107 >
108 <XCircle className="w-3 h-3" />
109 Error
110 </Badge>
111 )}
112 </TableCell>
113 </TableRow>
114 ))}
115 </TableBody>
116 </Table>
117 {sortedResults.length === 0 && (
118 <div className="text-center py-12 text-muted-foreground">
119 No results yet. Enter a DID and run the benchmark.
120 </div>
121 )}
122 </div>
123 </div>
124 );
125};