react-table#useSortBy TypeScript Examples
The following examples show how to use
react-table#useSortBy.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Table.tsx From crossfeed with Creative Commons Zero v1.0 Universal | 5 votes |
Table = <T extends object>(props: TableProps<T>) => { const { columns, data, initialSortBy, initialFilterBy, pageCount = 0, pageSize = 20, fetchData, disableFilters = false, renderPagination, renderExpanded, tableRef } = props; const stateReducer = (nextState: any, action: any, prevState: any) => { if (action.type === 'toggleSortBy' || action.type === 'setGlobalFilter') { return { ...nextState, pageIndex: 0 }; } return nextState; }; const instance = useTable( { columns, data, disableMultiSort: true, manualSortBy: Boolean(fetchData), manualPagination: Boolean(fetchData), manualFilters: Boolean(fetchData), autoResetSortBy: false, disableFilters, pageCount, stateReducer, initialState: { sortBy: initialSortBy ?? [], pageSize, pageIndex: 0, filters: initialFilterBy ?? [], globalFilter: [] } }, useFilters, useSortBy, useExpanded, usePagination ); useImperativeHandle(tableRef, () => instance); const { state: { sortBy, pageIndex, filters } } = instance; useEffect(() => { fetchData && fetchData({ sort: sortBy, page: pageIndex + 1, pageSize, filters }); }, [fetchData, sortBy, filters, pageIndex, pageSize]); return ( <div className={classes.root}> <div className={classes.tableInner}> <UsaTable {...instance.getTableProps()} bordered={false}> <TableHead<T> {...instance} /> <TableBody<T> {...instance} renderExpanded={renderExpanded} /> </UsaTable> </div> {props.noResults && ( <NoResults message={props.noResultsMessage!}></NoResults> )} {renderPagination && renderPagination(instance)} </div> ); }
Example #2
Source File: Table.tsx From grafana-chinese with Apache License 2.0 | 5 votes |
Table: FC<Props> = memo(({ data, height, onCellClick, width, columnMinWidth }) => {
const theme = useTheme();
const [ref, headerRowMeasurements] = useMeasure();
const tableStyles = getTableStyles(theme);
const { getTableProps, headerGroups, rows, prepareRow } = useTable(
{
columns: useMemo(() => getColumns(data, width, columnMinWidth ?? 150), [data, width, columnMinWidth]),
data: useMemo(() => getTableRows(data), [data]),
},
useSortBy,
useBlockLayout
);
const RenderRow = React.useCallback(
({ index, style }) => {
const row = rows[index];
prepareRow(row);
return (
<div {...row.getRowProps({ style })} className={tableStyles.row}>
{row.cells.map((cell: Cell, index: number) => (
<TableCell
key={index}
field={data.fields[cell.column.index]}
tableStyles={tableStyles}
cell={cell}
onCellClick={onCellClick}
/>
))}
</div>
);
},
[prepareRow, rows]
);
let totalWidth = 0;
for (const headerGroup of headerGroups) {
for (const header of headerGroup.headers) {
totalWidth += header.width as number;
}
}
return (
<div {...getTableProps()} className={tableStyles.table}>
<CustomScrollbar>
<div>
{headerGroups.map((headerGroup: any) => (
<div className={tableStyles.thead} {...headerGroup.getHeaderGroupProps()} ref={ref}>
{headerGroup.headers.map((column: any) =>
renderHeaderCell(column, tableStyles.headerCell, data.fields[column.index])
)}
</div>
))}
</div>
<FixedSizeList
height={height - headerRowMeasurements.height}
itemCount={rows.length}
itemSize={tableStyles.rowHeight}
width={totalWidth ?? width}
style={{ overflow: 'hidden auto' }}
>
{RenderRow}
</FixedSizeList>
</CustomScrollbar>
</div>
);
})
Example #3
Source File: FeTable.tsx From frontegg-react with MIT License | 5 votes |
FeTable: FC<TableProps> = <T extends object>(props: TableProps<T>) => { const tableRef = useRef<HTMLDivElement>(null); const firstRender = useRef<boolean>(true); const columns = useMemo(() => { const columns = props.columns.map( ({ sortable, Filter, Header, ...rest }) => ({ ...rest, disableSortBy: !sortable, disableFilters: !Filter, Filter, Header: Header ?? <div style={{ minWidth: rest.minWidth, maxWidth: rest.maxWidth }} />, } as FeTableColumnOptions<T>) ); if (props.expandable) { columns.unshift({ id: 'fe-expander', minWidth: 60, maxWidth: '60px' as any, Header: <div style={{ minWidth: '2rem', maxWidth: '2rem' }} />, Cell: (cell: Cell<T>) => { const row = cell.row as Row<T> & UseExpandedRowProps<T>; return ( <FeButton className={classNames('fe-table__expand-button', { 'is-expanded': row.isExpanded })} {...row.getToggleRowExpandedProps()} variant={row.isExpanded ? 'primary' : undefined} > <FeIcon name='right-arrow' /> </FeButton> ); }, }); } if (props.selection) { columns.unshift({ id: 'fe-selection', minWidth: 60, maxWidth: '60px' as any, Cell: (cell: Cell<T>) => { const row = cell.row as Row<T> & UseRowSelectRowProps<T>; return ( <FeCheckbox {...row.getToggleRowSelectedProps()} checked={row.isSelected} onChange={(e) => onRowSelected(row.original, e.target.checked)} /> ); }, }); } return columns as Column<T>[]; }, [props.columns, props.expandable]); const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow, state, // The page controls ;) page, canPreviousPage, canNextPage, pageOptions, pageCount, gotoPage, nextPage, previousPage, setPageSize, // select props toggleAllRowsSelected, isAllRowsSelected, selectedFlatRows, toggleRowSelected, } = useTable( { columns, data: props.data, getRowId: (row: any) => row[props.rowKey], manualSortBy: !!props.onSortChange, manualFilters: !!props.onFilterChange, manualPagination: !!props.onPageChange, manualRowSelectedKey: props.rowKey, pageCount: !!props.onPageChange ? props.pageCount : undefined, autoResetPage: !props.onPageChange, useControlledState: (state1: any, meta) => ({ ...state1, sortBy: props.sortBy ?? state1.sortBy, filters: props.filters ?? state1.filters, selectedRowIds: props.selectedRowIds ?? state1.selectedRowIds, } as FeTableState<T>), expandSubRows: false, autoResetExpanded: false, initialState: { pageIndex: 0, pageSize: props.pageSize, selectedRowIds: props.selectedRowIds || {}, }, } as FeUseTable<T>, useFilters, useSortBy, useExpanded, usePagination, useRowSelect, useFlexLayout ) as FeTableInstance<T>; checkTableProps(props); const tableState = state as UseSortByState<T> & UseFiltersState<T> & UsePaginationState<T> & UseRowSelectState<T>; const onSortChange = useCallback( (column: FeTableColumnProps<T>) => { if (props.hasOwnProperty('sortBy')) { const sortBy = props.isMultiSort ? tableState.sortBy.filter(({ id }) => id !== column.id) : []; if (!column.isSorted) { sortBy.push({ id: column.id, desc: false }); } else if (!column.isSortedDesc) { sortBy.push({ id: column.id, desc: true }); } props.onSortChange?.(sortBy); } else { if (column.isSorted && column.isSortedDesc) { column.clearSortBy(); } else { column.toggleSortBy(column.isSorted, props.isMultiSort ?? false); } } }, [props.onSortChange] ); const onFilterChange = useCallback( (column: FeTableColumnProps<T>, filterValue?: any) => { if (props.hasOwnProperty('filters')) { const filters = tableState.filters.filter(({ id }) => id !== column.id); if (filterValue != null) { filters.push({ id: column.id, value: filterValue }); } props.onFilterChange?.(filters); } else { column.setFilter(filterValue); } }, [props.onFilterChange, tableState] ); const onToggleAllRowsSelected = useCallback( (value: boolean) => { if (props.hasOwnProperty('selectedRowIds')) { const selectedIds = props.data.reduce((p, n: any) => ({ ...p, [n[props.rowKey]]: true }), {}); props.onRowSelected?.(value ? selectedIds : {}); } else { toggleAllRowsSelected(value); } }, [props.onRowSelected] ); const onRowSelected = useCallback( (row: any, value: boolean) => { const id = row[props.rowKey]; if (props.hasOwnProperty('selectedRowIds')) { const newSelectedRows: any = { ...props.selectedRowIds }; if (value) { newSelectedRows[id] = true; } else { delete newSelectedRows[id]; } props.onRowSelected?.(newSelectedRows); } else { toggleRowSelected(id, value); } }, [props.onRowSelected] ); const handleOnPageChange = useCallback(() => { if (pagination === 'pages') { tableRef.current?.querySelector(`.${prefixCls}__tbody`)?.scroll?.({ top: 0, left: 0, behavior: 'smooth' }); } props.onPageChange?.(tableState.pageSize, tableState.pageIndex); }, [tableState.pageIndex]); useEffect(() => { !props.hasOwnProperty('sortBy') && props.onSortChange?.(tableState.sortBy); }, [props.sortBy, tableState.sortBy]); useEffect(() => { !props.hasOwnProperty('filters') && props.onFilterChange?.(tableState.filters); }, [props.filters, tableState.filters]); useEffect(() => { firstRender.current ? (firstRender.current = false) : handleOnPageChange(); }, [tableState.pageIndex]); useEffect(() => { !props.hasOwnProperty('selectedRowIds') && props.onRowSelected?.(tableState.selectedRowIds as any); }, [tableState.selectedRowIds]); const tableHeadProps: FeTableTHeadProps<T> = { prefixCls, headerGroups, onSortChange, onFilterChange, toggleAllRowsSelected, isAllRowsSelected, selectedFlatRows, }; const tableRows: (Row<T> & UseExpandedRowProps<T>)[] = useMemo( () => (props.pagination ? page : rows) as (Row<T> & UseExpandedRowProps<T>)[], [page, rows, props.pagination] ); const tablePaginationProps: FeTablePaginationProps<T> = { pageIndex: tableState.pageIndex, pageSize: tableState.pageSize, canPreviousPage, canNextPage, pageOptions, pageCount, gotoPage, nextPage, previousPage, setPageSize, }; const { className, toolbar, loading, pagination, pageSize } = props; return ( <div className='fe-table__container'> <div ref={tableRef} className={classNames(prefixCls, className)} {...getTableProps()}> {toolbar && <FeTableToolbar />} <div className={classNames( `${prefixCls}__table-container`, loading && pagination === 'pages' && `${prefixCls}__table-container-loading` )} > <FeTableTBody pageSize={pageSize} pagination={pagination} onInfiniteScroll={handleOnPageChange} loading={props.loading} prefixCls={prefixCls} prepareRow={prepareRow} getTableBodyProps={getTableBodyProps} renderExpandedComponent={props.renderExpandedComponent} rows={tableRows} /> <FeTableTHead {...tableHeadProps} /> </div> {loading && pagination === 'pages' && rows.length > 0 && <FeLoader center size={24} />} {pagination === 'pages' && <FeTablePagination {...tablePaginationProps} />} </div> </div> ); }
Example #4
Source File: Table.tsx From solo with MIT License | 5 votes |
Table = <T extends object>({ columns, data, initialSortBy, manualPagination = true, manualSortBy = true, pageCount = 0, fetchData, onSelectedRowsChange, renderSubComponent, renderPagination, renderFilterControls }: TableProps<T>) => { const stateReducer = (nextState: any, action: any, prevState: any) => { if (action.type === "toggleSortBy" || action.type === "setGlobalFilter") { return { ...nextState, pageIndex: 0 }; } return nextState; }; const instance = useTable( { columns, data, manualGlobalFilter: true, disableMultiSort: true, manualSortBy, manualPagination, autoResetSortBy: !manualSortBy, pageCount, stateReducer, initialState: { sortBy: initialSortBy ?? [], pageSize: 20, globalFilter: [] } }, useGlobalFilter, useSortBy, useExpanded, usePagination, useRowSelect ); const { state: { sortBy, pageIndex, globalFilter, selectedRowIds } } = instance; useEffect(() => { fetchData && fetchData({ sort: sortBy, page: pageIndex + 1, filters: globalFilter }); }, [fetchData, sortBy, globalFilter, pageIndex]); useEffect(() => { onSelectedRowsChange && onSelectedRowsChange(instance); }, [selectedRowIds, instance, onSelectedRowsChange]); return ( <> {renderFilterControls && renderFilterControls(instance)} <USWDSTable {...instance.getTableProps()}> <TableHead headerGroups={instance.headerGroups} /> <TableBody {...instance} renderSubComponent={renderSubComponent} /> </USWDSTable> {renderPagination && renderPagination(instance)} </> ); }
Example #5
Source File: index.tsx From livepeer-com with MIT License | 4 votes |
Table = <T extends Record<string, unknown>>({ columns, data, header, pageSize = 100, rowSelection, onRowSelectionChange, initialSortBy, filters, showOverflow, }: Props<T>) => { const someColumnCanSort = useMemo(() => { // To see if we show the sort help tooltip or not // @ts-ignore return columns.some((column) => !column.disableSortBy); }, [columns]); const getRowId = useCallback((row, relativeIndex, parent) => { return row?.id ? row.id : relativeIndex; }, []); const { getTableProps, getTableBodyProps, prepareRow, headerGroups, // @ts-ignore page, // @ts-ignore nextPage, // @ts-ignore previousPage, // @ts-ignore canPreviousPage, // @ts-ignore canNextPage, // @ts-ignore toggleAllRowsSelected, // @ts-ignore selectedFlatRows, // @ts-ignore setFilter, // @ts-ignore state: { filters: currentFilters }, } = useTable( { // @ts-ignore columns, data, getRowId, initialState: { // @ts-ignore pageSize, pageIndex: 0, ...(initialSortBy ? { sortBy: initialSortBy } : undefined), }, manualSortBy: false, autoResetFilters: false, autoResetSortBy: false, autoResetPage: false, autoResetSelectedRows: false, }, useFilters, useSortBy, usePagination, useRowSelect, (hooks) => { if (rowSelection) { const isIndividualSelection = rowSelection === "individual"; hooks.visibleColumns.push((columns) => [ // Let's make a column for selection { id: "selection", // The header can use the table's getToggleAllRowsSelectedProps method // to render a checkbox // @ts-ignore Header: ({ getToggleAllPageRowsSelectedProps }) => { const props = getToggleAllPageRowsSelectedProps(); return isIndividualSelection ? null : ( <Checkbox onClick={props.onChange} value={props.checked} /> ); }, // The cell can use the individual row's getToggleRowSelectedProps method // to the render a checkbox Cell: ({ row }) => { return ( <Checkbox // @ts-ignore value={row.isSelected} onClick={() => { isIndividualSelection && toggleAllRowsSelected(false); // @ts-ignore row.toggleRowSelected(!row.isSelected); }} /> ); }, }, ...columns, ]); } } ); useEffect(() => { onRowSelectionChange?.(selectedFlatRows); }, [selectedFlatRows, onRowSelectionChange]); return ( <div> {header || filters ? ( <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between", mb: 3, }}> <div>{header}</div> {filters ? ( <Box sx={{ flex: "1", display: "flex", alignItems: "center", justifyContent: "flex-end", }}> {filters.map((f) => { let filter: JSX.Element; switch (f.type) { case "text": filter = ( <TextFilter {...f.props} setFilter={setFilter} currentFilters={currentFilters} /> ); break; case "checkbox": filter = ( <CheckboxFilter {...f.props} setFilter={setFilter} currentFilters={currentFilters} /> ); break; default: return null; } return ( <Box key={`${f.type}-${f.props.columnId}`} sx={{ ":not(:last-of-type)": { mr: 3 } }}> {filter} </Box> ); })} </Box> ) : null} </Box> ) : null} <Box sx={{ overflow: showOverflow ? "visible" : "hidden" }}> <Box sx={{ overflowX: showOverflow ? "visible" : "auto" }}> <Box as="table" {...getTableProps()} sx={{ minWidth: "100%", borderCollapse: "separate", borderSpacing: 0, }}> <thead> {headerGroups.map((headerGroup) => ( <Box as="tr" {...headerGroup.getHeaderGroupProps()} sx={{ borderRadius: "8px" }}> {headerGroup.headers.map((column, i) => { const withHelpTooltip = someColumnCanSort && i === headerGroup.headers.length - 1; return ( <Box as="th" scope="col" {...column.getHeaderProps( // @ts-ignore column.getSortByToggleProps() )} sx={{ textTransform: "uppercase", bg: "rgba(0,0,0,.03)", border: 0, borderBottom: "1px solid", borderTop: "1px solid", borderColor: "muted", fontSize: 0, color: "gray", px: 4, py: 2, fontWeight: 400, position: "relative", "&:first-of-type": { borderLeft: "1px solid", borderColor: "muted", borderTopLeftRadius: 6, borderBottomLeftRadius: 6, }, "&:last-of-type": { borderRight: "1px solid", borderColor: "muted", borderTopRightRadius: 6, borderBottomRightRadius: 6, }, }}> <Box sx={{ display: "flex", alignItems: "center", mr: withHelpTooltip ? 3 : 0, }}> <Box as="span" sx={{ whiteSpace: "nowrap" }}> {column.render("Header")} </Box> {/*@ts-ignore */} {column.canSort && ( <Box as="span" sx={{ ml: 2 }}> {/* @ts-ignore */} {column.isSorted ? // @ts-ignore column.isSortedDesc ? " â£" : " â¡" : " â¥"} </Box> )} </Box> {withHelpTooltip && ( <Box sx={{ alignItems: "center", display: "flex", position: "absolute", right: 3, top: "50%", transform: "translateY(-50%)", }}> <ReactTooltip id={`tooltip-multiorder`} className="tooltip" place="top" type="dark" effect="solid"> To multi-sort (sort by two column simultaneously) hold shift while clicking on second column name. </ReactTooltip> <Help data-tip data-for={`tooltip-multiorder`} sx={{ cursor: "pointer", ml: 1, }} /> </Box> )} </Box> ); })} </Box> ))} </thead> <tbody {...getTableBodyProps()}> {page.map((row: Row<object>) => { prepareRow(row); return ( <tr {...row.getRowProps()}> {row.cells.map((cell) => ( <Box as="td" {...cell.getCellProps()} sx={{ px: 4, py: 3, border: 0, borderBottom: "1px solid", borderBottomColor: "muted", bg: "background", fontSize: 1, }}> {cell.render("Cell")} </Box> ))} </tr> ); })} </tbody> </Box> </Box> <Paginator canPreviousPage={canPreviousPage} canNextPage={canNextPage} onPreviousPage={previousPage} onNextPage={nextPage} /> </Box> </div> ); }
Example #6
Source File: index.tsx From platform with MIT License | 4 votes |
function Table({ columns, data, searchPlaceholder = "games...", colour = "bg-teal-700" }) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
page,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
state,
preGlobalFilteredRows,
setGlobalFilter,
} = useTable(
{
columns,
data,
initialState: {
hiddenColumns: [
"id",
"whiteMemberId",
"blackMemberId",
"liChessUrl",
"chesscomUrl",
"eventId",
"formArray",
"bulletDiff",
"blitzDiff",
"rapidDiff",
"isOnline",
"standardChange",
"rapidChange"
]
}
},
useFilters,
useGlobalFilter,
useSortBy,
usePagination
);
return (
<>
<div className="sm:gap-x-2">
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={state.globalFilter}
setGlobalFilter={setGlobalFilter}
searchPlaceholder={searchPlaceholder}
/>
{headerGroups.map((headerGroup) =>
headerGroup.headers.map((column) =>
column.Filter ? (
<div className="mt-0" key={column.id}>
{column.render("Filter")}
</div>
) : null
)
)}
</div>
{/* table */}
<div className="relative mt-4 sm:flex sm:flex-col">
<div className="overflow-auto w-full shadow border-b border-gray-200 rounded-lg">
<table
{...getTableProps()}
className="w-full table-auto divide-y divide-gray-200"
>
<thead className="">
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th
scope="col"
className={classNames(colour, "group px-2 py-3 text-center text-xs font-medium text-gray-100 uppercase")}
{...column.getHeaderProps(column.getSortByToggleProps())}
>
<div className=" flex items-center text-center justify-between">
{column.render("Header")}
{/* Add a sort direction indicator */}
<span>
{column.isSorted ? (
column.isSortedDesc ? (
<SortDownIcon className="w-4 h-4 text-gray-200" />
) : (
<SortUpIcon className="w-4 h-4 text-gray-200" />
)
) : (
<SortIcon className="w-4 h-4 text-gray-400 opacity-0 group-hover:opacity-100" />
)}
</span>
</div>
</th>
))}
</tr>
))}
</thead>
<tbody
{...getTableBodyProps()}
className="bg-white divide-y divide-gray-200"
>
{page.map((row, i) => {
// new
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td
{...cell.getCellProps()}
className="py-4 px-2 whitespace-nowrap"
role="cell"
>
{cell.column.Cell.name === "defaultRenderer" ? (
<div className="text-sm text-gray-500">
{cell.render("Cell")}
</div>
) : (
cell.render("Cell")
)}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</div>
</div>
{/* Pagination */}
<div className="py-3 flex items-center justify-between">
<div className="flex-1 flex items-center justify-between">
<div className="flex gap-x-2 items-baseline">
<span className="text-xs text-gray-700">
Page <span className="font-medium">{state.pageIndex + 1}</span> of{" "}
<span className="font-medium">{pageOptions.length}</span>
</span>
<label>
<span className="sr-only">Items Per Page</span>
<select
className="mt-1 block w-full text-xs rounded-md border-gray-300 shadow-sm focus:border-teal-300 focus:ring focus:ring-teal-500 focus:ring-opacity-50"
value={state.pageSize}
onChange={(e) => {
setPageSize(Number(e.target.value));
}}
>
{[5, 10, 20].map((pageSize) => (
<option
className="hover:bg-teal-200"
key={pageSize}
value={pageSize}
>
Show {pageSize}
</option>
))}
</select>
</label>
</div>
<div>
<nav
className="relative mt-1 sm:mt-0 z-0 inline-flex rounded-md shadow-sm -space-x-px"
aria-label="Pagination"
>
<PageButton
className="rounded-l-md -mr-1 hidden sm:block"
onClick={() => gotoPage(0)}
disabled={!canPreviousPage}
>
<span className="sr-only">First</span>
<ChevronDoubleLeftIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</PageButton>
<PageButton
className="rounded-l-md sm:rounded-none"
onClick={() => previousPage()}
disabled={!canPreviousPage}
>
<span className="sr-only">Previous</span>
<ChevronLeftIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</PageButton>
<PageButton
className="rounded-r-md sm:rounded-none"
onClick={() => nextPage()}
disabled={!canNextPage}
>
<span className="sr-only">Next</span>
<ChevronRightIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</PageButton>
<PageButton
className="rounded-r-md hidden sm:block"
onClick={() => gotoPage(pageCount - 1)}
disabled={!canNextPage}
>
<span className="sr-only">Last</span>
<ChevronDoubleRightIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</PageButton>
</nav>
</div>
</div>
</div>
</>
);
}
Example #7
Source File: ProposalTable.tsx From mysterium-vpn-desktop with MIT License | 4 votes |
Table: React.FC<TableProps> = observer(function Table({ columns, data }) {
const { proposals, filters } = useStores()
const defaultColumn = React.useMemo(
() => ({
width: 50,
}),
[],
)
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow, setHiddenColumns, state } =
useTable<UIProposal>(
{
columns,
data,
defaultColumn,
autoResetSortBy: false,
initialState: {
sortBy: [{ id: "countryName" }, { id: "qualityLevel", desc: true }],
hiddenColumns: filters.country == null ? hiddenColsAllCountries : hiddenColsSingleCountry,
},
},
useBlockLayout,
useSortBy,
)
useEffect(() => {
if (filters.country == null) {
if (state.hiddenColumns != hiddenColsAllCountries) {
setHiddenColumns(hiddenColsAllCountries)
}
} else {
if (state.hiddenColumns != hiddenColsSingleCountry) {
setHiddenColumns(hiddenColsSingleCountry)
}
}
}, [filters.country])
const listRef = useRef<FixedSizeList>(null)
useEffect(() => {
if (proposals.suggestion) {
const idx = rows.findIndex((row) => row.original.providerId === proposals.suggestion?.providerId)
if (idx != -1) {
listRef.current?.scrollToItem(idx, "center")
}
}
}, [proposals.suggestion, data])
const renderRow = React.useCallback(
({ index, style }: { index: number; style: CSSProperties }): JSX.Element => {
return <RowRenderer prepareRow={prepareRow} rows={rows} index={index} style={style} />
},
[prepareRow, rows],
)
return (
<div className="table" {...getTableProps()}>
<div className="thead">
{headerGroups.map((headerGroup) => {
const { style, key, ...restHeaderGroupProps } = headerGroup.getHeaderGroupProps()
return (
<div key={key} className="tr" style={{ ...style, width: "100%" }} {...restHeaderGroupProps}>
{headerGroup.headers.map((column) => {
const { key, ...restHeaderProps } = column.getHeaderProps(
column.getSortByToggleProps({
title: column.canSort ? `Sort by ${column.Header}` : undefined,
}),
)
return (
<div
key={key}
className={`th ${
column.isSorted ? (column.isSortedDesc ? "sorted-desc" : "sorted-asc") : ""
}`}
{...restHeaderProps}
>
{column.render("Header")}
</div>
)
})}
</div>
)
})}
</div>
<div className="tbody" {...getTableBodyProps()}>
<AutoSizer>
{({ width, height }): JSX.Element => (
<FixedSizeList
itemCount={data.length}
itemSize={30}
width={width}
height={height}
ref={listRef}
>
{renderRow}
</FixedSizeList>
)}
</AutoSizer>
</div>
</div>
)
})
Example #8
Source File: selectable-table.tsx From admin with MIT License | 4 votes |
SelectableTable = < T extends | Product | CustomerGroup | ProductCollection | ProductTag | ProductType >({ label, resourceName = "", selectedIds = [], isLoading, totalCount = 0, data, columns, onChange, options, renderRow, renderHeaderGroup, setQuery, queryObject, paginate, }: SelectableTableProps<T>) => { const table = useTable<T>( { columns, data: data || [], manualPagination: true, initialState: { pageIndex: queryObject.offset / queryObject.limit, pageSize: queryObject.limit, selectedRowIds: selectedIds.reduce((prev, id) => { prev[id] = true return prev }, {} as Record<string, boolean>), }, pageCount: Math.ceil(totalCount / queryObject.limit), autoResetSelectedRows: false, autoResetPage: false, getRowId: (row: any) => row.id, }, useSortBy, usePagination, useRowSelect, useSelectionColumn ) useEffect(() => { onChange(Object.keys(table.state.selectedRowIds)) }, [table.state.selectedRowIds]) const handleNext = () => { if (!table.canNextPage) { return } paginate(1) table.nextPage() } const handlePrev = () => { if (!table.canPreviousPage) { return } paginate(-1) table.previousPage() } const handleSearch = (text: string) => { setQuery(text) if (text) { table.gotoPage(0) } } const debouncedSearch = React.useMemo(() => debounce(handleSearch, 300), []) return ( <div> <div className="inter-base-semibold my-large">{label}</div> <Table {...options} {...table.getTableProps()} handleSearch={options.enableSearch ? debouncedSearch : undefined} > {renderHeaderGroup && ( <Table.Head> {table.headerGroups?.map((headerGroup) => renderHeaderGroup({ headerGroup }) )} </Table.Head> )} <Table.Body {...table.getTableBodyProps()}> {isLoading ? ( <Spinner size="large" /> ) : ( table.rows.map((row) => { table.prepareRow(row) return renderRow({ row }) }) )} </Table.Body> </Table> <TablePagination count={totalCount!} limit={queryObject.limit} offset={queryObject.offset} pageSize={queryObject.offset + table.rows.length} title={resourceName} currentPage={table.state.pageIndex + 1} pageCount={table.pageCount} nextPage={handleNext} prevPage={handlePrev} hasNext={table.canNextPage} hasPrev={table.canPreviousPage} /> </div> ) }
Example #9
Source File: index.tsx From admin with MIT License | 4 votes |
SelectableTable = < T extends Product | CustomerGroup | ProductCollection | ProductTag >({ label, resourceName = "", selectedIds = [], isLoading, totalCount = 0, data, columns, onChange, options, renderRow, renderHeaderGroup, setQuery, queryObject, paginate, }: SelectableTableProps<T>) => { const table = useTable<T>( { columns, data: data || [], manualPagination: true, initialState: { pageIndex: queryObject.offset / queryObject.limit, pageSize: queryObject.limit, selectedRowIds: selectedIds.reduce((prev, id) => { prev[id] = true return prev }, {} as Record<string, boolean>), }, pageCount: Math.ceil(totalCount / queryObject.limit), autoResetSelectedRows: false, autoResetPage: false, getRowId: (row: any) => row.id, }, useSortBy, usePagination, useRowSelect, useSelectionColumn ) useEffect(() => { if (onChange) { onChange(Object.keys(table.state.selectedRowIds)) } }, [table.state.selectedRowIds]) const handleNext = () => { if (!table.canNextPage) { return } paginate(1) table.nextPage() } const handlePrev = () => { if (!table.canPreviousPage) { return } paginate(-1) table.previousPage() } const handleSearch = (text: string) => { setQuery(text) if (text) { table.gotoPage(0) } } const debouncedSearch = React.useMemo(() => debounce(handleSearch, 300), []) return ( <div> {label && <div className="inter-base-semibold my-large">{label}</div>} <Table {...options} {...table.getTableProps()} handleSearch={options.enableSearch ? debouncedSearch : undefined} > {renderHeaderGroup && ( <Table.Head> {table.headerGroups?.map((headerGroup) => renderHeaderGroup({ headerGroup }) )} </Table.Head> )} <Table.Body {...table.getTableBodyProps()}> {isLoading ? ( <Spinner size="large" /> ) : ( table.rows.map((row, i) => { table.prepareRow(row) return renderRow({ row }) }) )} </Table.Body> </Table> <TablePagination count={totalCount!} limit={queryObject.limit} offset={queryObject.offset} pageSize={queryObject.offset + table.rows.length} title={resourceName} currentPage={table.state.pageIndex + 1} pageCount={table.pageCount} nextPage={handleNext} prevPage={handlePrev} hasNext={table.canNextPage} hasPrev={table.canPreviousPage} /> </div> ) }
Example #10
Source File: price-list-table.tsx From admin with MIT License | 4 votes |
/*
* Root component of the price lists table.
*/
export function PriceListTable(props: PriceListTableProps) {
const {
priceLists,
queryObject,
count,
paginate,
setQuery,
columns,
options,
} = props
const tableConfig: TableOptions<PriceList> = {
columns: columns,
data: priceLists || [],
initialState: {
pageSize: queryObject.limit,
pageIndex: queryObject.offset / queryObject.limit,
},
pageCount: Math.ceil(count / queryObject.limit),
manualPagination: true,
autoResetPage: false,
}
const table = useTable(tableConfig, useSortBy, usePagination, useRowSelect)
// ********* HANDLERS *********
const handleNext = () => {
if (!table.canNextPage) {
return
}
paginate(1)
table.nextPage()
}
const handlePrev = () => {
if (!table.canPreviousPage) {
return
}
paginate(-1)
table.previousPage()
}
const handleSearch = (text: string) => {
setQuery(text)
if (text) {
table.gotoPage(0)
}
}
const debouncedSearch = React.useMemo(() => debounce(handleSearch, 300), [])
// ********* RENDER *********
return (
<>
<Table
{...table.getTableProps()}
{...options}
enableSearch={options.enableSearch}
handleSearch={options.enableSearch ? debouncedSearch : undefined}
filteringOptions={options.filter}
>
{/* HEAD */}
<Table.Head>
{table.headerGroups?.map((headerGroup, ind) => (
<PriceListTableHeaderRow key={ind} headerGroup={headerGroup} />
))}
</Table.Head>
{/* BODY */}
<Table.Body {...table.getTableBodyProps()}>
{table.rows.map((row) => {
table.prepareRow(row)
return <PriceListTableRow row={row} />
})}
</Table.Body>
</Table>
{/* PAGINATION */}
<TablePagination
count={count}
limit={queryObject.limit}
offset={queryObject.offset}
pageSize={queryObject.offset + table.rows.length}
title="Price Lists"
currentPage={table.state.pageIndex + 1}
pageCount={table.pageCount}
nextPage={handleNext}
prevPage={handlePrev}
hasNext={table.canNextPage}
hasPrev={table.canPreviousPage}
/>
</>
)
}
Example #11
Source File: customers-list-table.tsx From admin with MIT License | 4 votes |
/*
* Render a list of customers that belong to a customer group.
*/
function CustomersListTable(props: CustomersListTableProps) {
const {
customers,
removeCustomers,
setQuery,
paginate,
filteringOptions,
query,
queryObject,
count,
} = props
const tableConfig = {
data: customers,
columns: CUSTOMER_GROUPS_CUSTOMERS_LIST_TABLE_COLUMNS,
initialState: {
pageSize: queryObject.limit,
pageIndex: queryObject.offset / queryObject.limit,
},
pageCount: Math.ceil(count / queryObject.limit),
manualPagination: true,
autoResetPage: false,
}
const table = useTable(tableConfig, useSortBy, usePagination)
// ********* HANDLERS *********
const handleNext = () => {
if (!table.canNextPage) {
return
}
paginate(1)
table.nextPage()
}
const handlePrev = () => {
if (!table.canPreviousPage) {
return
}
paginate(-1)
table.previousPage()
}
const handleSearch = (text: string) => {
setQuery(text)
if (text) {
table.gotoPage(0)
}
}
return (
<>
<Table
enableSearch
handleSearch={handleSearch}
searchValue={query}
filteringOptions={filteringOptions}
{...table.getTableProps()}
>
<Table.Head>
{table.headerGroups?.map((headerGroup, index) => (
<CustomersListTableHeaderRow
key={index}
headerGroup={headerGroup}
/>
))}
</Table.Head>
<Table.Body {...table.getTableBodyProps()}>
{table.rows.map((row) => {
table.prepareRow(row)
return (
<CustomersListTableRow
row={row}
key={row.id}
removeCustomers={removeCustomers}
/>
)
})}
</Table.Body>
</Table>
<TablePagination
count={count!}
limit={queryObject.limit}
offset={queryObject.offset}
pageSize={queryObject.offset + table.rows.length}
title="Customers"
currentPage={table.state.pageIndex + 1}
pageCount={table.pageCount}
nextPage={handleNext}
prevPage={handlePrev}
hasNext={table.canNextPage}
hasPrev={table.canPreviousPage}
/>
</>
)
}
Example #12
Source File: customer-groups-table.tsx From admin with MIT License | 4 votes |
/*
* Root component of the customer groups table.
*/
function CustomerGroupsTable(props: CustomerGroupsTableProps) {
const { customerGroups, queryObject, count, paginate, setQuery } = props
const tableConfig: TableOptions<CustomerGroup> = {
columns: CUSTOMER_GROUPS_TABLE_COLUMNS,
data: customerGroups || [],
initialState: {
pageSize: queryObject.limit,
pageIndex: queryObject.offset / queryObject.limit,
},
pageCount: Math.ceil(count / queryObject.limit),
manualPagination: true,
autoResetPage: false,
}
const table: TableInstance<CustomerGroup> = useTable(
tableConfig,
useSortBy,
usePagination
)
// ********* HANDLERS *********
const handleNext = () => {
if (!table.canNextPage) {
return
}
paginate(1)
table.nextPage()
}
const handlePrev = () => {
if (!table.canPreviousPage) {
return
}
paginate(-1)
table.previousPage()
}
const handleSearch = (text: string) => {
setQuery(text)
if (text) {
table.gotoPage(0)
}
}
// ********* RENDER *********
return (
<div className="w-full h-full overflow-y-auto flex flex-col justify-between">
<Table
enableSearch
handleSearch={handleSearch}
searchValue={queryObject.q}
{...table.getTableProps()}
>
{/* HEAD */}
<Table.Head>
{table.headerGroups?.map((headerGroup, ind) => (
<CustomerGroupsTableHeaderRow key={ind} headerGroup={headerGroup} />
))}
</Table.Head>
{/* BODY */}
<Table.Body {...table.getTableBodyProps()}>
{table.rows.map((row) => {
table.prepareRow(row)
return (
<CustomerGroupContextContainer key={row.id} group={row.original}>
<CustomerGroupsTableRow row={row} />
</CustomerGroupContextContainer>
)
})}
</Table.Body>
</Table>
{/* PAGINATION */}
<TablePagination
count={count}
limit={queryObject.limit}
offset={queryObject.offset}
pageSize={queryObject.offset + table.rows.length}
title="Customers"
currentPage={table.state.pageIndex + 1}
pageCount={table.pageCount}
nextPage={handleNext}
prevPage={handlePrev}
hasNext={table.canNextPage}
hasPrev={table.canPreviousPage}
/>
</div>
)
}
Example #13
Source File: index.tsx From livepeer-com with MIT License | 4 votes |
DataTableComponent = <T extends Record<string, unknown>>({ columns, header, rowSelection, initialSortBy, filterItems, showOverflow, cursor = "default", stateSetter, state, tableData, selectAction, createAction, emptyState, viewAll, noPagination = false, border = false, tableLayout = "fixed", }: DataTableProps<T>) => { const { isLoading, data } = tableData; const dataMemo = useMemo(() => data?.rows ?? [], [data?.rows]); const someColumnCanSort = useMemo(() => { // To see if we show the sort help tooltip or not // @ts-ignore return columns.some((column) => !column.disableSortBy); }, [columns]); const getRowId = useCallback((row, relativeIndex) => { return row?.id ? row.id : relativeIndex; }, []); const { getTableProps, getTableBodyProps, prepareRow, headerGroups, rows, // @ts-ignore toggleAllRowsSelected, // @ts-ignore selectedFlatRows, // @ts-ignore state: { sortBy }, } = useTable( { // @ts-ignore columns, getRowId, data: dataMemo, initialState: { // @ts-ignore pageSize: state.pageSize, pageIndex: 0, ...(initialSortBy ? { sortBy: initialSortBy } : undefined), }, disableSortBy: !!viewAll, manualSortBy: false, autoResetFilters: false, autoResetSortBy: false, autoResetPage: false, autoResetSelectedRows: false, }, useSortBy, useRowSelect, (hooks) => { if (rowSelection) { const isIndividualSelection = rowSelection === "individual"; hooks.visibleColumns.push((columns) => [ // Let's make a column for selection { id: "selection", // The header can use the table's getToggleAllRowsSelectedProps method // to render a checkbox Header: ({ // @ts-ignore getToggleAllRowsSelectedProps, // @ts-ignore isAllRowsSelected, }) => { if (isIndividualSelection) return null; const props = getToggleAllRowsSelectedProps(); return ( <Checkbox css={{ display: "flex" }} onClick={props.onChange} value="toggle-all" checked={isAllRowsSelected ? true : false} /> ); }, // The cell can use the individual row's getToggleRowSelectedProps method // to the render a checkbox Cell: ({ row }) => { return ( <Checkbox css={{ display: "flex" }} // @ts-ignore value={row.isSelected} // @ts-ignore checked={row.isSelected} onClick={() => { isIndividualSelection && toggleAllRowsSelected(false); // @ts-ignore row.toggleRowSelected(!row.isSelected); }} /> ); }, }, ...columns, ]); } } ); useEffect(() => { stateSetter.setSelectedRows(selectedFlatRows); }, [selectedFlatRows, stateSetter.setSelectedRows]); useEffect(() => { const order = sortBy?.map((o) => `${o.id}-${o.desc}`).join(",") ?? ""; stateSetter.setOrder(order); }, [sortBy, stateSetter.setOrder]); useEffect(() => { stateSetter.setNextCursor(data?.nextCursor); }, [data?.nextCursor, stateSetter.setNextCursor]); const handlePreviousPage = useCallback(() => { stateSetter.setNextCursor(state.cursor); // current cursor will be next const prevCursorsClone = [...state.prevCursors]; const newCursor = prevCursorsClone.pop(); stateSetter.setCursor(newCursor); stateSetter.setPrevCursors([...prevCursorsClone]); }, [ stateSetter.setNextCursor, stateSetter.setCursor, stateSetter.setPrevCursors, state.prevCursors, state.cursor, ]); const handleNextPage = useCallback(() => { stateSetter.setPrevCursors((p) => [...p, state.cursor]); stateSetter.setCursor(state.nextCursor); stateSetter.setNextCursor(""); }, [ stateSetter.setPrevCursors, stateSetter.setCursor, stateSetter.setNextCursor, state.nextCursor, state.cursor, ]); const onSetFilters = (e) => { stateSetter.setCursor(""); stateSetter.setPrevCursors([]); stateSetter.setFilters(e); }; return ( <Box> <Flex align="end" justify="between" css={{ mb: "$3", borderBottom: "1px solid", borderColor: border ? "$neutral5" : "transparent", pb: border ? "$2" : 0, }}> <Box>{header}</Box> <Flex css={{ alignItems: "center" }}> {state.selectedRows.length ? ( <Flex css={{ ai: "center" }}> <Flex css={{ ai: "center", mr: "$3" }}> <Box css={{ fontSize: "$2", color: "$primary9" }}> {state.selectedRows.length} selected </Box> <Box css={{ height: 18, width: "1px", bc: "$primary7", mx: "$3" }} /> <Box css={{ cursor: "pointer", fontSize: "$2", color: "$violet11", }} onClick={() => toggleAllRowsSelected(false)}> Deselect </Box> </Flex> {selectAction && ( <Button size="2" // @ts-ignore css={{ display: "flex", alignItems: "center", }} {...selectAction} /> )} </Flex> ) : ( <> {!viewAll && filterItems && ( <TableFilter items={filterItems} onDone={(e) => onSetFilters(e)} /> )} {createAction && ( <Button variant="primary" size="2" // @ts-ignore css={{ display: "flex", alignItems: "center" }} {...createAction} /> )} </> )} </Flex> </Flex> {isLoading ? ( <Flex align="center" justify="center" css={{ height: "calc(100vh - 400px)" }}> <Spinner /> </Flex> ) : !data?.count ? ( !JSON.parse(state.stringifiedFilters).length ? ( emptyState ) : ( <Flex direction="column" justify="center" css={{ margin: "0 auto", height: "calc(100vh - 400px)", maxWidth: 300, }}> <Heading css={{ fontWeight: 500, mb: "$3" }}> No results found </Heading> <Text variant="gray" css={{ lineHeight: 1.5, mb: "$3" }}> There aren't any results for that query. </Text> </Flex> ) ) : ( <Box css={{ overflow: showOverflow ? "visible" : "hidden" }}> <Box css={{ overflowX: showOverflow ? "visible" : "auto" }}> <Table {...getTableProps()}> <Thead> {headerGroups.map((headerGroup) => ( <Tr {...headerGroup.getHeaderGroupProps()}> {headerGroup.headers.map((column, i) => { const withHelpTooltip = someColumnCanSort && i === headerGroup.headers.length - 1; return ( <Td as={i === 0 ? Th : Td} scope="col" css={{ pl: i === 0 ? "$1" : 0, width: i === 0 && rowSelection === "all" ? "30px" : "auto", }} {...column.getHeaderProps( // @ts-ignore column.getSortByToggleProps() )}> <Flex css={{ ai: "center", mr: withHelpTooltip ? "$3" : 0, }}> <Box css={{ fontSize: "$2", whiteSpace: "nowrap" }}> {column.render("Header")} </Box> {/*@ts-ignore */} {column.canSort && ( <Box css={{ ml: "$2" }}> {/* @ts-ignore */} {column.isSorted ? // @ts-ignore column.isSortedDesc ? " â£" : " â¡" : " â¥"} </Box> )} </Flex> </Td> ); })} </Tr> ))} </Thead> <Tbody {...getTableBodyProps()}> {rows.map((row: Row<object>) => { prepareRow(row); return ( <Tr css={{ "&:hover": { backgroundColor: "$neutral2", cursor, }, }} {...row.getRowProps()}> {row.cells.map((cell, i) => ( <Td as={i === 0 ? Th : Td} css={{ py: 0, width: i === 0 && rowSelection === "all" ? "30px" : "auto", ...cell.value?.css, }} {...cell.getCellProps()}> {cell.value?.href ? ( <Link href={cell.value.href} passHref> <A css={{ textDecoration: "none", py: "$2", pl: i === 0 ? "$1" : 0, display: "block", "&:hover": { textDecoration: "none", }, }}> {cell.render("Cell")} </A> </Link> ) : ( <Box css={{ py: "$2", pl: i === 0 ? "$1" : 0 }}> {cell.render("Cell")} </Box> )} </Td> ))} </Tr> ); })} </Tbody> </Table> </Box> {!noPagination && ( <Flex justify="between" align="center" css={{ mt: "$4", p: "$1" }}> <Text> <b>{data?.count}</b> results </Text> {viewAll ? ( <Link href={viewAll} passHref> <A variant="primary" css={{ display: "flex", ai: "center" }}> <Box>View all</Box> <ArrowRightIcon /> </A> </Link> ) : ( <Flex> <Button css={{ marginRight: "6px" }} onClick={handlePreviousPage} disabled={state.prevCursors.length <= 0}> Previous </Button> <Button onClick={handleNextPage} disabled={ state.nextCursor === "" || // @ts-ignore state.pageSize >= parseFloat(data?.count) }> Next </Button> </Flex> )} </Flex> )} </Box> )} </Box> ); }
Example #14
Source File: StatisticsTable.tsx From camunda-cockpit-plugins with Apache License 2.0 | 4 votes |
StatisticsTable: React.FC<Props> = ({ activities }) => { const columns = React.useMemo( () => [ { Header: 'Activity Name', accessor: 'activityName', Cell: ({ value }: any) => <Clippy value={value}>{value}</Clippy>, }, { Header: 'Instances', accessor: 'instances', Cell: ({ value }: any) => <Clippy value={value}>{value}</Clippy>, }, { Header: 'Total', accessor: 'duration', Cell: ({ value }: any) => <Clippy value={value}>{value}</Clippy>, }, { Header: 'Average', accessor: 'average', Cell: ({ value }: any) => <Clippy value={value}>{value}</Clippy>, }, { Header: 'Median', accessor: 'median', Cell: ({ value }: any) => <Clippy value={value}>{value}</Clippy>, }, ], [] ); const counter = React.useMemo(() => { const counter: Record<string, number> = {}; for (const activity of activities) { const name = activity.activityName; counter[name] = counter[name] ? counter[name] + 1 : 1; } return counter; }, [activities]); const [totals, durations] = React.useMemo(() => { const totals: Record<string, number> = {}; const durations: Record<string, number[]> = {}; for (const activity of activities) { const duration = new Date(activity.endTime).getTime() - new Date(activity.startTime).getTime(); totals[activity.activityName] = totals[activity.activityName] ? totals[activity.activityName] + duration : duration; if (!durations[activity.activityName]) { durations[activity.activityName] = [duration]; } else { durations[activity.activityName].push(duration); } } return [totals, durations]; }, [activities]); const activityNames = React.useMemo(() => { const activityNames = Object.keys(durations); activityNames.sort((a, b) => { if (totals[a] > totals[b]) { return -1; } else if (totals[a] < totals[b]) { return 1; } return 0; }); return activityNames; }, [activities]); const data = React.useMemo( () => activityNames.map((activityName: string) => { durations[activityName].sort((a: number, b: number) => { if (a > b) { return -1; } else if (a < b) { return 1; } return 0; }); return { activityName, instances: counter[activityName], duration: asctime(totals[activityName]), average: asctime(totals[activityName] / counter[activityName]), median: asctime(durations[activityName][Math.floor(durations[activityName].length / 2)]), }; }), [activities] ); const tableInstance = useTable({ columns: columns as any, data }, useSortBy); const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = tableInstance; return ( <table className="cam-table" {...getTableProps()}> <thead> {headerGroups.map(headerGroup => ( <tr {...headerGroup.getHeaderGroupProps()}> {headerGroup.headers.map(column => ( /* @ts-ignore */ <th {...column.getHeaderProps(column.getSortByToggleProps())}> {column.render('Header')} <span style={{ position: 'absolute', fontSize: '125%' }}> { /* @ts-ignore */ column.isSorted ? ( /* @ts-ignore */ column.isSortedDesc ? ( <GoChevronDown style={{ color: '#155cb5' }} /> ) : ( <GoChevronUp style={{ color: '#155cb5' }} /> ) ) : ( <TiMinus style={{ color: '#155cb5' }} /> ) } </span> </th> ))} </tr> ))} </thead> <tbody {...getTableBodyProps()}> {rows.map(row => { prepareRow(row); return ( <tr {...row.getRowProps()}> {row.cells.map(cell => { return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>; })} </tr> ); })} </tbody> </table> ); }
Example #15
Source File: index.tsx From livepeer-com with MIT License | 4 votes |
CommonAdminTable = ({
id,
loading,
onFetchData,
onRowSelected,
setNextCursor,
columns,
data,
nextCursor,
err,
filtersDesc,
rowsPerPage,
initialSortBy = [],
children,
}: CommonAdminTableProps) => {
const [cursor, setCursor] = useState("");
const [prevCursor, setPrevCursor] = useState([]);
const fetchDataDebounced = useAsyncDebounce(({ sortBy, cursor, filters }) => {
let order;
if (sortBy.length) {
order = sortBy.map((o) => `${o.id}-${o.desc}`).join(",");
}
onFetchData({ order, cursor, filters });
}, 1000);
const dm = useMemo(() => data, [data]);
const tableOptions: any = {
columns,
data: dm,
manualFilters: true,
autoResetSortBy: false,
manualSortBy: true,
maxMultiSortColCount: 2,
initialState: { sortBy: initialSortBy },
};
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
selectedFlatRows,
toggleAllRowsSelected,
setFilter,
state: { filters, sortBy },
rows,
}: any = useTable(
tableOptions,
useFilters,
useSortBy,
useRowSelect,
(hooks) => {
hooks.visibleColumns.push((columns) => [
// Let's make a column for selection
{
id: "selection",
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ rows }) => {
return (
<>
<Button
variant="secondarySmall"
disabled={prevCursor.length === 0}
sx={{ margin: 0, padding: "2px", px: "4px" }}
onClick={() => {
setNextCursor(cursor);
setCursor(prevCursor.pop());
setPrevCursor([...prevCursor]);
}}>
â
</Button>
<Button
variant="secondarySmall"
disabled={rows.length < rowsPerPage || nextCursor === ""}
sx={{ margin: 0, ml: 2, padding: "2px", px: "4px" }}
onClick={() => {
prevCursor.push(cursor);
setPrevCursor([...prevCursor]);
setCursor(nextCursor);
setNextCursor("");
}}>
â¢
</Button>
</>
);
},
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<Checkbox
// @ts-ignore
value={row.isSelected}
onClick={(e) => {
toggleAllRowsSelected(false);
// @ts-ignore
row.toggleRowSelected(!row.isSelected);
}}
/>
</div>
),
},
...columns,
]);
}
);
useEffect(() => {
onRowSelected(selectedFlatRows[0]?.original);
}, [selectedFlatRows]);
useEffect(() => {
setPrevCursor([]);
setNextCursor("");
setCursor("");
}, [sortBy, filters]);
useEffect(() => {
fetchDataDebounced({ sortBy, cursor, filters });
}, [sortBy, cursor, filters]);
return (
<Box
id={id}
sx={{
mb: 0,
mt: 0,
}}>
<Flex
sx={{
justifyContent: "flex-start",
alignItems: "baseline",
my: "1em",
}}>
{children}
{filtersDesc.map((fd) => {
if (typeof fd.render === "function") {
return fd.render({
value: (filters.find((o) => o.id === fd.id) || [])[0]?.value,
setValue: (v) => setFilter(fd.id, v),
});
}
return (
<Input
key={fd.id}
sx={{ width: "10em", ml: "1em" }}
label={`${fd.placeholder || fd.id} filter input`}
value={(filters.find((o) => o.id === fd.id) || [])[0]?.value}
onChange={(e) => setFilter(fd.id, e.target.value)}
placeholder={fd.placeholder}></Input>
);
})}
</Flex>
{err && <Box>{err}</Box>}
<Box>
<Box
as="table"
sx={{
display: "table",
width: "100%",
borderCollapse: "inherit",
borderSpacing: "0",
border: 0,
}}
{...getTableProps()}>
<Box as="thead" sx={{ position: "relative" }}>
{headerGroups.map((headerGroup, i) => (
<Box as="tr" key={i} {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column: any, i) => (
<Box
as="th"
sx={{
userSelect: "none",
fontWeight: "normal",
textTransform: "uppercase",
bg: "rgba(0,0,0,.03)",
borderBottom: "1px solid",
borderTop: "1px solid",
borderColor: "muted",
borderLeft: "0px solid",
borderRight: "0px solid",
fontSize: 0,
color: "gray",
py: 2,
"&:first-of-type": {
borderLeft: "1px solid",
borderColor: "muted",
borderTopLeftRadius: 6,
borderBottomLeftRadius: 6,
},
"&:last-of-type": {
borderRight: "1px solid",
borderColor: "muted",
borderTopRightRadius: 6,
borderBottomRightRadius: 6,
},
}}
align="left"
{...column.getHeaderProps(
column.getSortByToggleProps({ title: "" })
)}
key={i}>
<Flex sx={{ mr: "-18px" }}>
{column.render("Header")}
<span>
{column.canSort &&
(column.isSorted
? column.isSortedDesc
? "â£"
: "â¡"
: "â¥")}
</span>
{i === headerGroup.headers.length - 1 && (
<Flex
sx={{ alignItems: "center", ml: "auto", mr: "1em" }}>
<Flex>
<ReactTooltip
id={`tooltip-multiorder`}
className="tooltip"
place="top"
type="dark"
effect="solid">
To multi-sort (sort by two column simultaneously)
hold shift while clicking on second column name.
</ReactTooltip>
<Help
data-tip
data-for={`tooltip-multiorder`}
sx={{
cursor: "pointer",
ml: 1,
}}
/>
</Flex>
</Flex>
)}
</Flex>
</Box>
))}
</Box>
))}
{loading && (
<Box
as="tr"
sx={{
height: "0px",
border: 0,
bg: "transparent !important",
margin: 0,
padding: 0,
}}>
<Box
as="th"
sx={{ border: 0, bg: "transparent", margin: 0, padding: 0 }}
colSpan={1000}>
<Box sx={{ width: "100%", position: "relative" }}>
<Box
sx={{
position: "absolute",
top: "-1px",
left: "6px",
right: "0px",
}}>
<Box
sx={{
backgroundColor: "dodgerblue",
height: "1px",
animation: `${loadingAnim} 3s ease-in-out infinite`,
}}
/>
</Box>
</Box>
</Box>
</Box>
)}
</Box>
<tbody {...getTableBodyProps()}>
{rows.map((row: any, rowIndex) => {
prepareRow(row);
return (
<Box
as="tr"
sx={{
bg: "transparent !important",
}}
{...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<Box
as="td"
sx={{
fontSize: 1,
borderBottomColor: "muted",
borderBottomWidth: "1px",
borderBottomStyle: "solid",
borderTop: "0px solid",
borderLeft: "0px solid",
borderRight: "0px solid",
}}
{...cell.getCellProps()}>
{renderCell(cell)}
</Box>
);
})}
</Box>
);
})}
</tbody>
</Box>
</Box>
</Box>
);
}
Example #16
Source File: index.tsx From polkabtc-ui with Apache License 2.0 | 4 votes |
VaultScoresTable = ({
challengeTime
}: Props): JSX.Element => {
const { polkaBtcLoaded } = useSelector((state: StoreType) => state.general);
const statsApi = usePolkabtcStats();
const [data, setData] = React.useState<PatchedVaultData[]>([]);
const [status, setStatus] = React.useState(STATUSES.IDLE);
const [error, setError] = React.useState<Error | null>(null);
const { t } = useTranslation();
// TODO: should add an abort-controller
React.useEffect(() => {
// TODO: should follow `<AuthenticatedApp />` vs. `<UnauthenticatedApp />` approach
// - (Re: https://kentcdodds.com/blog/authentication-in-react-applications)
if (!polkaBtcLoaded) return;
if (!statsApi) return;
(async () => {
try {
setStatus(STATUSES.PENDING);
const response = await statsApi.getChallengeVaults(challengeTime);
const sortedVaults = response.data.sort((a, b) => b.lifetime_sla - a.lifetime_sla);
const transformedVaults = sortedVaults.map(vault => ({
...vault,
lifetime_sla: Number(vault.lifetime_sla).toFixed(2)
}));
setStatus(STATUSES.RESOLVED);
setData(transformedVaults);
} catch (error) {
setStatus(STATUSES.REJECTED);
setError(error);
}
})();
}, [
polkaBtcLoaded,
challengeTime,
statsApi
]);
const columns = React.useMemo(
() => [
// TODO: should type properly
{
Header: t('leaderboard.account_id'),
accessor: 'id',
Filter: DefaultColumnFilter,
classNames: [
'text-left'
]
},
{
Header: `${t('leaderboard.collateral')} (DOT)`,
accessor: 'collateral',
classNames: [
'text-right'
]
},
{
Header: t('leaderboard.request_issue_count'),
accessor: 'request_issue_count',
classNames: [
'text-right'
]
},
{
Header: t('leaderboard.execute_issue_count'),
accessor: 'execute_issue_count',
classNames: [
'text-right'
]
},
{
Header: t('leaderboard.request_redeem_count'),
accessor: 'request_redeem_count',
classNames: [
'text-right'
]
},
{
Header: t('leaderboard.execute_redeem_count'),
accessor: 'execute_redeem_count',
classNames: [
'text-right'
]
},
{
Header: t('leaderboard.lifetime_sla'),
accessor: 'lifetime_sla',
Filter: NumberRangeColumnFilter,
filter: 'between',
classNames: [
'text-right'
]
}
],
[t]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable(
{
columns,
data
},
useFilters,
useGlobalFilter,
useSortBy
);
if (status === STATUSES.IDLE || status === STATUSES.PENDING) {
return (
<div
className={clsx(
'flex',
'justify-center'
)}>
<EllipsisLoader dotClassName='bg-interlayTreePoppy-400' />
</div>
);
}
if (status === STATUSES.REJECTED && error) {
return (
<ErrorHandler error={error} />
);
}
if (status === STATUSES.RESOLVED) {
// TODO: should optimize re-renders https://kentcdodds.com/blog/optimize-react-re-renders
return (
<InterlayTableContainer>
<InterlayTable {...getTableProps()}>
<InterlayThead>
{headerGroups.map(headerGroup => (
// eslint-disable-next-line react/jsx-key
<InterlayTr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
// eslint-disable-next-line react/jsx-key
<InterlayTh
{...column.getHeaderProps([
{
className: clsx(column.classNames),
style: column.style
},
column.getSortByToggleProps()
])}>
<SortByContainer>
<span>{column.render('Header')}</span>
<SortBy
isSorted={column.isSorted}
isSortedDesc={column.isSortedDesc} />
</SortByContainer>
{column.canFilter && column.Filter && (
<div>{column.render('Filter', { placeholder: 'Search by Account ID' })}</div>
)}
</InterlayTh>
))}
</InterlayTr>
))}
</InterlayThead>
<InterlayTbody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row);
return (
// eslint-disable-next-line react/jsx-key
<InterlayTr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
// eslint-disable-next-line react/jsx-key
<InterlayTd
{...cell.getCellProps([
{
className: clsx(cell.column.classNames),
style: cell.column.style
}
])}>
{cell.render('Cell')}
</InterlayTd>
);
})}
</InterlayTr>
);
})}
</InterlayTbody>
</InterlayTable>
</InterlayTableContainer>
);
}
return null;
}
Example #17
Source File: index.tsx From polkabtc-ui with Apache License 2.0 | 4 votes |
StakedRelayerScoresTable = ({
challengeTime
}: Props): JSX.Element => {
const { polkaBtcLoaded } = useSelector((state: StoreType) => state.general);
const statsApi = usePolkabtcStats();
const [data, setData] = useState<(PatchedRelayerData)[]>([]);
const [status, setStatus] = useState(STATUSES.IDLE);
const [error, setError] = useState<Error | null>(null);
const { t } = useTranslation();
useEffect(() => {
if (!polkaBtcLoaded) return;
if (!statsApi) return;
(async () => {
try {
setStatus(STATUSES.PENDING);
const response = await statsApi.getRelayers(challengeTime);
const sortedStakedRelayers = response.data.sort((a, b) => b.lifetime_sla - a.lifetime_sla);
const transformedStakedRelayers = sortedStakedRelayers.map(stakedRelayer => ({
...stakedRelayer,
lifetime_sla: Number(stakedRelayer.lifetime_sla).toFixed(2)
}));
setStatus(STATUSES.RESOLVED);
setData(transformedStakedRelayers);
} catch (error) {
setStatus(STATUSES.REJECTED);
setError(error);
}
})();
}, [
polkaBtcLoaded,
challengeTime,
statsApi
]);
const columns = useMemo(
() => [
{
Header: t('leaderboard.account_id'),
accessor: 'id',
Filter: DefaultColumnFilter,
classNames: [
'text-left'
]
},
{
Header: `${t('leaderboard.stake')} (DOT)`,
accessor: 'stake',
classNames: [
'text-right'
],
style: {
minWidth: 120
}
},
{
Header: t('leaderboard.block_count'),
accessor: 'block_count',
classNames: [
'text-right'
]
},
{
Header: t('leaderboard.lifetime_sla'),
accessor: 'lifetime_sla',
Filter: NumberRangeColumnFilter,
filter: 'between',
classNames: [
'text-right'
]
}
],
[t]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable(
{
columns,
data
},
useFilters,
useGlobalFilter,
useSortBy
);
if (status === STATUSES.IDLE || status === STATUSES.PENDING) {
return (
<div
className={clsx(
'flex',
'justify-center'
)}>
<EllipsisLoader dotClassName='bg-interlayTreePoppy-400' />
</div>
);
}
if (status === STATUSES.REJECTED && error) {
return (
<ErrorHandler error={error} />
);
}
if (status === STATUSES.RESOLVED) {
return (
<InterlayTableContainer>
<InterlayTable {...getTableProps()}>
<InterlayThead>
{headerGroups.map(headerGroup => (
// eslint-disable-next-line react/jsx-key
<InterlayTr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
// eslint-disable-next-line react/jsx-key
<InterlayTh
{...column.getHeaderProps([
{
className: clsx(column.classNames),
style: column.style
},
column.getSortByToggleProps()
])}>
<SortByContainer>
<span>{column.render('Header')}</span>
<SortBy
isSorted={column.isSorted}
isSortedDesc={column.isSortedDesc} />
</SortByContainer>
{column.canFilter && column.Filter && (
<div>{column.render('Filter', { placeholder: 'Search by Account ID' })}</div>
)}
</InterlayTh>
))}
</InterlayTr>
))}
</InterlayThead>
<InterlayTbody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row);
return (
// eslint-disable-next-line react/jsx-key
<InterlayTr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
// eslint-disable-next-line react/jsx-key
<InterlayTd
{...cell.getCellProps([
{
className: clsx(cell.column.classNames),
style: cell.column.style
}
])}>
{cell.render('Cell')}
</InterlayTd>
);
})}
</InterlayTr>
);
})}
</InterlayTbody>
</InterlayTable>
</InterlayTableContainer>
);
}
return null;
}
Example #18
Source File: Table.tsx From opensaas with MIT License | 4 votes |
Table: React.FC<TableProps> = <T extends object>(props: TableProps<T>) => { const { expandable, selection, pagination, sortBy, pageCount, data, selectedRowIds, pageSize, rowKey, loading, isMultiSort, renderExpandedComponent, onPageChange, filters: propsFilters, onSortChange: propsOnSortChange, onRowSelected: propsOnRowSelected, onFilterChange: propsOnFilterChange, columns: propsColumns, } = props; const classes = useStyles(); const tableRef = useRef<HTMLTableElement>(null); const hasSortBy = props.hasOwnProperty('sortBy'); const hasFilters = props.hasOwnProperty('filters'); const hasPagination = props.hasOwnProperty('pagination'); const hasOnPageChange = props.hasOwnProperty('onPageChange'); const hasSelectedRowIds = props.hasOwnProperty('selectedRowIds'); const onRowSelected = useCallback( (row: UseRowSelectRowProps<T> & Row<T> & UseTableRowProps<T>, value: boolean) => { const id = (row.original as any)[rowKey]; if (hasSelectedRowIds) { const newSelectedRows: any = { ...selectedRowIds }; if (value) { newSelectedRows[id] = true; } else { delete newSelectedRows[id]; } propsOnRowSelected?.(newSelectedRows); } else { row.toggleRowSelected(value); } }, [hasSelectedRowIds, rowKey, selectedRowIds, propsOnRowSelected], ); const columns = useMemo(() => { const columns = propsColumns.map( ({ sortable, Filter, Header, ...rest }) => ({ ...rest, disableSortBy: !sortable, disableFilters: !Filter, Filter, Header: Header ?? <div style={{ minWidth: rest.minWidth, maxWidth: rest.maxWidth }} />, } as TableColumnOptions<T>), ); if (expandable) { columns.unshift({ id: 'expander', minWidth: 60, maxWidth: '60px' as any, Cell: (cell: UseTableCellProps<T>) => { const row = cell.row as Row<T> & UseExpandedRowProps<T>; return ( <IconButton className={classes.expandIcon} {...row.getToggleRowExpandedProps()}> {row.isExpanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} </IconButton> ); }, }); } if (selection) { columns.unshift({ id: 'selection', minWidth: 60, maxWidth: '60px' as any, Cell: (cell: UseTableCellProps<T>) => { const row = cell.row as UseRowSelectRowProps<T> & Row<T> & UseTableRowProps<T>; return ( <Checkbox className={classes.checkBox} {...row.getToggleRowSelectedProps()} checked={row.isSelected} onChange={(e) => onRowSelected(row, e.target.checked)} /> ); }, }); } return columns as Column<T>[]; }, [propsColumns, expandable, classes, selection, onRowSelected]); const tableHooks: PluginHook<T>[] = [useFilters, useSortBy]; if (expandable) { tableHooks.push(useExpanded); } if (pagination) { tableHooks.push(usePagination); } if (selection) { tableHooks.push(useRowSelect); } tableHooks.push(useFlexLayout); const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow, state, page, pageOptions, gotoPage, nextPage, previousPage, toggleAllRowsSelected, isAllRowsSelected, selectedFlatRows, } = useTable( { columns, data, getRowId: (row: any) => row[rowKey], manualSortBy: !!propsOnSortChange, manualFilters: !!propsOnFilterChange, manualPagination: !!onPageChange, manualRowSelectedKey: rowKey, pageCount: pageCount ?? 0, useControlledState: (state1: any) => ({ ...state1, sortBy: sortBy ?? state1.sortBy, filters: propsFilters ?? state1.filters, selectedRowIds: selectedRowIds ?? state1.selectedRowIds, } as TableState<T> & UseFiltersState<T> & UseSortByState<T> & UseRowSelectState<T>), expandSubRows: false, initialState: { pageIndex: 0, pageSize: pageSize ?? 0, selectedRowIds: selectedRowIds || {}, }, } as UseTableOptions<T> & UseFiltersOptions<T> & UseSortByOptions<T> & UseExpandedOptions<T> & UseRowSelectOptions<T> & UsePaginationOptions<T>, ...tableHooks, ) as TableInstance<T> & UseTableInstanceProps<T> & UsePaginationInstanceProps<T> & UseRowSelectInstanceProps<T>; if (expandable && !renderExpandedComponent) { throw Error('Table: you must provide renderExpandedComponent property if the table is expandable'); } if (hasSortBy && !propsOnSortChange) { throw Error('Table: you must provide onSortChange property if sortBy is controlled'); } if (hasFilters && !propsOnFilterChange) { throw Error('Table: you must provide onFilterChange property if filters is controlled'); } if (hasPagination && !pageSize) { throw Error('Table: you must provide pageSize property if pagination enabled'); } if (hasOnPageChange && !pageCount) { throw Error('Table: you must provide pageCount property if onPageChange is controlled'); } const tableState = state as UseSortByState<T> & UseFiltersState<T> & UsePaginationState<T> & UseRowSelectState<T>; const onSortChange = useCallback( (column: TableColumnProps<T>) => { if (hasSortBy) { const sortBy = isMultiSort ? tableState.sortBy.filter(({ id }) => id !== column.id) : []; if (!column.isSorted) { sortBy.push({ id: column.id, desc: false }); } else if (!column.isSortedDesc) { sortBy.push({ id: column.id, desc: true }); } propsOnSortChange?.(sortBy); } else { if (column.isSorted && column.isSortedDesc) { column.clearSortBy(); } else { column.toggleSortBy(column.isSorted, isMultiSort ?? false); } } }, [hasSortBy, isMultiSort, tableState.sortBy, propsOnSortChange], ); const onFilterChange = useCallback( (column: TableColumnProps<T>, filterValue?: any) => { if (hasFilters) { const filters = tableState.filters.filter(({ id }) => id !== column.id); if (filterValue != null) { filters.push({ id: column.id, value: filterValue }); } propsOnFilterChange?.(filters); } else { column.setFilter(filterValue); } }, [propsOnFilterChange, hasFilters, tableState.filters], ); const onToggleAllRowsSelected = useCallback( (value: boolean) => { if (hasSelectedRowIds) { const selectedIds = data.reduce((p, n: any) => ({ ...p, [n[rowKey]]: true }), {}); propsOnRowSelected?.(value ? selectedIds : {}); } else { toggleAllRowsSelected(value); } }, [hasSelectedRowIds, data, rowKey, propsOnRowSelected, toggleAllRowsSelected], ); useEffect(() => { if (!hasSortBy) propsOnSortChange?.(tableState.sortBy); }, [hasSortBy, propsOnSortChange, tableState.sortBy]); useEffect(() => { if (!hasFilters) propsOnFilterChange?.(tableState.filters); }, [hasFilters, propsOnFilterChange, tableState.filters]); useEffect(() => { tableRef.current?.querySelector('.table-tbody')?.scroll?.({ top: 0, left: 0, behavior: 'smooth' }); onPageChange?.(tableState.pageSize, tableState.pageIndex); }, [onPageChange, tableState.pageSize, tableState.pageIndex]); useEffect(() => { if (!hasSelectedRowIds) propsOnRowSelected?.(tableState.selectedRowIds as any); }, [hasSelectedRowIds, propsOnRowSelected, tableState.selectedRowIds]); const onPageChangeHandler = (page: number) => { if (page > tableState.pageIndex) { nextPage(); } else { previousPage(); } }; return ( <Paper className={classes.paper}> <MaterialUITable className={classes.table} ref={tableRef} {...getTableProps()}> <TableHead headerGroups={headerGroups} onSortChange={onSortChange} onFilterChange={onFilterChange} toggleAllRowsSelected={onToggleAllRowsSelected} isAllRowsSelected={isAllRowsSelected} selectedFlatRows={selectedFlatRows} /> <TableBody getTableBodyProps={getTableBodyProps} prepareRow={prepareRow} loading={loading} rows={(pagination ? page : rows) as (Row<T> & UseExpandedRowProps<T>)[]} renderExpandedComponent={renderExpandedComponent} /> </MaterialUITable> {pagination === 'pages' && ( <TablePagination className={classes.footer} rowsPerPageOptions={[]} component='div' count={rows.length} rowsPerPage={tableState.pageSize} page={tableState.pageIndex} onChangePage={(e, page) => onPageChangeHandler(page)} ActionsComponent={(props) => ( <TablePaginationActions {...props} gotoPage={gotoPage} pageOptions={pageOptions} /> )} /> )} </Paper> ); }
Example #19
Source File: Table.tsx From frontegg-react with MIT License | 4 votes |
Table: FC<TableProps> = <T extends object>(props: TableProps<T>) => { const classes = useStyles(); const tableRef = useRef<HTMLTableElement>(null); const firstRender = useRef<boolean>(true); const columns = useMemo(() => { const columns = props.columns.map( ({ sortable, Filter, Header, ...rest }) => ({ ...rest, disableSortBy: !sortable, disableFilters: !Filter, Filter, Header: Header ?? <div style={{ minWidth: rest.minWidth, maxWidth: rest.maxWidth }} />, } as FeTableColumnOptions<T>) ); if (props.expandable) { columns.unshift({ id: 'fe-expander', minWidth: 60, maxWidth: '60px' as any, Header: <div style={{ minWidth: '1.5rem', maxWidth: '1.5rem' }} />, Cell: (cell: Cell<T>) => { const row = cell.row as Row<T> & UseExpandedRowProps<T>; return ( <IconButton className={classes.expandIcon} {...row.getToggleRowExpandedProps()}> {row.isExpanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} </IconButton> ); }, }); } if (props.selection) { columns.unshift({ id: 'fe-selection', minWidth: 60, maxWidth: '60px' as any, Cell: (cell: Cell<T>) => { const row = cell.row as Row<T> & UseRowSelectRowProps<T>; return ( <Checkbox className={classes.checkBox} {...row.getToggleRowSelectedProps()} checked={row.isSelected} onChange={(e) => onRowSelected(row.original, e.target.checked)} /> ); }, }); } return columns as Column<T>[]; }, [props.columns, props.expandable]); const tableHooks: PluginHook<T>[] = [useFilters, useSortBy]; if (props.expandable) { tableHooks.push(useExpanded); } if (props.pagination) { tableHooks.push(usePagination); } if (props.selection) { tableHooks.push(useRowSelect); } tableHooks.push(useFlexLayout); const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow, state, // The page controls ;) page, // canPreviousPage, // canNextPage, pageOptions, pageCount, gotoPage, nextPage, previousPage, // setPageSize, // select props toggleAllRowsSelected, isAllRowsSelected, selectedFlatRows, toggleRowSelected, } = useTable( { columns, data: props.data, getRowId: (row: any) => row[props.rowKey], manualSortBy: !!props.onSortChange, manualFilters: !!props.onFilterChange, manualPagination: !!props.onPageChange, manualRowSelectedKey: props.rowKey, pageCount: !!props.onPageChange ? props.pageCount : undefined, autoResetPage: !props.onPageChange, useControlledState: (state1: any) => { return { ...state1, sortBy: props.sortBy ?? state1.sortBy, filters: props.filters ?? state1.filters, selectedRowIds: props.selectedRowIds ?? state1.selectedRowIds, } as TableState<T> & UseFiltersState<T> & UseSortByState<T> & UseRowSelectState<T>; }, expandSubRows: false, initialState: { pageIndex: 0, pageSize: props.pageSize ?? 0, selectedRowIds: props.selectedRowIds || {}, }, } as UseTableOptions<T> & UseFiltersOptions<T> & UseSortByOptions<T> & UseExpandedOptions<T> & UseRowSelectOptions<T> & UsePaginationOptions<T>, ...tableHooks ) as TableInstance<T> & UseTableInstanceProps<T> & UsePaginationInstanceProps<T> & UseRowSelectInstanceProps<T>; if (props.expandable && !props.renderExpandedComponent) { throw Error('FeTable: you must provide renderExpandedComponent property if the table is expandable'); } if (props.hasOwnProperty('sortBy') && !props.onSortChange) { throw Error('FeTable: you must provide onSortChange property if sortBy is controlled'); } if (props.hasOwnProperty('filters') && !props.onFilterChange) { throw Error('FeTable: you must provide onFilterChange property if filters is controlled'); } if (props.hasOwnProperty('pagination') && !props.pageSize) { throw Error('FeTable: you must provide pageSize property if pagination enabled'); } if (props.hasOwnProperty('onPageChange') && !props.pageCount) { throw Error('FeTable: you must provide pageCount property if onPageChange is controlled'); } const tableState = state as UseSortByState<T> & UseFiltersState<T> & UsePaginationState<T> & UseRowSelectState<T>; const onSortChange = useCallback( (column: FeTableColumnProps<T>) => { if (props.hasOwnProperty('sortBy')) { const sortBy = props.isMultiSort ? tableState.sortBy.filter(({ id }) => id !== column.id) : []; if (!column.isSorted) { sortBy.push({ id: column.id, desc: false }); } else if (!column.isSortedDesc) { sortBy.push({ id: column.id, desc: true }); } props.onSortChange?.(sortBy); } else { if (column.isSorted && column.isSortedDesc) { column.clearSortBy(); } else { column.toggleSortBy(column.isSorted, props.isMultiSort ?? false); } } }, [props.onSortChange] ); const onFilterChange = useCallback( (column: FeTableColumnProps<T>, filterValue?: any) => { if (props.hasOwnProperty('filters')) { const filters = tableState.filters.filter(({ id }) => id !== column.id); if (filterValue != null) { filters.push({ id: column.id, value: filterValue }); } props.onFilterChange?.(filters); } else { column.setFilter(filterValue); } }, [props.onFilterChange, tableState] ); const onToggleAllRowsSelected = useCallback( (value: boolean) => { if (props.hasOwnProperty('selectedRowIds')) { const selectedIds = props.data.reduce((p, n: any) => ({ ...p, [n[props.rowKey]]: true }), {}); props.onRowSelected?.(value ? selectedIds : {}); } else { toggleAllRowsSelected(value); } }, [props.onRowSelected] ); const onRowSelected = useCallback( (row: any, value: boolean) => { const id = row[props.rowKey]; if (props.hasOwnProperty('selectedRowIds')) { const newSelectedRows: any = { ...props.selectedRowIds }; if (value) { newSelectedRows[id] = true; } else { delete newSelectedRows[id]; } props.onRowSelected?.(newSelectedRows); } else { toggleRowSelected(id, value); } }, [props.onRowSelected] ); const handleOnPageChange = useCallback(() => { if (pagination === 'pages') { tableRef.current?.scroll?.({ top: 0, left: 0, behavior: 'smooth' }); } props.onPageChange?.(tableState.pageSize, tableState.pageIndex); }, [tableState.pageIndex]); useEffect(() => { !props.hasOwnProperty('sortBy') && props.onSortChange?.(tableState.sortBy); }, [props.sortBy, tableState.sortBy]); useEffect(() => { !props.hasOwnProperty('filters') && props.onFilterChange?.(tableState.filters); }, [props.filters, tableState.filters]); useEffect(() => { firstRender.current ? (firstRender.current = false) : handleOnPageChange(); }, [tableState.pageIndex]); useEffect(() => { !props.hasOwnProperty('selectedRowIds') && props.onRowSelected?.(tableState.selectedRowIds as any); }, [tableState.selectedRowIds]); const onPageChangeHandler = (page: number) => { if (page > tableState.pageIndex) { nextPage(); } else { previousPage(); } }; const { className, loading, pagination, totalData, pageSize } = props; return ( <Paper ref={tableRef} className={classes.paper}> <MaUTable className={classNames(classes.table, className)} {...getTableProps()}> <TableHead headerGroups={headerGroups} onSortChange={onSortChange} onFilterChange={onFilterChange} toggleAllRowsSelected={onToggleAllRowsSelected} isAllRowsSelected={isAllRowsSelected} selectedFlatRows={selectedFlatRows} /> <TableBody pageSize={pageSize} pagination={pagination} getTableBodyProps={getTableBodyProps} prepareRow={prepareRow} loading={loading} rows={(pagination ? page : rows) as (Row<T> & UseExpandedRowProps<T>)[]} renderExpandedComponent={props.renderExpandedComponent} onInfiniteScroll={handleOnPageChange} /> </MaUTable> {loading && pagination === 'pages' && rows.length > 0 && <Loader center size={24} />} {pagination === 'pages' && ( <TablePagination className={classes.footer} rowsPerPageOptions={[]} component='div' count={totalData || rows.length} rowsPerPage={tableState.pageSize} page={tableState.pageIndex} onChangePage={(e, page) => onPageChangeHandler(page)} ActionsComponent={(props) => ( <TablePaginationActions {...props} gotoPage={gotoPage} pageOptions={pageOptions} /> )} /> )} </Paper> ); }
Example #20
Source File: AuditLogTable.tsx From camunda-cockpit-plugins with Apache License 2.0 | 4 votes |
AuditLogTable: React.FC<Props> = ({ activities, decisions }) => { const columns = React.useMemo( () => [ { Header: 'Activity Name', accessor: 'activityName', Cell: ({ value }: any) => { const baseUrl = `${window.location.href.split('#')[0]}/` .replace(/\/+$/, '/') .replace(/\/app\/tasklist\//, '/app/cockpit/'); if (value.activityType === 'businessRuleTask' && decisions.has(value.id)) { return <a href={`${baseUrl}#/decision-instance/${decisions.get(value.id)}`}>{value.activityName}</a>; } else if (value.activityType === 'callActivity' && value.calledProcessInstanceId && value.endTime) { return ( <a href={`${baseUrl}#/history/process-instance/${value.calledProcessInstanceId}`}>{value.activityName}</a> ); } else if (value.activityType === 'callActivity' && value.calledProcessInstanceId) { return ( <a href={`${baseUrl}#/process-instance/${value.calledProcessInstanceId}/runtime`}>{value.activityName}</a> ); } return <Clippy value={value.activityName}>{value.activityName}</Clippy>; }, }, { Header: 'Start Time', accessor: 'startDate', Cell: ({ value }: any) => ( <Clippy value={value ? value.format('YYYY-MM-DDTHH:mm:ss') : value}> {value ? value.format('YYYY-MM-DDTHH:mm:ss') : value} </Clippy> ), }, { Header: 'End Time', accessor: 'endDate', Cell: ({ value }: any) => ( <Clippy value={value ? value.format('YYYY-MM-DDTHH:mm:ss') : value}> {value ? value.format('YYYY-MM-DDTHH:mm:ss') : value} </Clippy> ), }, { Header: 'Duration', accessor: 'duration', Cell: ({ value }: any) => <Clippy value={value}>{value}</Clippy>, }, { Header: 'Type', accessor: 'type', Cell: ({ value }: any) => <Clippy value={value}>{value}</Clippy>, }, { Header: 'User', accessor: 'assignee', Cell: ({ value }: any) => <Clippy value={value}>{value}</Clippy>, }, { Header: 'Canceled', accessor: 'canceled', Cell: ({ value }: any) => <Clippy value={value}>{value}</Clippy>, }, ], [activities, decisions] ); const data = React.useMemo( () => activities.map((activity: any) => { return { activityName: activity, startDate: moment(activity.startTime), endDate: activity.endTime ? moment(activity.endTime) : '', duration: activity.endTime ? asctime(new Date(activity.endTime).getTime() - new Date(activity.startTime).getTime()) : '', type: activity.activityType, assignee: activity.assignee, canceled: activity.canceled ? 'true' : 'false', }; }), [activities, decisions] ); const tableInstance = useTable({ columns: columns as any, data }, useSortBy); const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = tableInstance; return ( <table className="cam-table" {...getTableProps()}> <thead> {headerGroups.map(headerGroup => ( <tr {...headerGroup.getHeaderGroupProps()}> {headerGroup.headers.map(column => ( /* @ts-ignore */ <th {...column.getHeaderProps(column.getSortByToggleProps())}> {column.render('Header')} <span style={{ position: 'absolute', fontSize: '125%' }}> { /* @ts-ignore */ column.isSorted ? ( /* @ts-ignore */ column.isSortedDesc ? ( <GoChevronDown style={{ color: '#155cb5' }} /> ) : ( <GoChevronUp style={{ color: '#155cb5' }} /> ) ) : ( <TiMinus style={{ color: '#155cb5' }} /> ) } </span> </th> ))} </tr> ))} </thead> <tbody {...getTableBodyProps()}> {rows.map(row => { prepareRow(row); return ( <tr {...row.getRowProps()}> {row.cells.map(cell => { return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>; })} </tr> ); })} </tbody> </table> ); }
Example #21
Source File: HistoryTable.tsx From camunda-cockpit-plugins with Apache License 2.0 | 4 votes |
HistoryTable: React.FC<Props> = ({ instances }) => { const columns = React.useMemo( () => [ { Header: 'State', accessor: 'state', Cell: ({ value }: any) => <Clippy value={value}>{value}</Clippy>, }, { Header: 'Instance ID', Cell: ({ value }: any) => ( <Clippy value={value}> <a href={`#/history/process-instance/${value}`}>{value}</a> </Clippy> ), accessor: 'id', }, { Header: 'Start Time', accessor: 'startTime', Cell: ({ value }: any) => ( <Clippy value={value ? value.format('YYYY-MM-DDTHH:mm:ss') : value}> {value ? value.format('YYYY-MM-DDTHH:mm:ss') : value} </Clippy> ), }, { Header: 'End Time', accessor: 'endTime', Cell: ({ value }: any) => ( <Clippy value={value ? value.format('YYYY-MM-DDTHH:mm:ss') : value}> {value ? value.format('YYYY-MM-DDTHH:mm:ss') : value} </Clippy> ), }, { Header: 'Business Key', accessor: 'businessKey', Cell: ({ value }: any) => <Clippy value={value}>{value}</Clippy>, }, ], [] ); const data = React.useMemo( () => instances.map((instance: any) => { return { state: instance.state, id: instance.id, businessKey: instance.businessKey, startTime: moment(instance.startTime), endTime: instance.endTime ? moment(instance.endTime) : '', }; }), [instances] ); const tableInstance = useTable({ columns: columns as any, data }, useSortBy); const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = tableInstance; return ( <table className="cam-table" {...getTableProps()}> <thead> {headerGroups.map(headerGroup => ( <tr {...headerGroup.getHeaderGroupProps()}> {headerGroup.headers.map(column => ( /* @ts-ignore */ <th {...column.getHeaderProps(column.getSortByToggleProps())}> {column.render('Header')} <span style={{ position: 'absolute', fontSize: '125%' }}> { /* @ts-ignore */ column.isSorted ? ( /* @ts-ignore */ column.isSortedDesc ? ( <GoChevronDown style={{ color: '#155cb5' }} /> ) : ( <GoChevronUp style={{ color: '#155cb5' }} /> ) ) : ( <TiMinus style={{ color: '#155cb5' }} /> ) } </span> </th> ))} </tr> ))} </thead> <tbody {...getTableBodyProps()}> {rows.map(row => { prepareRow(row); return ( <tr {...row.getRowProps()}> {row.cells.map(cell => { return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>; })} </tr> ); })} </tbody> </table> ); }
Example #22
Source File: VariablesTable.tsx From camunda-cockpit-plugins with Apache License 2.0 | 4 votes |
VariablesTable: React.FC<Props> = ({ instance, activities, variables }) => { const api = useContext(APIContext); const columns = React.useMemo( () => [ { Header: 'Name', accessor: 'name', Cell: ({ value }: any) => <Clippy value={value}>{value}</Clippy>, }, { Header: 'Type', accessor: 'type', }, { Header: 'Value', accessor: 'value', Cell: ({ data, row, value }: any) => { const raw = data[row.index]; switch (raw.type) { case 'Object': return <Modal title={`${raw.name}`} label="View" variable={raw} />; case 'File': return ( <Clippy value={`${window.location.origin}${api.engineApi}/history/variable-instance/${raw.id}/data`}> <a href={`${api.engineApi}/history/variable-instance/${raw.id}/data`}>Download</a> </Clippy> ); case 'Json': return <Modal title={`${raw.name}`} label="View" variable={raw} />; default: return ( <Clippy value={typeof value === 'string' || typeof value === 'number' ? value : JSON.stringify(value)}> {typeof value === 'string' || typeof value === 'number' ? value : JSON.stringify(value)} </Clippy> ); } }, }, { Header: 'Scope', accessor: 'scope', }, { Header: 'Created', accessor: 'createTime', Cell: ({ value }: any) => <Clippy value={value}>{value.split('.')[0]}</Clippy>, }, ], [] ); const data = React.useMemo(() => { return variables .filter( (variable: any) => variable.activityInstanceId === instance.id || !!(activities.has(variable.activityInstanceId) && activities.get(variable.activityInstanceId).activityName) ) .map((variable: any) => { return { ...variable, scope: variable.activityInstanceId === instance.id ? instance.processDefinitionName : activities?.get(variable.activityInstanceId).activityName, }; }); }, [instance, variables, activities]); const tableInstance = useTable({ columns: columns as any, data }, useSortBy); const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = tableInstance; return ( <table className="cam-table" {...getTableProps()}> <thead> {headerGroups.map(headerGroup => ( <tr {...headerGroup.getHeaderGroupProps()}> {headerGroup.headers.map(column => ( /* @ts-ignore */ <th {...column.getHeaderProps(column.getSortByToggleProps())}> {column.render('Header')} <span style={{ position: 'absolute', fontSize: '125%' }}> { /* @ts-ignore */ column.isSorted ? ( /* @ts-ignore */ column.isSortedDesc ? ( <GoChevronDown style={{ color: '#155cb5' }} /> ) : ( <GoChevronUp style={{ color: '#155cb5' }} /> ) ) : ( <TiMinus style={{ color: '#155cb5' }} /> ) } </span> </th> ))} </tr> ))} </thead> <tbody {...getTableBodyProps()}> {rows.map(row => { prepareRow(row); return ( <tr {...row.getRowProps()}> {row.cells.map(cell => { return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>; })} </tr> ); })} </tbody> </table> ); }