diff --git a/frontend/components/table/ColumnHeader.tsx b/frontend/components/table/ColumnHeader.tsx index 019905c..4ba9361 100644 --- a/frontend/components/table/ColumnHeader.tsx +++ b/frontend/components/table/ColumnHeader.tsx @@ -5,6 +5,51 @@ import type { DatasetRow, DatasetColumn } from "./types"; import { ColumnIcon } from "./ColumnIcon"; import { floorWidth } from "./utils"; +function SortIndicator({ direction }: { direction: false | "asc" | "desc" }) { + if (direction === "asc") { + return ( + + ); + } + if (direction === "desc") { + return ( + + ); + } + // Unsorted: show a faint up/down chevron pair as a hint that the column is sortable + return ( + + ); +} + export function ColumnHeader({ header, column, @@ -16,6 +61,10 @@ export function ColumnHeader({ isResizing: boolean; containerHeight: number; }) { + const isSorted = header.column.getIsSorted(); + const canSort = header.column.getCanSort(); + const toggleSort = header.column.getToggleSortingHandler(); + return (
{ + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + header.column.toggleSorting(); + } + } + : undefined + } + aria-sort={ + isSorted === "asc" + ? "ascending" + : isSorted === "desc" + ? "descending" + : undefined + } > {column && } {column?.isPrimaryKey && ( @@ -45,6 +118,7 @@ export function ColumnHeader({ )} {column?.name ?? header.id} + {canSort && }
{ + const a = rowA.getValue(columnId); + const b = rowB.getValue(columnId); + const toNum = (v: unknown): number => { + if (typeof v === "number") return v; + if (typeof v !== "string") return Number.NaN; + const n = Number(v.replace(/[^0-9.-]/g, "")); + return Number.isFinite(n) ? n : Number.NaN; + }; + const na = toNum(a); + const nb = toNum(b); + if (!Number.isNaN(na) && !Number.isNaN(nb)) return na - nb; + return String(a ?? "").localeCompare(String(b ?? ""), undefined, { + sensitivity: "base", + }); + }, }), ); @@ -84,6 +106,8 @@ export function DatasetTable({ return () => observer.disconnect(); }, []); + const [sorting, setSorting] = useState([]); + const [storedWidths, setStoredWidths] = usePersistedColumnWidths(datasetId); const columns = useMemo( @@ -96,6 +120,9 @@ export function DatasetTable({ columns, columnResizeMode: "onChange", getCoreRowModel: getCoreRowModel(), + getSortedRowModel: getSortedRowModel(), + onSortingChange: setSorting, + state: { sorting }, getRowId: (row) => row._id, });