import * as React from "react"; import DataGrid, { Column, SelectColumn, SortColumn } from "react-data-grid"; import { format, timeFormat, timeParse } from "@hpcc-js/common"; import { useData } from "./hooks"; import type { Table } from "./table"; export type QuerySortItem = { attribute: string, descending: boolean }; function copyAndSort(items: T[], attribute: string, descending?: boolean): T[] { const key = attribute as keyof T; return [...items].sort((a: T, b: T) => { if (a[key] < b[key]) { return descending ? 1 : -1; } else if (a[key] > b[key]) { return descending ? -1 : 1; } return 0; }); } interface EmptyRowsRendererProps { message: string } const EmptyRowsRenderer: React.FunctionComponent = ({ message }) => { return
{message} --- * --- * ---
; }; interface ColumnEx extends Column { __hpcc_pattern?: ReturnType; __hpcc_format?: ReturnType | ReturnType; } export interface ReactTableProps { table: Table; sort?: QuerySortItem, } export const ReactTable: React.FunctionComponent = ({ table, sort }) => { const [columns, data] = useData(table); const multiSelect = table.multiSelect(); const columnTypes = table.columnTypes(); const columnPatterns = table.columnPatterns(); const columnFormats = table.columnFormats(); const [listColumns, setListColumns] = React.useState[]>([]); const [sortColumn, setSortColumn] = React.useState(); const [rows, setRows] = React.useState([]); const [selectedRows, setSelectedRows] = React.useState>(new Set()); // Columns --- React.useEffect(() => { setListColumns([ ...multiSelect ? [SelectColumn] : [], ...columns.map((column): ColumnEx => { const type = columnTypes[column] ?? "string"; let formatter; let __hpcc_pattern; let __hpcc_format; switch (type) { case "time": __hpcc_pattern = columnPatterns[column] !== undefined ? timeParse(columnPatterns[column]) : undefined; __hpcc_format = columnFormats[column] !== undefined ? timeFormat(columnFormats[column]) : undefined; break; case "number": formatter = (props) => { return
{props.row[props.column.key]}
; }; // eslint-disable-next-line no-fallthrough default: __hpcc_format = columnFormats[column] !== undefined ? format(columnFormats[column]) : undefined; } return { key: column, name: column, resizable: true, sortable: true, minWidth: 80, formatter, __hpcc_pattern, __hpcc_format }; }) ]); }, [columnFormats, columnPatterns, columnTypes, columns, multiSelect]); const onSortColumnsChange = React.useCallback((sortColumns: SortColumn[]) => { const futureSortColumn = sortColumns.slice(-1)[0]; const sorted = futureSortColumn !== undefined; const isSortedDescending: boolean = futureSortColumn?.direction === "DESC"; setSortColumn(futureSortColumn); setRows(copyAndSort(rows, sorted ? futureSortColumn.columnKey : "key", sorted ? isSortedDescending : false)); }, [rows]); const rowKeyGetter = React.useCallback((row: any) => { return row.key; }, []); const onSelectedRowsChange = React.useCallback((selectedRows: Set) => { setSelectedRows(selectedRows); }, []); const onRowClick = React.useCallback((row, column) => { table.onRowClickCallback(row, column.key); }, [table]); // Rows --- React.useEffect(() => { let items = data.map((row, index) => { const retVal = { key: index }; listColumns.forEach((column, index) => { let val = row[index] as string; if (column.__hpcc_pattern && column.__hpcc_format) { val = column.__hpcc_format(column.__hpcc_pattern(val)); } else if (column.__hpcc_pattern) { val = column.__hpcc_pattern(val).toString(); } else if (column.__hpcc_format) { val = column.__hpcc_format(val as any); } retVal[column.key] = val; }); return retVal; }); if (sort?.attribute) { items = copyAndSort(items, sort.attribute, sort.descending); } setRows(items); }, [listColumns, data, sort]); return }} className={table.darkMode() ? "rdg-dark" : "rdg-light"} sortColumns={sortColumn ? [sortColumn] : []} onSortColumnsChange={onSortColumnsChange} selectedRows={selectedRows} onSelectedRowsChange={multiSelect ? onSelectedRowsChange : undefined} onRowClick={multiSelect ? undefined : onRowClick} aria-describedby={""} aria-label={""} aria-labelledby={""} style={{ height: "100%" }} />; };