Skip to content

Commit

Permalink
Merge branch 'enhancement-ItemTable-virtualization' into staging
Browse files Browse the repository at this point in the history
  • Loading branch information
campb303 committed May 5, 2021
2 parents fb00034 + 2d95d14 commit 529f240
Show file tree
Hide file tree
Showing 5 changed files with 14,670 additions and 126 deletions.
38 changes: 32 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
"react-relative-time": "0.0.7",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1",
"react-table": "^7.5.1"
"react-table": "^7.5.1",
"react-virtualized": "^9.22.3",
"react-window": "^1.8.6"
},
"scripts": {
"start:frontend": "react-scripts start",
Expand Down
248 changes: 129 additions & 119 deletions src/components/ItemTable/ItemTable.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React, { useState } from "react";
import React, { memo, useState } from "react";
import PropTypes from "prop-types";
import { useTable, useFilters, useFlexLayout, useSortBy } from "react-table";
import { Table, TableBody, TableCell, TableHead, TableRow, TableContainer, Box, Grid, makeStyles, useTheme } from "@material-ui/core";
import { Table, TableBody, TableCell, TableHead, TableRow, TableContainer, Box, Grid, ButtonGroup, IconButton, makeStyles, useTheme } from "@material-ui/core";
import { ArrowDownward, ArrowUpward } from "@material-ui/icons";
import { useHistory } from "react-router-dom";
import RelativeTime from "react-relative-time";
import ItemTableFilter from "../ItemTableFilter/";
import ItemtTableSortButtons from "../ItemTableSortButtons/";
import { FixedSizeList, areEqual } from 'react-window';
import { AutoSizer } from "react-virtualized";
import ItemTableFilter from "../ItemTableFilter/"
import ItemTableCell from "../ItemTableCell";
import LastUpdatedCell from "../LastUpdatedCell/";
import jester from "./loading-annimation.gif";
Expand Down Expand Up @@ -35,10 +37,12 @@ export default function ItemTable({ data, rowCanBeSelected, loading }) {
backgroundColor: theme.palette.type === 'light' ? theme.palette.grey[50] : theme.palette.grey[700],
},
},
columnBorders: {
borderLeftWidth: "1px",
borderLeftStyle: "solid",
borderColor: theme.palette.type === "light" ? theme.palette.grey[300] : theme.palette.grey[500]
// The AutoSizer and FixedSizeList components create extra div elements within the table body
// that break DOM nesting rules and cause the table body to have a 0px height. These styles
// are a hotfix to force the table body to have height until a better solution is found.
VirtualizedTableStyles: {
height: '82vh !important',
display:"table-row"
},
tableMargin: {
marginTop: theme.spacing(2)
Expand Down Expand Up @@ -96,120 +100,126 @@ export default function ItemTable({ data, rowCanBeSelected, loading }) {

return (
loading
? (
<Box className={classes.loadingAnnimation}>
<img src={jester} alt="Items are loading." />
</Box>
) : (
<TableContainer>
<Table
{...getTableProps}
aria-label="Table of Queue Items"
size="small"
classes={{ root: classes.tableMargin }}
>
<TableHead>
{headerGroups.map(headerGroup => (
<TableRow {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => {
// Determine sort directions
const isSortedAsc = column.isSorted && !column.isSortedDesc;
const isSortedDesc = column.isSorted && column.isSortedDesc;

return (
<Grid container spacing={0}>
<TableCell
{...column.getHeaderProps()}
classes={{ root: classes.tableHeaderPadding }}
>
<Grid container spacing={0}>
<Grid item sm={10} >
{column.render("Filter")}
</Grid>
<Grid item sm={2} alignItems='center' justify='center'>
<ItemtTableSortButtons
sortAscArrowProps={{
...column.getSortByToggleProps(),
onClick: _ => (isSortedAsc ? column.clearSortBy() : column.toggleSortBy(false))
}}
sortDescArrowProps={{
...column.getSortByToggleProps(),
onClick: _ => (isSortedDesc ? column.clearSortBy() : column.toggleSortBy(true))
}}
sortDirection={(_ => {
if (isSortedAsc) {
return 'asc';
}
else if (isSortedDesc) {
return 'desc';
}
else {
return undefined;
}
})()}
/>
</Grid>
? (
<Box className={classes.loadingAnnimation}>
<img src={jester} alt="Items are loading." />
</Box>
)
: (
<TableContainer>
<Table stickyHeader {...getTableProps()} size="small">
<TableHead>
{headerGroups.map(headerGroup => (
<TableRow {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<TableCell {...column.getHeaderProps()}>
<Grid container spacing={0}>
<Grid item sm={10}>
{column.render('Filter')}
</Grid>
</TableCell>
</Grid>
);
})}
</TableRow>
))}
</TableHead>

<TableBody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
let isSelected = selectedRow.queue === row.original.queue && selectedRow.number === row.original.number
return (
<TableRow
hover
onClick={() => {
history.push(`/${row.original.queue}/${row.original.number}`);
setSelectedRow({ queue: row.original.queue, number: row.original.number });
}}
// This functionality should be achieved by using the selected prop and
// overriding the selected class but this applied the secondary color at 0.08% opacity.
// Overridding the root class is a workaround.
classes={{
root: (isSelected && rowCanBeSelected) ? classes.rowSelected : classes.bandedRows,
hover: classes.hoverBackgroundColor
}}
{...row.getRowProps()}
>
{row.cells.map(cell => (
cell.render(_ => {
switch (cell.column.id) {
case "dateReceived":
return (
<ItemTableCell TableCellProps={cell.getCellProps()}>
<RelativeTime value={cell.value} />
</ItemTableCell>
);
case "lastUpdated":
return (
<LastUpdatedCell
time={cell.value}
ItemTableCellProps={cell.getCellProps()}
/>
);
default:
return (
<ItemTableCell TableCellProps={cell.getCellProps()}>
{cell.value}
</ItemTableCell>
);
}
})
<Grid item sm={2} alignItems='center' justify='center'>
<ButtonGroup orientation="vertical" size="small">
<IconButton
size="small"
onClick={(_ => {
const isSortedAsc = column.isSorted && !column.isSortedDesc;
isSortedAsc ? column.clearSortBy() : column.toggleSortBy(false)
})}
>
<ArrowUpward {...column.getSortByToggleProps()}
fontSize="inherit"
color={column.isSorted && column.isSortedDesc === false ? "default" : "disabled"}
/>
</IconButton>
<IconButton
size="small"
onClick={(_ => {
const isSortedDesc = column.isSorted && column.isSortedDesc;
isSortedDesc ? column.clearSortBy() : column.toggleSortBy(true)
})}
>
<ArrowDownward {...column.getSortByToggleProps(column.isSortedDesc)}
fontSize="inherit"
color={column.isSorted && column.isSortedDesc ? "default" : "disabled"}
/>
</IconButton>
</ButtonGroup>
</Grid>
</Grid>
</TableCell>
))}
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
)
))}
</TableHead>

<TableBody {...getTableBodyProps()} classes={{ root: classes.VirtualizedTableStyles }}>
<AutoSizer disableWidth>
{({ height, width }) => (
<FixedSizeList
className="Table"
height={height}
width="100%"
itemCount={rows.length}
itemSize={100}
>
{memo(({ index, style }) => {
const row = rows[index]
prepareRow(row)
let isSelected = selectedRow.queue === row.original.queue && selectedRow.number === row.original.number
return (
<TableRow
hover
onClick={() => {
history.push(`/${row.original.queue}/${row.original.number}`);
setSelectedRow({ queue: row.original.queue, number: row.original.number });
}}
// This functionality should be achieved by using the selected prop and
// overriding the selected class but this applied the secondary color at 0.08% opacity.
// Overridding the root class is a workaround.
classes={{
root: (isSelected && rowCanBeSelected) ? classes.rowSelected : classes.bandedRows,
hover: classes.hoverBackgroundColor
}}
{...row.getRowProps({
style,
})}
>
{row.cells.map(cell => (
cell.render(_ => {
switch (cell.column.id) {
case "dateReceived":
return (
<ItemTableCell TableCellProps={cell.getCellProps()}>
<RelativeTime value={cell.value} />
</ItemTableCell>
);
case "lastUpdated":
return (
<LastUpdatedCell
time={cell.value}
ItemTableCellProps={cell.getCellProps()}
/>
);
default:
return (
<ItemTableCell TableCellProps={cell.getCellProps()}>
{cell.value}
</ItemTableCell>
);
}
})
))}
</TableRow>
);
}, areEqual, [prepareRow, rows]
)}
</FixedSizeList>
)}
</AutoSizer>
</TableBody>
</Table>
</TableContainer >
)
);
}

Expand Down
Loading

0 comments on commit 529f240

Please sign in to comment.