/ concept-collection / benchcompress
Sign in
concept-collection / benchcompress
benchcompress / web-ui / src / components / benchmark / table / BenchmarkTable.tsx
221 lines · 7.1 KBBlameHistoryRaw
1import { useMemo } from "react";
2import { useSearchParams } from "react-router-dom";
3import {
4 flexRender,
5 getCoreRowModel,
6 useReactTable,
7 getSortedRowModel,
8} from "@tanstack/react-table";
9import { BenchmarkResult } from "../../../types";
10import { columns } from "./columns";
11import { BenchmarkCharts } from "../charts/BenchmarkCharts";
12import { exportToCsv } from "../export/csvExport";
14interface BenchmarkTableProps {
15 results: BenchmarkResult[];
18export function BenchmarkTable({ results }: BenchmarkTableProps) {
19 const [searchParams, setSearchParams] = useSearchParams();
20 const selectedDataset = searchParams.get("dataset") || "";
21 const selectedAlgorithm = searchParams.get("algorithm") || "";
23 const availableDatasets = useMemo(() => {
24 return Array.from(new Set(results.map((result) => result.dataset))).sort();
25 }, [results]);
27 const availableAlgorithms = useMemo(() => {
28 return Array.from(
29 new Set(results.map((result) => result.algorithm)),
30 ).sort();
31 }, [results]);
33 // Memoize filtered data to prevent unnecessary recalculations
34 const filteredData = useMemo(() => {
35 let filtered = results;
36 if (selectedDataset) {
37 filtered = filtered.filter((row) => row.dataset === selectedDataset);
38 }
39 if (selectedAlgorithm) {
40 filtered = filtered.filter((row) => row.algorithm === selectedAlgorithm);
41 }
42 return filtered;
43 }, [results, selectedDataset, selectedAlgorithm]);
45 const table = useReactTable({
46 data: filteredData || [],
47 columns,
48 getCoreRowModel: getCoreRowModel(),
49 getSortedRowModel: getSortedRowModel(),
50 });
52 // Prepare data for bar charts when either dataset or algorithm is selected
53 const chartData = useMemo(() => {
54 if (selectedDataset) {
55 return results
56 .filter((row: BenchmarkResult) => row.dataset === selectedDataset)
57 .map((row: BenchmarkResult) => ({
58 algorithm: row.algorithm,
59 compression_ratio: row.compression_ratio,
60 encode_speed: row.encode_mb_per_sec,
61 decode_speed: row.decode_mb_per_sec,
62 }));
63 } else if (selectedAlgorithm) {
64 return results
65 .filter((row: BenchmarkResult) => row.algorithm === selectedAlgorithm)
66 .map((row: BenchmarkResult) => ({
67 algorithm: row.dataset, // Use dataset as the x-axis label when algorithm is selected
68 compression_ratio: row.compression_ratio,
69 encode_speed: row.encode_mb_per_sec,
70 decode_speed: row.decode_mb_per_sec,
71 }));
72 }
73 return [];
74 }, [results, selectedDataset, selectedAlgorithm]);
76 return (
77 <div className="table-container">
78 <div
79 style={{
80 marginBottom: "20px",
81 display: "flex",
82 alignItems: "center",
83 gap: "10px",
84 justifyContent: "space-between",
85 }}
86 >
87 <div style={{ display: "flex", alignItems: "center", gap: "20px" }}>
88 <div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
89 <label htmlFor="dataset-select">Dataset:</label>
90 <select
91 id="dataset-select"
92 value={selectedDataset}
93 onChange={(e) => {
94 if (e.target.value) {
95 setSearchParams({ dataset: e.target.value });
96 } else {
97 setSearchParams(
98 selectedAlgorithm ? { algorithm: selectedAlgorithm } : {},
99 );
100 }
101 }}
102 style={{
103 padding: "8px",
104 borderRadius: "4px",
105 border: "1px solid #ccc",
106 minWidth: "200px",
107 backgroundColor: "#fff",
108 }}
109 >
110 <option value="">All Datasets</option>
111 {availableDatasets.map((dataset) => (
112 <option key={dataset} value={dataset}>
113 {dataset}
114 </option>
115 ))}
116 </select>
117 </div>
118 <div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
119 <label htmlFor="algorithm-select">Algorithm:</label>
120 <select
121 id="algorithm-select"
122 value={selectedAlgorithm}
123 onChange={(e) => {
124 if (e.target.value) {
125 setSearchParams({ algorithm: e.target.value });
126 } else {
127 setSearchParams(
128 selectedDataset ? { dataset: selectedDataset } : {},
129 );
130 }
131 }}
132 style={{
133 padding: "8px",
134 borderRadius: "4px",
135 border: "1px solid #ccc",
136 minWidth: "200px",
137 backgroundColor: "#fff",
138 }}
139 >
140 <option value="">All Algorithms</option>
141 {availableAlgorithms.map((algorithm) => (
142 <option key={algorithm} value={algorithm}>
143 {algorithm}
144 </option>
145 ))}
146 </select>
147 </div>
148 </div>
149 <button
150 onClick={() =>
151 exportToCsv(filteredData, selectedDataset || selectedAlgorithm)
152 }
153 style={{
154 padding: "8px 16px",
155 backgroundColor: "#4CAF50",
156 color: "white",
157 border: "none",
158 borderRadius: "4px",
159 cursor: "pointer",
160 display: "flex",
161 alignItems: "center",
162 gap: "8px",
163 }}
164 >
165 <svg
166 width="16"
167 height="16"
168 viewBox="0 0 16 16"
169 fill="none"
170 xmlns="http://www.w3.org/2000/svg"
171 >
172 <path d="M8 12L3 7H6V1H10V7H13L8 12Z" fill="currentColor" />
173 <path d="M2 14V15H14V14H2Z" fill="currentColor" />
174 </svg>
175 Download CSV
176 </button>
177 </div>
179 {(selectedDataset || selectedAlgorithm) && chartData.length > 0 && (
180 <BenchmarkCharts chartData={chartData} />
181 )}
183 <table>
184 <thead>
185 {table.getHeaderGroups().map((headerGroup) => (
186 <tr key={headerGroup.id}>
187 {headerGroup.headers.map((header) => (
188 <th
189 key={header.id}
190 onClick={header.column.getToggleSortingHandler()}
191 style={{ cursor: "pointer" }}
192 >
193 {flexRender(
194 header.column.columnDef.header,
195 header.getContext(),
196 )}
197 {header.column.getIsSorted() && (
198 <span style={{ marginLeft: "4px" }}>
199 {header.column.getIsSorted() === "asc" ? "↑" : "↓"}
200 </span>
201 )}
202 </th>
203 ))}
204 </tr>
205 ))}
206 </thead>
207 <tbody>
208 {table.getRowModel().rows.map((row) => (
209 <tr key={row.id}>
210 {row.getVisibleCells().map((cell) => (
211 <td key={cell.id}>
212 {flexRender(cell.column.columnDef.cell, cell.getContext())}
213 </td>
214 ))}
215 </tr>
216 ))}
217 </tbody>
218 </table>
219 </div>
220 );
moveopenescclose