TypeScript 97.5%
SQL 1.4%
Python 0.8%
1import Link from "next/link";2import { Table, TableBody, TableCell, TableEmpty, TableHead, TableHeader, TableRow } from "@/components/ui/table";3import { Badge, StatusBadge } from "@/components/ui/badge";4import { formatBytes, formatDate, formatMs, formatUsd, timeAgo } from "@/lib/format";5import type { RequestListRow } from "@/lib/queries/dashboard";6import { cn } from "@/lib/utils";78export function NetworkLabel({ network, requested }: { network: string | null; requested?: string }) {9 if (!network) return <span className="text-fg-subtle">—</span>;10 return (11 <span className="inline-flex items-center gap-1">12 <span>{network === "isp" ? "ISP" : network}</span>13 {requested && requested !== "auto" && requested !== network ? (14 <span className="text-[11px] text-fg-subtle" title={`Requested ${requested}`}>15 (asked {requested})16 </span>17 ) : null}18 </span>19 );20}2122export function HttpCode({ code }: { code: number | null }) {23 if (code === null) return <span className="text-fg-subtle">—</span>;24 const tone = code < 300 ? "text-success" : code < 400 ? "text-info" : code < 500 ? "text-warning" : "text-danger";25 return <span className={cn("font-mono tabular", tone)}>{code}</span>;26}2728/** Request log table. `compact` hides secondary columns (used on the Overview). */29export function RequestsTable({ rows, compact, emptyMessage = "No requests match these filters." }: { rows: RequestListRow[]; compact?: boolean; emptyMessage?: React.ReactNode }) {30 const cols = compact ? 7 : 11;31 return (32 <Table>33 <TableHeader>34 <TableRow className="hover:bg-transparent">35 <TableHead>Request</TableHead>36 <TableHead>Time</TableHead>37 <TableHead>Domain</TableHead>38 <TableHead>Status</TableHead>39 <TableHead className="text-right">HTTP</TableHead>40 {!compact ? <TableHead>Network</TableHead> : null}41 {!compact ? <TableHead>Country</TableHead> : null}42 <TableHead className="text-right">Latency</TableHead>43 {!compact ? <TableHead className="text-right">Attempts</TableHead> : null}44 {!compact ? <TableHead className="text-right">Bandwidth</TableHead> : null}45 <TableHead className="text-right">Cost</TableHead>46 </TableRow>47 </TableHeader>48 <TableBody>49 {rows.length === 0 ? (50 <TableEmpty colSpan={cols}>{emptyMessage}</TableEmpty>51 ) : (52 rows.map((r) => (53 <TableRow key={r.id}>54 <TableCell>55 <Link href={`/dashboard/requests/${r.id}`} className="font-mono text-[12.5px] text-accent underline-offset-4 hover:underline" prefetch={false}>56 {r.id}57 </Link>58 {r.source !== "api" ? (59 <Badge variant="outline" className="ml-2 align-middle text-[10.5px]">60 {r.source}61 </Badge>62 ) : null}63 </TableCell>64 <TableCell className="whitespace-nowrap text-fg-muted" title={formatDate(r.createdAt, { timeStyle: "medium" })}>65 {timeAgo(r.createdAt)}66 </TableCell>67 <TableCell className="max-w-[220px] truncate" title={r.url}>68 {r.domain}69 </TableCell>70 <TableCell>71 <StatusBadge status={r.status} />72 </TableCell>73 <TableCell className="text-right">74 <HttpCode code={r.httpStatus} />75 </TableCell>76 {!compact ? (77 <TableCell className="text-fg-muted">78 <NetworkLabel network={r.network} requested={r.requestedNetwork} />79 </TableCell>80 ) : null}81 {!compact ? <TableCell className="font-mono tabular text-fg-muted">{r.country ?? "—"}</TableCell> : null}82 <TableCell className="text-right font-mono tabular">{formatMs(r.latencyMs)}</TableCell>83 {!compact ? <TableCell className="text-right font-mono tabular">{r.attempts || "—"}</TableCell> : null}84 {!compact ? <TableCell className="text-right font-mono tabular text-fg-muted">{formatBytes(r.bytesIn + r.bytesOut)}</TableCell> : null}85 <TableCell className="text-right font-mono tabular">{formatUsd(r.priceUsd, true)}</TableCell>86 </TableRow>87 ))88 )}89 </TableBody>90 </Table>91 );92}93