omnisealbench / frontend /src /components /LeaderboardTable.tsx
Mark Duppenthaler
Parity in functionality
ed37070
raw
history blame
4.63 kB
import React, { useEffect, useState } from 'react'
import API from '../API'
import LeaderboardFilter from './LeaderboardFilter'
interface LeaderboardTableProps {
file: string
}
interface Row {
metric: string
[key: string]: string | number
}
interface Groups {
[group: string]: { [subgroup: string]: string[] }
}
const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ file }) => {
const [tableRows, setTableRows] = useState<Row[]>([])
const [tableHeader, setTableHeader] = useState<string[]>([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const [groups, setGroups] = useState<Groups>({})
const [selectedMetrics, setSelectedMetrics] = useState<Set<string>>(new Set())
const [defaultSelectedMetrics, setDefaultSelectedMetrics] = useState<string[]>([])
useEffect(() => {
API.fetchStaticFile(`data/${file}_benchmark.csv`)
.then((response) => {
const data = JSON.parse(response)
const rows: Row[] = data['rows']
const groups = data['groups'] as { [key: string]: string[] }
// Each value of groups is a list of metrics, group them by the first part of the metric before the first _
const groupsData = Object.entries(groups)
.sort(([groupA], [groupB]) => {
// Make sure "overall" comes first
if (groupA === 'Overall') return -1
if (groupB === 'Overall') return 1
// Otherwise sort alphabetically
return groupA.localeCompare(groupB)
})
.reduce(
(acc, [group, metrics]) => {
// Sort metrics to ensure consistent subgroup order
const sortedMetrics = [...metrics].sort()
// Create and sort subgroups
acc[group] = sortedMetrics.reduce<{ [key: string]: string[] }>((subAcc, metric) => {
const [mainGroup, subGroup] = metric.split('_')
if (!subAcc[mainGroup]) {
subAcc[mainGroup] = []
}
subAcc[mainGroup].push(metric)
return subAcc
}, {})
// Convert to sorted entries and back to object
acc[group] = Object.fromEntries(
Object.entries(acc[group]).sort(([subGroupA], [subGroupB]) =>
subGroupA.localeCompare(subGroupB)
)
)
return acc
},
{} as { [key: string]: { [key: string]: string[] } }
)
const allKeys: string[] = Array.from(new Set(rows.flatMap((row) => Object.keys(row))))
setSelectedMetrics(new Set(data['default_selected_metrics']))
setDefaultSelectedMetrics(data['default_selected_metrics'])
setTableHeader(allKeys)
setTableRows(rows)
setGroups(groupsData)
setLoading(false)
})
.catch((err) => {
setError('Failed to fetch JSON: ' + err.message)
setLoading(false)
})
}, [file])
const handleSelectDefaults = () => {
setSelectedMetrics(new Set(defaultSelectedMetrics))
}
return (
<div className="rounded shadow overflow-auto">
<h3 className="font-bold mb-2">{file}</h3>
{loading && <div>Loading...</div>}
{error && <div className="text-red-500">{error}</div>}
{!loading && !error && (
<div className="overflow-x-auto">
<LeaderboardFilter
groups={groups}
selectedMetrics={selectedMetrics}
setSelectedMetrics={setSelectedMetrics}
defaultSelectedMetrics={defaultSelectedMetrics}
/>
<table className="table">
<thead>
<tr>
{tableHeader.map((col, idx) => (
<th key={idx}>{col}</th>
))}
</tr>
</thead>
<tbody>
{tableRows
.filter((row) => selectedMetrics.has(row['metric'] as string))
.map((row, i) => (
<tr key={i}>
{Object.keys(row).map((column, j) => {
const cell = row[column]
return (
<td key={j}>
<div className="">
{isNaN(Number(cell)) ? cell : Number(Number(cell).toFixed(3))}
</div>
</td>
)
})}
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
)
}
export default LeaderboardTable