"use client"; import { useEffect, useMemo, useState } from "react"; import { renderCell, type CellRenderer } from "@/components/cell-renderers"; import { ResultsTable } from "@/components/ResultsTable"; import { cellSortValue, type BrowserRow, type ColumnDef } from "@/lib/browser-row"; import { nextSort } from "@/lib/sort-rows"; import { applyTableView, browserViewHistory, facetKeysOf, facetValues, parseTableView, serializeTableView, type TableView, type ViewHistory, } from "@/lib/table-view"; import type { SortState } from "@/lib/types"; const FACET_LABELS: Record = { tags: "Tags" }; export function RecordBrowser({ rows, columns, heading = "Records", renderers, history, }: { rows: BrowserRow[]; columns: ColumnDef[]; heading?: string; renderers?: Record; history?: ViewHistory; }) { const viewHistory = useMemo(() => history ?? browserViewHistory(), [history]); const facetKeys = useMemo(() => facetKeysOf(rows), [rows]); const sortable = (key: string) => columns.some((column) => column.key === key); const baseSort: SortState = { key: columns[0]?.key ?? "name", dir: 1 }; const [search, setSearch] = useState(""); const [draft, setDraft] = useState(""); const view = parseTableView(search, facetKeys, sortable); const sort = view.sort ?? baseSort; const visible = applyTableView(rows, { ...view, sort }); useEffect(() => { const read = () => { const next = viewHistory.read(); setSearch(next); setDraft(parseTableView(next, facetKeys, sortable).q); }; read(); return viewHistory.subscribe(read); }, [viewHistory, facetKeys, columns]); function commit(next: TableView) { const query = serializeTableView(next, baseSort); viewHistory.push(query); setSearch(query ? `?${query}` : ""); setDraft(next.q); } function toggleFacet(key: string, value: string) { const current = view.facets[key] ?? []; const values = current.includes(value) ? current.filter((item) => item !== value) : [...current, value]; commit({ q: view.q, sort, facets: { ...view.facets, [key]: values } }); } const tableColumns = columns.map((column) => ({ key: column.key, label: column.label, sortable: true, render: (row: BrowserRow) => renderCell(column.key, row, renderers), })); return (

{heading}

{ event.preventDefault(); commit({ q: draft, sort, facets: view.facets }); }} >
{facetKeys.map((key) => { const values = facetValues(rows, key); if (values.length === 0) return null; const selected = view.facets[key] ?? []; return (
{FACET_LABELS[key] ?? key} {values.map((value) => ( ))}
); })} row.id} sort={sort} onSort={(key) => commit({ q: view.q, facets: view.facets, sort: nextSort(sort, key) })} empty="No records match this view." />
); }