import React, { useState, useEffect, useMemo } from 'react'; import { useTable, useSortBy, useFilters, usePagination } from 'react-table'; import api from '../api'; // Default filter UI for columns function DefaultColumnFilter({ column: { filterValue, preFilteredRows, setFilter }, }) { const count = preFilteredRows.length; return ( { setFilter(e.target.value || undefined); }} placeholder={`Search ${count} records...`} className="px-2 py-1 text-sm border rounded focus:outline-none focus:ring-2 focus:ring-primary/50 w-full" /> ); } // Dummy data for when API fails const dummyData = [ { Model: 'WatermarkA', 'Success Rate': '95%', 'Attack Resistance': 'High', 'Visual Quality': '9.2', 'Compute Requirements': 'Medium' }, { Model: 'WatermarkB', 'Success Rate': '92%', 'Attack Resistance': 'Medium', 'Visual Quality': '9.5', 'Compute Requirements': 'Low' }, { Model: 'WatermarkC', 'Success Rate': '98%', 'Attack Resistance': 'Very High', 'Visual Quality': '8.8', 'Compute Requirements': 'High' } ]; // Dummy columns for when API fails const dummyColumns = [ { Header: 'Model', accessor: 'Model' }, { Header: 'Success Rate', accessor: 'Success Rate' }, { Header: 'Attack Resistance', accessor: 'Attack Resistance' }, { Header: 'Visual Quality', accessor: 'Visual Quality' }, { Header: 'Compute Requirements', accessor: 'Compute Requirements' } ]; function Leaderboard({ benchmark }) { const [data, setData] = useState([]); const [columns, setColumns] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [searchQuery, setSearchQuery] = useState(''); useEffect(() => { // Fetch leaderboard data and columns when the benchmark changes async function fetchData() { try { setLoading(true); // Fetch available columns first const columnsResponse = await api.getColumns(benchmark); if (!columnsResponse.success) { throw new Error(columnsResponse.error || 'Failed to fetch columns'); } // Format columns for react-table const tableColumns = columnsResponse.columns.map(column => ({ Header: column, accessor: column, Filter: DefaultColumnFilter, })); setColumns(tableColumns); // Fetch leaderboard data const dataResponse = await api.getLeaderboard(benchmark); if (!dataResponse.success) { throw new Error(dataResponse.error || 'Failed to fetch leaderboard data'); } setData(dataResponse.data); setError(null); } catch (err) { console.error('Leaderboard error:', err); setError(err.message || 'An error occurred'); // Set dummy data so UI doesn't show error setData(dummyData); setColumns(dummyColumns.map(col => ({ ...col, Filter: DefaultColumnFilter }))); } finally { setLoading(false); } } fetchData(); }, [benchmark]); // Filter data based on search query const filteredData = useMemo(() => { if (!searchQuery) return data; return data.filter(row => { return Object.values(row).some(value => String(value).toLowerCase().includes(searchQuery.toLowerCase()) ); }); }, [data, searchQuery]); // Set up react-table const { getTableProps, getTableBodyProps, headerGroups, page, prepareRow, canPreviousPage, canNextPage, pageOptions, pageCount, gotoPage, nextPage, previousPage, setPageSize, state: { pageIndex, pageSize }, } = useTable( { columns, data: filteredData, initialState: { pageIndex: 0, pageSize: 10 }, }, useFilters, useSortBy, usePagination ); if (loading) { return (
Loading leaderboard data...
); } return (

{benchmark.charAt(0).toUpperCase() + benchmark.slice(1)} Watermark Benchmark

setSearchQuery(e.target.value)} className="w-full px-4 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-primary/50" />
{headerGroups.map(headerGroup => ( {headerGroup.headers.map(column => ( ))} ))} {page.map(row => { prepareRow(row); return ( {row.cells.map(cell => ( ))} ); })}
{column.render('Header')} {column.isSorted ? column.isSortedDesc ? ' ↓' : ' ↑' : ''}
{column.canFilter ? column.render('Filter') : null}
{cell.render('Cell')}
Page{' '} {pageIndex + 1} of {pageOptions.length}
Go to page: { const page = e.target.value ? Number(e.target.value) - 1 : 0; gotoPage(page); }} className="w-16 px-2 py-1 border rounded" />
); } export default Leaderboard;