react-table#Row TypeScript Examples
The following examples show how to use
react-table#Row.
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: product-table-config.tsx From admin with MIT License | 6 votes |
ProductRow = ({ row }: { row: Row<Product> }) => {
const { isSelected } = row
return (
<Table.Row
{...row.getRowProps()}
className={clsx({ "bg-grey-5": isSelected })}
>
{row.cells.map((cell) => {
return (
<Table.Cell {...cell.getCellProps()}>
{cell.render("Cell")}
</Table.Cell>
)
})}
</Table.Row>
)
}
Example #2
Source File: types.tsx From admin with MIT License | 6 votes |
TypeRow = ({ row }: { row: Row<ProductType> }) => {
return (
<Table.Row {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<Table.Cell {...cell.getCellProps()}>
{cell.render("Cell")}
</Table.Cell>
)
})}
</Table.Row>
)
}
Example #3
Source File: tags.tsx From admin with MIT License | 6 votes |
TagRow = ({ row }: { row: Row<ProductTag> }) => {
return (
<Table.Row {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<Table.Cell {...cell.getCellProps()}>
{cell.render("Cell")}
</Table.Cell>
)
})}
</Table.Row>
)
}
Example #4
Source File: products.tsx From admin with MIT License | 6 votes |
ProductRow = ({ row }: { row: Row<Product> }) => {
return (
<Table.Row {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<Table.Cell {...cell.getCellProps()}>
{cell.render("Cell")}
</Table.Cell>
)
})}
</Table.Row>
)
}
Example #5
Source File: groups.tsx From admin with MIT License | 6 votes |
CustomerGroupsRow = ({ row }: { row: Row<CustomerGroup> }) => {
return (
<Table.Row {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<Table.Cell {...cell.getCellProps()}>
{cell.render("Cell")}
</Table.Cell>
)
})}
</Table.Row>
)
}
Example #6
Source File: index.tsx From ke with MIT License | 6 votes |
mountRows = (rows: Row[], prepareRow: Function): ReactNode => rows.map((row: Row) => { prepareRow(row) return ( // eslint-disable-next-line <TableRow flexDirection="row" {...row.getRowProps()} data-testid="table-row"> {row.cells.map((cell: CellProps) => ( <TableCell key={cell.row.index} justifyContent="flex-start" p={4} {...cell.getCellProps()}> {cell.column.toDetailRoute && cell.column.accessor ? ( <Link to={{ pathname: `${cell.column.toDetailRoute}/${ cell.column.getDetailRouteKey ? cell.column.getDetailRouteKey(cell.row.original) : cell.column.accessor(cell.row.original) }`, }} > {cell.render('Cell')} </Link> ) : ( cell.render('Cell') )} </TableCell> ))} </TableRow> ) })
Example #7
Source File: collection.tsx From admin with MIT License | 6 votes |
CollectionRow = ({ row }: { row: Row<ProductCollection> }) => {
return (
<Table.Row {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<Table.Cell {...cell.getCellProps()}>
{cell.render("Cell")}
</Table.Cell>
)
})}
</Table.Row>
)
}
Example #8
Source File: customer-groups-table.tsx From admin with MIT License | 6 votes |
/*
* Render react-table row for the customer groups table.
*/
function CustomerGroupsTableRow(props: CustomerGroupsTableRowProps) {
const { row } = props
const { showModal } = useContext(CustomerGroupContext)
const actions = [
{
label: "Edit",
onClick: showModal,
icon: <EditIcon size={20} />,
},
{
label: "Details",
onClick: () => navigate(row.original.id),
icon: <DetailsIcon size={20} />,
},
]
return (
<Table.Row
color={"inherit"}
actions={actions}
linkTo={props.row.original.id}
{...props.row.getRowProps()}
>
{props.row.cells.map((cell, index) => (
<Table.Cell {...cell.getCellProps()}>
{cell.render("Cell", { index })}
</Table.Cell>
))}
</Table.Row>
)
}
Example #9
Source File: body.component.spec.tsx From master-frontend-lemoncode with MIT License | 6 votes |
describe('common/table/BodyComponent', () => {
it('should render as expected', () => {
// Arrange
const TestRowComponent: React.FunctionComponent<RowRendererProps<
any
>> = props => (
<RowComponent>
<CellComponent>{props.row.testRow}</CellComponent>
</RowComponent>
);
const props = {
rows: ([
{ getRowProps: jest.fn(), original: { testRow: 1 } },
{ getRowProps: jest.fn(), original: { testRow: 2 } },
{ getRowProps: jest.fn(), original: { testRow: 3 } },
] as unknown) as Row[],
rowRenderer: TestRowComponent,
prepareRow: jest.fn(),
};
// Act
const { getByText } = render(<BodyComponent {...props} />);
// Assert
expect(getByText('1')).toBeInTheDocument();
expect(getByText('2')).toBeInTheDocument();
expect(getByText('3')).toBeInTheDocument();
});
});
Example #10
Source File: price-list-table.tsx From admin with MIT License | 6 votes |
/*
* Render react-table row for the price lists table.
*/
function PriceListTableRow(props: PriceListTableRowProps) {
const { row } = props
return (
<Table.Row
color={"inherit"}
linkTo={row.original.id}
id={row.original.id}
className="group"
{...row.getRowProps()}
>
{row.cells.map((cell, index) => cell.render("Cell", { index }))}
</Table.Row>
)
}
Example #11
Source File: edit-customers-table.tsx From admin with MIT License | 6 votes |
/*
* Edit customers table row.
*/
function EditCustomersTableRow(props: EditCustomersTableRowProps) {
return (
<Table.Row
color={"inherit"}
linkTo={`/a/customers/${props.row.original.id}`}
{...props.row.getRowProps()}
>
{props.row.cells.map((cell, index) => (
<Table.Cell {...cell.getCellProps()}>
{cell.render("Cell", { index })}
</Table.Cell>
))}
</Table.Row>
)
}
Example #12
Source File: StatusPage.tsx From solo with MIT License | 5 votes |
StatusPage: React.FC = () => {
const { docs, updateDocuments, pageCount } = useDocumentSet();
const tableColumns = useMemo(createColumns, []);
const renderSubComponent = ({
original: { shipTo, holder, part, statuses }
}: Row<Document>) => (
<>
<DocumentStepper statuses={statuses} />
<DocumentDetails
shipper={holder}
receiver={shipTo}
part={part}
statuses={statuses}
/>
</>
);
const renderPagination = (table: TableInstance<Document>) => (
<Paginator table={table} />
);
const renderFilterControls = ({
setGlobalFilter
}: TableInstance<Document>) => (
<SelectFilterControls options={filterable} onSubmit={setGlobalFilter} />
);
return (
<div className="tablet:margin-x-8 overflow-x-auto">
<Title>Status</Title>
<Table<Document>
columns={tableColumns}
data={docs}
renderSubComponent={renderSubComponent}
renderPagination={renderPagination}
renderFilterControls={renderFilterControls}
fetchData={updateDocuments}
pageCount={pageCount}
/>
</div>
);
}
Example #13
Source File: index.tsx From livepeer-com with MIT License | 5 votes |
useTableState = <T extends Record<string, unknown>>({
tableId,
pageSize = 20,
}: {
tableId: string;
pageSize?: number;
}) => {
const [order, setOrder] = useState("");
const [cursor, setCursor] = useState("");
const [prevCursors, setPrevCursors] = useState<string[]>([]);
const [nextCursor, setNextCursor] = useState("default");
const [filters, setFilters] = useState<TFilter[]>([]);
const [selectedRows, setSelectedRows] = useState<Row<T>[]>([]);
const queryClient = useQueryClient();
const stringifiedFilters = useMemo(() => {
const formatted = formatFiltersForApiRequest(filters);
return JSON.stringify(formatted);
}, [filters]);
const stateSetter: StateSetter<T> = useMemo(
() => ({
setOrder,
setCursor,
setPrevCursors,
setNextCursor,
setFilters,
setSelectedRows,
}),
[]
);
const state: State<T> = useMemo(
() => ({
tableId,
order,
cursor,
prevCursors,
nextCursor,
filters,
stringifiedFilters,
selectedRows,
pageSize,
invalidate: () => queryClient.invalidateQueries(tableId),
}),
[
order,
cursor,
prevCursors,
nextCursor,
filters,
stringifiedFilters,
selectedRows,
pageSize,
queryClient,
tableId,
]
);
return { state, stateSetter };
}
Example #14
Source File: customers-list-table.tsx From admin with MIT License | 5 votes |
/*
* Renders customer group customers list table row.
*/
function CustomersListTableRow(props: CustomersListTableRowProps) {
const { row, removeCustomers } = props
const actions = [
{
label: "Details",
onClick: () => navigate(`/a/customers/${row.original.id}`),
icon: <DetailsIcon size={20} />,
},
// {
// label: "Send an email",
// onClick: () => window.open(`mailto:${row.original.email}`),
// icon: <MailIcon size={20} />,
// },
{
label: "Delete from the group",
variant: "danger",
onClick: () =>
removeCustomers({
customer_ids: [{ id: row.original.id }],
}),
icon: <TrashIcon size={20} />,
},
]
return (
<Table.Row
color={"inherit"}
actions={actions}
linkTo={`/a/customers/${props.row.original.id}`}
{...props.row.getRowProps()}
>
{props.row.cells.map((cell, index) => (
<Table.Cell {...cell.getCellProps()}>
{cell.render("Cell", { index })}
</Table.Cell>
))}
</Table.Row>
)
}
Example #15
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 #16
Source File: DisplayTable.tsx From devex with GNU General Public License v3.0 | 5 votes |
DisplayTable: React.FC<IDisplayTableParams<DsBlockObj | TxBlockObj | TransactionDetails | TransactionStatus>> =
({ columns, data }) => {
const { getTableProps, headerGroups, rows, prepareRow } = useTable<DsBlockObj | TxBlockObj | TransactionDetails | TransactionStatus>({
columns,
data,
})
return (
<div className='display-table'>
<table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup: HeaderGroup<DsBlockObj | TxBlockObj | TransactionDetails | TransactionStatus>) => (
<tr {...headerGroup.getHeaderGroupProps()} key={headerGroup.getHeaderGroupProps().key}>
{headerGroup.headers.map((column) => (
<th
{...column.getHeaderProps()}
key={column.getHeaderProps().key}
id={column.id}
>
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody>
{rows.map((row: Row<DsBlockObj | TxBlockObj | TransactionDetails | TransactionStatus >) => {
prepareRow(row)
return (
<tr {...row.getRowProps()} key={row.getRowProps().key}>
{row.cells.map((cell: Cell<DsBlockObj | TxBlockObj | TransactionDetails | TransactionStatus>) => {
return (
<td {...cell.getCellProps()}
key={cell.getCellProps().key}>
{cell.render('Cell')}
</td>
)
})}
</tr>
);
}
)}
</tbody>
</table>
</div>
);
}
Example #17
Source File: index.tsx From admin with MIT License | 5 votes |
PricesTable = ({ id, selectProduct }: PricesTableProps) => {
const params = useQueryFilters(defaultQueryProps)
const { products, isLoading, count = 0 } = useAdminPriceListProducts(
id,
params.queryObject
)
const columns = usePricesColumns()
return (
<div className="w-full overflow-y-auto flex flex-col justify-between min-h-[300px] h-full ">
<SelectableTable
columns={columns}
data={products || []}
renderRow={({ row }: { row: Row<Product> }) => {
const handleSelect = () => {
selectProduct(row.original)
}
const actions = [
{
label: "Edit prices",
icon: <EditIcon size={20} />,
onClick: handleSelect,
},
{
label: "Remove product",
icon: <CancelIcon size={20} />,
variant: "danger" as const,
onClick: () => {},
},
]
return (
<Table.Row
{...row.getRowProps()}
actions={actions}
onClick={handleSelect}
className="hover:bg-grey-5 hover:cursor-pointer"
>
{row.cells.map((cell) => {
return (
<Table.Cell {...cell.getCellProps()}>
{cell.render("Cell")}
</Table.Cell>
)
})}
</Table.Row>
)
}}
renderHeaderGroup={ProductHeader}
isLoading={isLoading}
totalCount={count}
options={{
enableSearch: false,
searchPlaceholder: "Search by name or SKU...",
}}
{...params}
/>
</div>
)
}
Example #18
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 #19
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 #20
Source File: index.tsx From livepeer-com with MIT License | 4 votes |
StreamsTable = ({ userId, id }: { userId: string; id: string }) => {
const [deleteModal, setDeleteModal] = useState(false);
const [selectedStreams, setSelectedStreams] = useState([]);
const [streams, setStreams] = useState([]);
const { getStreams, deleteStream, deleteStreams, getBroadcasters } = useApi();
useEffect(() => {
async function init() {
const [streams] = await getStreams(userId);
setStreams(streams);
}
init();
}, [userId, deleteModal]);
const close = useCallback(() => {
setDeleteModal(false);
}, []);
const isVisible = usePageVisibility();
useEffect(() => {
if (!isVisible) {
return;
}
const interval = setInterval(async () => {
const [streams] = await getStreams(userId);
setStreams(streams);
}, 5000);
return () => clearInterval(interval);
}, [userId, isVisible]);
const columns: any = useMemo(
() => [
{
Header: "Name",
accessor: "name",
Cell: TextCell,
sortType: (...params: SortTypeArgs) =>
stringSort("original.name.children", ...params),
},
{
Header: "Details",
accessor: "details",
Cell: RenditionsDetailsCell,
disableSortBy: true,
},
{
Header: "Created",
accessor: "created",
Cell: DateCell,
sortType: (...params: SortTypeArgs) =>
dateSort("original.created.date", ...params),
},
{
Header: "Last Active",
accessor: "lastActive",
Cell: DateCell,
sortType: (...params: SortTypeArgs) =>
dateSort("original.lastActive.date", ...params),
},
{
Header: "Status",
accessor: "status",
disableSortBy: true,
},
],
[]
);
const data: StreamsTableData[] = useMemo(() => {
return streams.map((stream) => {
return {
id: stream.id,
name: {
id: stream.id,
children: stream.name,
tooltipChildren: stream.createdByTokenName ? (
<>
Created by token <b>{stream.createdByTokenName}</b>
</>
) : null,
href: `/app/stream/${stream.id}`,
},
details: { stream },
created: { date: new Date(stream.createdAt), fallback: <i>unseen</i> },
lastActive: {
date: new Date(stream.lastSeen),
fallback: <i>unseen</i>,
},
status: stream.isActive ? "Active" : "Idle",
};
});
}, [streams]);
const handleRowSelectionChange = useCallback(
(rows: Row<StreamsTableData>[]) => {
setSelectedStreams(
rows.map((r) => streams.find((s) => s.id === r.original.id))
);
},
[streams]
);
return (
<Container sx={{ mb: 5 }} id={id}>
{deleteModal && selectedStreams.length && (
<DeleteStreamModal
numStreamsToDelete={selectedStreams.length}
streamName={selectedStreams[0].name}
onClose={close}
onDelete={() => {
if (selectedStreams.length === 1) {
deleteStream(selectedStreams[0].id).then(close);
} else if (selectedStreams.length > 1) {
deleteStreams(selectedStreams.map((s) => s.id)).then(close);
}
}}
/>
)}
<Flex sx={{ alignItems: "center", mb: 3 }}>
<Box>
<Link href="/app/stream/new-stream" passHref>
<A variant="buttons.outlineSmall" sx={{ mr: 2 }}>
Create
</A>
</Link>
<Button
variant="primarySmall"
aria-label="Delete Stream button"
disabled={!selectedStreams.length}
onClick={() => selectedStreams.length && setDeleteModal(true)}>
Delete
</Button>
<Box
sx={{
ml: "1.4em",
display: ["none", "none", "none", "inline-block"],
}}>
<b>New beta feature</b>: Record your live streams. Send feedback to
[email protected].
<Box
as="a"
target="_blank"
href="https://livepeer.com/blog/record-every-video-livestream-with-livepeer"
sx={{
display: "inline-block",
ml: "0.2em",
textDecoration: "none",
color: "primary",
cursor: "pointer",
":hover": { textDecoration: "underline" },
}}>
<b>Read more ⬈</b>
</Box>
</Box>
</Box>
</Flex>
<TableV2
columns={columns}
data={data}
rowSelection="all"
onRowSelectionChange={handleRowSelectionChange}
initialSortBy={[{ id: "created", desc: true }]}
/>
</Container>
);
}
Example #21
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 #22
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 #23
Source File: ScanTasksView.tsx From crossfeed with Creative Commons Zero v1.0 Universal | 4 votes |
ScanTasksView: React.FC = () => {
const { apiPost, token } = useAuthContext();
const [scanTasks, setScanTasks] = useState<ScanTask[]>([]);
const [totalResults, setTotalResults] = useState(0);
const [errors, setErrors] = useState<Errors>({});
const killScanTask = async (index: number) => {
try {
const row = scanTasks[index];
await apiPost(`/scan-tasks/${row.id}/kill`, { body: {} });
setScanTasks(
Object.assign([], scanTasks, {
[index]: {
...row,
status: 'failed'
}
})
);
} catch (e) {
setErrors({
global:
e.status === 422 ? 'Unable to kill scan' : e.message ?? e.toString()
});
console.log(e);
}
};
const renderExpanded = (row: Row<ScanTask>) => {
const { original } = row;
return (
<div className={classes.expandedRoot}>
{original.fargateTaskArn && (
<>
<h4>
Logs
{original.fargateTaskArn?.match('.*/(.*)') && (
<a
target="_blank"
rel="noopener noreferrer"
href={`https://us-east-1.console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups/log-group/${process
.env
.REACT_APP_FARGATE_LOG_GROUP!}/log-events/worker$252Fmain$252F${
(original.fargateTaskArn.match('.*/(.*)') || [])[1]
}`}
>
{' '}
(View all on CloudWatch)
</a>
)}
</h4>
<Log
token={token ?? ''}
url={`${process.env.REACT_APP_API_URL}/scan-tasks/${original.id}/logs`}
/>
</>
)}
<h4>Input</h4>
<small>
<pre>{JSON.stringify(JSON.parse(original.input), null, 2)}</pre>
</small>
<h4>Output</h4>
<small>
<pre>{original.output || 'None'}</pre>
</small>
{row.original.status !== 'finished' &&
row.original.status !== 'failed' && (
<>
<h4>Actions</h4>
<a
href="# "
onClick={(e) => {
e.preventDefault();
killScanTask(row.index);
}}
>
Kill
</a>
</>
)}
</div>
);
};
const columns: Column<ScanTask>[] = [
{
Header: 'ID',
accessor: 'id',
Filter: ColumnFilter,
disableSortBy: true,
disableFilters: true
},
{
Header: 'Status',
accessor: 'status',
Filter: selectFilter([
'created',
'queued',
'requested',
'started',
'finished',
'failed'
]),
disableSortBy: true
},
{
Header: 'Name',
id: 'name',
accessor: ({ scan }) => scan?.name,
Filter: selectFilter([
// TODO: sync this with the SCAN_SCHEMA
'censys',
'amass',
'findomain',
'portscanner',
'wappalyzer',
'censysIpv4',
'censysCertificates',
'sslyze',
'searchSync',
'cve',
'dotgov',
'webscraper',
'intrigueIdent',
'shodan',
'hibp',
'lookingGlass',
'dnstwist',
'peCybersixgill',
'peHibpSync',
'peShodan',
'peDomMasq',
'rootDomainSync'
]),
disableSortBy: true
},
{
Header: 'Created At',
id: 'createdAt',
accessor: ({ createdAt }) => dateAccessor(createdAt),
disableFilters: true
},
{
Header: 'Finished At',
id: 'finishedAt',
accessor: ({ finishedAt }) => dateAccessor(finishedAt),
disableFilters: true
},
{
Header: 'Details',
Cell: ({ row }: CellProps<ScanTask>) => (
<span
{...row.getToggleRowExpandedProps()}
className="text-center display-block"
>
{row.isExpanded ? <FaMinus /> : <FaPlus />}
</span>
),
disableFilters: true
}
];
const PAGE_SIZE = 25;
const fetchScanTasks = useCallback(
async (query: Query<ScanTask>) => {
const { page, sort, filters } = query;
try {
const { result, count } = await apiPost<ApiResponse>(
'/scan-tasks/search',
{
body: {
page,
sort: sort[0]?.id ?? 'createdAt',
order: sort[0]?.desc ? 'DESC' : 'ASC',
filters: filters
.filter((f) => Boolean(f.value))
.reduce(
(accum, next) => ({
...accum,
[next.id]: next.value
}),
{}
)
}
}
);
setScanTasks(result);
setTotalResults(count);
} catch (e) {
console.error(e);
}
},
[apiPost]
);
const renderPagination = (table: TableInstance<ScanTask>) => (
<Paginator table={table} totalResults={totalResults} />
);
return (
<>
{errors.global && <p className={classes.error}>{errors.global}</p>}
<Table<ScanTask>
renderPagination={renderPagination}
columns={columns}
data={scanTasks}
pageCount={Math.ceil(totalResults / PAGE_SIZE)}
fetchData={fetchScanTasks}
pageSize={PAGE_SIZE}
initialSortBy={[
{
id: 'createdAt',
desc: true
}
]}
renderExpanded={renderExpanded}
/>
</>
);
}
Example #24
Source File: ViewAllTable.tsx From devex with GNU General Public License v3.0 | 4 votes |
ViewAllTable: React.FC<IViewAllTableParams<DsBlockObj | TxBlockObj | TransactionDetails>> =
({ columns, data, isLoading, fetchData, pageCount: controlledPageCount }) => {
const { getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
page,
canPreviousPage,
canNextPage,
pageCount,
gotoPage,
nextPage,
previousPage,
// Get the state from the instance
state: { pageIndex } } = useTable<DsBlockObj | TxBlockObj | TransactionDetails>({
columns,
data,
initialState: { pageIndex: 0 },
manualPagination: true,
pageCount: controlledPageCount,
}, usePagination)
const fetchDataDebounce = useAsyncDebounce(fetchData, 300)
useEffect(() => {
fetchDataDebounce({ pageIndex })
// fetchDataDebounce changes when fetchData function changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pageIndex, fetchData])
const generatePagination = useCallback((currentPage: number, pageCount: number, delta = 2) => {
const separate = (a: number, b: number, isLower: boolean) => {
const temp = b - a
if (temp === 0)
return [a]
else if (temp === 1)
return [a, b]
else if (temp === 2)
return [a, a + 1, b]
else
return [a, isLower ? -1 : -2, b]
}
return Array(delta * 2 + 1)
.fill(0)
.map((_, index) => currentPage - delta + index)
.filter(page => 0 < page && page <= pageCount)
.flatMap((page, index, { length }) => {
if (!index) {
return separate(1, page, true)
}
if (index === length - 1) {
return separate(page, pageCount, false)
}
return [page]
})
}, [])
return (
<>
<BRow>
<BCol className='align-self-center pl-3'>
{data.length === 0
? null
: <span className='subtext'>Items Per Page: <strong>10</strong></span>}
</BCol>
<BCol>
<Pagination className='justify-content-end'>
<Pagination.Prev onClick={() => previousPage()} disabled={!canPreviousPage} />
{generatePagination(pageIndex + 1, pageCount).map((page) => {
if (page === -1)
return <Pagination.Ellipsis key={page} onClick={() => gotoPage(pageIndex - 5)} />
else if (page === -2)
return <Pagination.Ellipsis key={page} onClick={() => gotoPage(pageIndex + 5)} />
else if (page === pageIndex + 1)
return <Pagination.Item key={page} active>{page}</Pagination.Item>
else
return <Pagination.Item key={page} onClick={() => gotoPage(Number(page) - 1)}>{page}</Pagination.Item>
})}
<Pagination.Next onClick={() => nextPage()} disabled={!canNextPage} />
</Pagination>
</BCol>
</BRow>
<div className='viewall-table table'>
{isLoading ? <div className='center-spinner mt-4'><Spinner animation="border" /></div> : null}
<table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup: HeaderGroup<DsBlockObj | TxBlockObj | TransactionDetails>) => (
<tr {...headerGroup.getHeaderGroupProps()} key={headerGroup.getHeaderGroupProps().key} >
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps()} key={column.getHeaderProps().key} id={column.id}>
{column.render('Header')}
</th>
))}
</tr>
))}
</thead>
<tbody style={isLoading ? { opacity: '0.5' } : {}}{...getTableBodyProps()}>
{page.map((row: Row<DsBlockObj | TxBlockObj | TransactionDetails>) => {
prepareRow(row)
return (
<tr {...row.getRowProps()} key={row.getRowProps().key}>
{row.cells.map((cell: Cell<DsBlockObj | TxBlockObj | TransactionDetails>) => {
return (
<td {...cell.getCellProps()}
key={cell.getCellProps().key}>
{cell.render('Cell')}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
</div>
</>
)
}
Example #25
Source File: TxnsPage.tsx From devex with GNU General Public License v3.0 | 4 votes |
TxnsPage: React.FC = () => {
const networkContext = useContext(NetworkContext)
const { dataService } = networkContext!
const fetchIdRef = useRef(0)
const [isLoading, setIsLoading] = useState(false)
const [pageCount, setPageCount] = useState(0)
const [data, setData] = useState<TransactionDetails[] | null>(null)
const [recentTxnHashes, setRecentTxnHashes] = useState<string[] | null>(null)
const columns = useMemo(
() => [{
id: 'from-col',
Header: 'From',
accessor: 'txn.senderAddress',
Cell: ({ value }: { value: string }) => (
<QueryPreservingLink to={`/address/${hexAddrToZilAddr(value)}`}>
{hexAddrToZilAddr(value)}
</QueryPreservingLink>)
}, {
id: 'to-col',
Header: 'To',
Cell: ({ row }: { row: Row<TransactionDetails> }) => {
return <ToAddrDisp txnDetails={row.original} />
}
}, {
id: 'hash-col',
Header: 'Hash',
accessor: 'hash',
Cell: ({ row }: { row: Row<TransactionDetails> }) => {
console.log(row)
return <QueryPreservingLink to={`/tx/0x${row.original.hash}`}>
<div className='text-right mono'>
{row.original.txn.txParams.receipt && !row.original.txn.txParams.receipt.success
&& <FontAwesomeIcon className='mr-1' icon={faExclamationCircle} color='red' />
}
{'0x' + row.original.hash}
</div>
</QueryPreservingLink>
}
}, {
id: 'amount-col',
Header: 'Amount',
accessor: 'txn.amount',
Cell: ({ value }: { value: string }) => (
<OverlayTrigger placement='right'
overlay={<Tooltip id={'amt-tt'}>{qaToZil(value)}</Tooltip>}>
<div className='text-right sm'>{qaToZil(value, 12)}</div>
</OverlayTrigger>
)
}, {
id: 'fee-col',
Header: 'Fee',
accessor: 'txn',
Cell: ({ value }: { value: Transaction }) => {
const fee = Number(value.txParams.gasPrice) * value.txParams.receipt!.cumulative_gas
return <OverlayTrigger placement='top'
overlay={<Tooltip id={'fee-tt'}>{qaToZil(fee)}</Tooltip>}>
<div className='text-center sm' >{qaToZil(fee, 4)}</div>
</OverlayTrigger>
}
}], []
)
const fetchData = useCallback(({ pageIndex }) => {
if (!dataService) return
const fetchId = ++fetchIdRef.current
let txnHashes: string[] | null
let txnList: TxList
let txnBodies: TransactionDetails[]
const getData = async () => {
try {
setIsLoading(true)
txnHashes = recentTxnHashes
if (!txnHashes) {
txnList = await dataService.getRecentTransactions()
if (!txnList) return
txnHashes = txnList.TxnHashes
setPageCount(Math.ceil(txnList.number / 10))
setRecentTxnHashes(txnHashes)
}
const slicedTxnHashes = txnHashes.slice(pageIndex * 10, pageIndex * 10 + 10)
if (slicedTxnHashes) {
txnBodies = await dataService.getTransactionsDetails(slicedTxnHashes)
if (txnBodies)
setData(txnBodies)
}
} catch (e) {
console.log(e)
} finally {
setIsLoading(false)
}
}
if (fetchId === fetchIdRef.current)
getData()
// Recent transaction hashes is not changed after the initial fetch, until the user refreshes/re-render the component
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dataService])
return (
<>
{<div>
<h2>Recent Transactions</h2>
<ViewAllTable
columns={columns}
data={data ? data : []}
isLoading={isLoading}
fetchData={fetchData}
pageCount={pageCount}
/>
</div>}
</>
)
}
Example #26
Source File: ValTxnList.tsx From devex with GNU General Public License v3.0 | 4 votes |
ValTxnList: React.FC = () => {
const networkContext = useContext(NetworkContext)
const { dataService, networkUrl } = networkContext!
useEffect(() => { setData(null) }, [networkUrl])
const [data, setData] = useState<TransactionDetails[] | null>(null)
const columns = useMemo(
() => [{
id: 'from-col',
Header: 'From',
accessor: 'txn.senderAddress',
Cell: ({ value }: { value: string }) => (
<QueryPreservingLink to={`/address/${hexAddrToZilAddr(value)}`}>
{hexAddrToZilAddr(value)}
</QueryPreservingLink>)
}, {
id: 'to-col',
Header: 'To',
Cell: ({ row }: { row: Row<TransactionDetails> }) => {
return <ToAddrDisp txnDetails={row.original} />
}
}, {
id: 'hash-col',
Header: 'Hash',
accessor: 'hash',
Cell: ({ row }: { row: Row<TransactionDetails> }) => {
return <QueryPreservingLink to={`/tx/0x${row.original.hash}`}>
<div className='text-right mono'>
{row.original.txn.txParams.receipt && !row.original.txn.txParams.receipt.success
&& <FontAwesomeIcon className='mr-1' icon={faExclamationCircle} color='red' />
}
{'0x' + row.original.hash}
</div>
</QueryPreservingLink>
}
}, {
id: 'amount-col',
Header: 'Amount',
accessor: 'txn.amount',
Cell: ({ value }: { value: string }) => (
<OverlayTrigger placement='right'
overlay={<Tooltip id={'amt-tt'}>{qaToZil(value)}</Tooltip>}>
<div className='text-right sm'>{qaToZil(value, 13)}</div>
</OverlayTrigger>
)
}, {
id: 'fee-col',
Header: 'Fee',
accessor: 'txn',
Cell: ({ value }: { value: Transaction }) => {
const fee = Number(value.txParams.gasPrice) * value.txParams.receipt!.cumulative_gas
return <OverlayTrigger placement='top'
overlay={<Tooltip id={'fee-tt'}>{qaToZil(fee)}</Tooltip>}>
<div className='text-center sm'>{qaToZil(fee, 4)}</div>
</OverlayTrigger>
}
}], []
)
// Fetch Data
useEffect(() => {
let isCancelled = false
if (!dataService) return
let receivedData: TransactionDetails[]
const getData = async () => {
try {
receivedData = await dataService.getLatest5ValidatedTransactions()
if (!isCancelled && receivedData)
setData(receivedData)
} catch (e) {
if (!isCancelled)
console.log(e)
}
}
getData()
const getDataTimer = setInterval(async () => {
await getData()
}, refreshRate)
return () => {
isCancelled = true
clearInterval(getDataTimer)
}
}, [networkUrl, dataService])
return <>
<Card className='valtxlist-card'>
<Card.Header>
<div className='valtxlist-card-header'>
<span>Transactions</span>
<QueryPreservingLink to={'/tx'}>View Recent Transactions</QueryPreservingLink>
</div>
</Card.Header>
<Card.Body>
{data
? <DisplayTable columns={columns} data={data} />
: <Spinner animation="border" role="status" />
}
</Card.Body>
</Card>
</>
}
Example #27
Source File: TxBlockDetailsPage.tsx From devex with GNU General Public License v3.0 | 4 votes |
TxBlockDetailsPage: React.FC = () => {
const { blockNum } = useParams()
const networkContext = useContext(NetworkContext)
const { dataService, isIsolatedServer } = networkContext!
const [error, setError] = useState<string | null>(null)
const [isLoading, setIsLoading] = useState(false)
const [isLoadingTrans, setIsLoadingTrans] = useState(false)
const [txBlockObj, setTxBlockObj] = useState<TxBlockObj | null>(null)
const [txBlockTxns, setTxBlockTxns] = useState<string[] | null>(null)
const [latestTxBlockNum, setLatestTxBlockNum] = useState<number | null>(null)
const [transactionData, setTransactionData] = useState<TransactionDetails[] | null>(null)
// Fetch data
useEffect(() => {
setIsLoading(true)
if (!dataService || isIsolatedServer === null) return
let latestTxBlockNum: number
let txBlockObj: TxBlockObj
let txBlockTxns: string[]
const getData = async () => {
try {
if (isNaN(blockNum))
throw new Error('Not a valid block number')
if (isIsolatedServer) {
txBlockTxns = await dataService.getISTransactionsForTxBlock(parseInt(blockNum))
latestTxBlockNum = await dataService.getISBlockNum()
} else {
txBlockObj = await dataService.getTxBlockObj(parseInt(blockNum))
latestTxBlockNum = await dataService.getNumTxBlocks()
try {
txBlockTxns = await dataService.getTransactionsForTxBlock(parseInt(blockNum))
} catch (e) { console.log(e) }
}
if (txBlockObj)
setTxBlockObj(txBlockObj)
if (txBlockTxns)
setTxBlockTxns(txBlockTxns)
if (latestTxBlockNum)
setLatestTxBlockNum(latestTxBlockNum)
} catch (e) {
console.log(e)
setError(e)
} finally {
setIsLoading(false)
}
}
getData()
return () => {
setTxBlockObj(null)
setTxBlockTxns(null)
setLatestTxBlockNum(null)
setError(null)
}
}, [blockNum, dataService, isIsolatedServer])
const columns = useMemo(
() => [{
id: 'from-col',
Header: 'From',
accessor: 'txn.senderAddress',
Cell: ({ value }: { value: string }) => (
<QueryPreservingLink to={`/address/${hexAddrToZilAddr(value)}`}>
{hexAddrToZilAddr(value)}
</QueryPreservingLink>
)
}, {
id: 'to-col',
Header: 'To',
Cell: ({ row }: { row: Row<TransactionDetails> }) => {
return <ToAddrDisp txnDetails={row.original} />
}
}, {
id: 'hash-col',
Header: 'Hash',
Cell: ({ row }: { row: Row<TransactionDetails> }) => {
console.log(row)
return <QueryPreservingLink to={`/tx/0x${row.original.hash}`}>
<div className='text-right mono'>
{row.original.txn.txParams.receipt && !row.original.txn.txParams.receipt.success
&& <FontAwesomeIcon className='mr-1' icon={faExclamationCircle} color='red' />
}
{'0x' + row.original.hash}
</div>
</QueryPreservingLink>
}
}, {
id: 'amount-col',
Header: 'Amount',
accessor: 'txn.amount',
Cell: ({ value }: { value: string }) => (
<OverlayTrigger placement='right'
overlay={<Tooltip id={'amt-tt'}>{qaToZil(value)}</Tooltip>}>
<div className='text-right'>{qaToZil(value, 10)}</div>
</OverlayTrigger>
)
}, {
id: 'fee-col',
Header: 'Fee',
accessor: 'txn',
Cell: ({ value }: { value: Transaction }) => {
const fee = Number(value.txParams.gasPrice) * value.txParams.receipt!.cumulative_gas
return <OverlayTrigger placement='top'
overlay={<Tooltip id={'fee-tt'}>{qaToZil(fee)}</Tooltip>}>
<div className='text-center'>{qaToZil(fee, 4)}</div>
</OverlayTrigger>
}
}], []
)
const fetchData = useCallback(({ pageIndex }) => {
if (!txBlockTxns || !dataService) return
let receivedData: TransactionDetails[]
const getData = async () => {
try {
setIsLoadingTrans(true)
receivedData = await dataService.getTransactionsDetails(txBlockTxns.slice(pageIndex * 10, pageIndex * 10 + 10))
if (receivedData)
setTransactionData(receivedData)
} catch (e) {
console.log(e)
} finally {
setIsLoadingTrans(false)
}
}
getData()
}, [dataService, txBlockTxns])
return <>
{isLoading ? <div className='center-spinner'><Spinner animation="border" /></div> : null}
{error
? <NotFoundPage />
: <>
{latestTxBlockNum &&
<div className={isIsolatedServer ? 'txblock-header mb-3' : 'txblock-header'}>
<h3 className='mb-1'>
<span className='mr-1'>
<FontAwesomeIcon className='fa-icon' icon={faCubes} />
</span>
<span className='ml-2'>
Tx Block
</span>
{' '}
<span className='subtext'>#{blockNum}</span>
<LabelStar type='Tx Block' />
</h3>
<span>
<QueryPreservingLink
className={
isIsolatedServer
? parseInt(blockNum, 10) === 1 ? 'disabled mr-3' : 'mr-3'
: parseInt(blockNum, 10) === 0 ? 'disabled mr-3' : 'mr-3'}
to={`/txbk/${parseInt(blockNum, 10) - 1}`}>
<FontAwesomeIcon size='2x' className='fa-icon' icon={faCaretSquareLeft} />
</QueryPreservingLink>
<QueryPreservingLink
className={
isIsolatedServer
? parseInt(blockNum, 10) === latestTxBlockNum ? 'disabled' : ''
: parseInt(blockNum, 10) === latestTxBlockNum - 1 ? 'disabled' : ''}
to={`/txbk/${parseInt(blockNum, 10) + 1}`}>
<FontAwesomeIcon size='2x' className='fa-icon' icon={faCaretSquareRight} />
</QueryPreservingLink>
</span>
</div>
}
{txBlockObj && (
<>
<div className='subtext'>
<HashDisp hash={'0x' + txBlockObj.body.BlockHash} />
</div>
<Card className='txblock-details-card'>
<Card.Body>
<Container>
<BRow>
<BCol>
<div className='txblock-detail'>
<span>Date:</span>
<span>
{timestampToDisplay(txBlockObj.header.Timestamp)}
{' '}
({timestampToTimeago(txBlockObj.header.Timestamp)})
</span>
</div>
</BCol>
<BCol>
<div className='txblock-detail'>
<span>Transactions:</span>
<span>{txBlockObj.header.NumTxns}</span>
</div>
</BCol>
</BRow>
<BRow>
<BCol>
<div className='txblock-detail'>
<span>Gas Limit:</span>
<span>{txBlockObj.header.GasLimit}</span>
</div>
</BCol>
<BCol>
<div className='txblock-detail'>
<span>Gas Used:</span>
<span>{txBlockObj.header.GasUsed}</span>
</div>
</BCol>
</BRow>
<BRow>
<BCol>
<div className='txblock-detail'>
<span>Txn Fees:</span>
<span>{qaToZil(txBlockObj.header.TxnFees)}</span>
</div>
</BCol>
<BCol>
<div className='txblock-detail'>
<span>Rewards Fees:</span>
<span>{qaToZil(txBlockObj.header.Rewards)}</span>
</div>
</BCol>
</BRow>
<BRow>
<BCol>
<div className='txblock-detail'>
<span>DS Block:</span>
<span><QueryPreservingLink to={`/dsbk/${txBlockObj.header.DSBlockNum}`}>{txBlockObj.header.DSBlockNum}</QueryPreservingLink></span>
</div>
</BCol>
<BCol>
<div className='txblock-detail'>
<span>DS Leader:</span>
<span><QueryPreservingLink to={`/address/${pubKeyToZilAddr(txBlockObj.header.MinerPubKey)}`}>{pubKeyToZilAddr(txBlockObj.header.MinerPubKey)}</QueryPreservingLink></span>
</div>
</BCol>
</BRow>
</Container>
</Card.Body>
</Card>
{txBlockObj.body.MicroBlockInfos.length > 0 && (
<Card className='txblock-details-card mono'>
<Card.Body>
<Container>
<span>Micro Blocks</span>
{txBlockObj.body.MicroBlockInfos
.map((x) => (
<div key={x.MicroBlockHash}>[{x.MicroBlockShardId}] {x.MicroBlockHash}</div>
))}
</Container>
</Card.Body>
</Card>
)}
</>
)}
{txBlockTxns && txBlockTxns.length > 0 && (
<>
<h4>Transactions</h4>
<ViewAllTable
isLoading={isLoadingTrans}
fetchData={fetchData}
pageCount={Math.ceil(txBlockTxns.length / 10)}
columns={columns}
data={transactionData ? transactionData : []} />
</>
)}
</>
}
</>
}
Example #28
Source File: MinerTable.tsx From devex with GNU General Public License v3.0 | 4 votes |
MinerTable: React.FC<IMinerTableParams> = ({ addresses }) => {
const generatePagination = useCallback((currentPage: number, pageCount: number, delta = 1) => {
const separate = (a: number, b: number, isLower: boolean) => {
const temp = b - a
if (temp === 0)
return [a]
else if (temp === 1)
return [a, b]
else if (temp === 2)
return [a, a + 1, b]
else
return [a, isLower ? -1 : -2, b]
}
return Array(delta * 2 + 1)
.fill(0)
.map((_, index) => currentPage - delta + index)
.filter(page => 0 < page && page <= pageCount)
.flatMap((page, index, { length }) => {
if (!index) {
return separate(1, page, true)
}
if (index === length - 1) {
return separate(page, pageCount, false)
}
return [page]
})
}, [])
const columns = useMemo(
() => [{
id: 'address-col',
Header: 'Addresses',
accessor: 'address',
// eslint-disable-next-line react/display-name
Cell: (props: Cell<IMinerObj>) =>
(<>
[{props.row.index}]
{' '}
<QueryPreservingLink to={`/address/${pubKeyToZilAddr(props.value)}`}>{pubKeyToZilAddr(props.value)}</QueryPreservingLink>
</>)
}], []
) as Array<Column<IMinerObj>>
const data = useMemo(() => (addresses.map((x) => ({ address: x })) as IMinerObj[]), [addresses])
const {
getTableProps,
getTableBodyProps,
prepareRow,
page,
canPreviousPage,
canNextPage,
pageCount,
gotoPage,
nextPage,
previousPage,
state: { pageIndex },
} = useTable<IMinerObj>({
columns,
data,
initialState: { pageIndex: 0 },
}, usePagination)
return (
<>
<div className='py-3'>
<table {...getTableProps()}>
<tbody {...getTableBodyProps()}>
{page.map((row: Row<IMinerObj>) => {
prepareRow(row)
return (
<tr {...row.getRowProps()} key={row.getRowProps().key}>
{row.cells.map((cell: Cell<IMinerObj>) => {
return (
<td {...cell.getCellProps()} key={cell.getCellProps().key}>
{cell.render('Cell')}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
</div>
<div className='mx-auto'>
{data.length !== 0 &&
<Pagination className='viewall-pagination'>
<Pagination.Prev onClick={() => previousPage()} disabled={!canPreviousPage} />
{generatePagination(pageIndex + 1, pageCount).map((page) => {
if (page === -1)
return <Pagination.Ellipsis key={page} onClick={() => gotoPage(pageIndex - 5)} />
else if (page === -2)
return <Pagination.Ellipsis key={page} onClick={() => gotoPage(pageIndex + 5)} />
else if (page === pageIndex + 1)
return <Pagination.Item key={page} active>{page}</Pagination.Item>
else
return <Pagination.Item key={page} onClick={() => gotoPage(Number(page) - 1)}>{page}</Pagination.Item>
})}
<Pagination.Next onClick={() => nextPage()} disabled={!canNextPage} />
</Pagination>
}
</div>
</>
)
}