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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
/*
 * 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 vote down vote up
/*
 * 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 vote down vote up
/*
 * 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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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>
  );
}