-
Notifications
You must be signed in to change notification settings - Fork 0
Support for grouping in ItemTable #177
Comments
I would add group by any of the column headers. |
This functionality is supported in react-table and needs to be exposed via the UI. |
Work has begun on this issue. Here are a few notes on how grouping works in react-table and the changes implementing it may require.
|
Here is a gif to give a visual on how react-table handles grouping: Also here is a link to this example on codesandbox |
I was able to get a rough implementation of grouping working. Below I will detail what needed to be added for this to work and what still needs to be done/improved ImplementationFirst, in order to use grouping in
const tableInstance = useTable(
{
columns,
data,
autoResetSortBy: false,
autoResetFilters: false,
defaultColumn: {
Filter: ({ column: { Header, setFilter } }) => {
return (
<ItemTableFilter
label={Header}
onChange={(event) => setFilter(event.target.value)}
/>
);
},
},
initialState: {
sortBy: [
{ id: "queue" },
{ id: 'number' },
{ id: 'lastUpdated' },
],
},
},
- useFilters, useFlexLayout, useSortBy,
+ useFilters, useFlexLayout, useGroupBy, useSortBy, useExpanded
); Next, aggregates were added to each column. To add aggregates to a column there are two props to pass,
Here is how this implementation looks in our code: const columns = React.useMemo(
() => [
{ Header: 'Queue', accessor: 'queue',aggregate: 'uniqueCount', Aggregated: ({ value }) => `In ${value} queue(s) `, },
{ Header: 'Item #', accessor: 'number', aggregate: 'count', Aggregated: ({ value }) => `${value} items in queue` },
{ Header: 'From', accessor: 'userAlias', aggregate: 'uniqueCount', Aggregated: ({ value }) => `Items from ${value} unique user(s) ` },
{ Header: 'Assigned To', accessor: 'assignedTo', aggregate: 'uniqueCount', Aggregated: ({ value }) => `Items assigned to ${value} unique staff memeber(s) ` },
{ Header: 'Subject', accessor: 'subject', aggregate: 'uniqueCount', Aggregated: ({ value }) => `${value} unique subject(s)` },
{ Header: 'Status', accessor: 'status', aggregate: 'uniqueCount', Aggregated: ({ value }) => `${value} unique status(es)` },
{ Header: 'Priority', accessor: 'priority', aggregate: 'uniqueCount', Aggregated: ({ value }) => `${value} unique priorities` },
{ Header: 'Last Updated', accessor: 'lastUpdated', aggregate: 'sum', Aggregated: ({ value }) => `${Math.round(value * 100) / 100} (avg) time since last update`, sortInverted: true, Cell: ({ value }) => <RelativeTime value={value} /> },
{ Header: 'Department', accessor: 'department', aggregate: 'uniqueCount', Aggregated: ({ value }) => `${value} unique department(s)` },
{ Header: 'Building', accessor: 'building', aggregate: 'uniqueCount', Aggregated: ({ value }) => `${value} unique building(s)` },
{ Header: 'Date Received', accessor: 'dateReceived', aggregate: 'sum', Aggregated: ({ value }) => `${Math.round(value * 100) / 100} (avg) date received`, sortInverted: true, Cell: ({ value }) => <RelativeTime value={value} /> },
], []); Next, a rough UI for interacting with grouping was implemented. In order to interact with grouping, we need to pass the //Maps this UI to each column header
{headerGroup.headers.map(column => (
<TableRow {...column.getHeaderProps()}>
<Grid container spacing={0}>
<Grid item>
{column.canGroupBy ? (
// expand column props. then pass getGroupByToggleProps
<IconButton size="small" justify="center" {...column.getGroupByToggleProps()}>
//Change icon based on if column is grouped or not
{column.isGrouped ? <LayersClear /> : <Layers />}
</IconButton>
) : null}
</Grid>
<Grid item>
{column.render('Header')}
</Grid>
</Grid>
</TableRow>
))} Screenshot of the above UI Next the UI for the table needed to be addressed. react-table handles grouping by collapsing the grouped rows into a single row. The grouped information can then be seen by expanding the row (which is why we needed to add the {row.cells.map(cell => {
+ return (
+ cell.isGrouped ? (
+ // If it's a grouped cell, add an expander and row count
+ <ItemTableCell TableCellProps={cell.getCellProps()}>
+ <IconButton size="small" {...row.getToggleRowExpandedProps()}>
+ {row.isExpanded ? <ArrowDropDown /> : <ArrowRight />}
+ </IconButton>
+ {cell.render('Cell')} ({row.subRows.length})
+ </ItemTableCell> ) :
+ cell.isAggregated ? (
+ // If the cell is aggregated, use the Aggregated renderer for cell
+ <ItemTableCell TableCellProps={cell.getCellProps()}>
+ {cell.render('Aggregated')}
+ </ItemTableCell> ) :
+ //If the cell is a placeholder don't render anything
+ cell.isPlaceholder ? null :
+ (
// Otherwise, just render the regular 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>
);
}
})
)
+ )
})} Next StepsThere are a few things that still need to happen:
|
Why is this?
If something can be a list, it should be a list.
When talking about UI, include screenshot. Be sure to properly format code snippets. <Grid container spacing={0}>
<Grid item>
{column.canGroupBy ? (
// expand column props. then pass getGroupByToggleProps
<IconButton size="small" justify="center" {...column.getGroupByToggleProps()}>
//Change icon based on if column is grouped or not
{column.isGrouped ? <LayersClear /> : <Layers />}
</IconButton>
) : null}
</Grid>
<Grid item>. // This line is improperly indented.
{column.render('Header')}
</Grid>
Can this hook be modified to be open by default? |
My initial comment detailing the rough implementation of groping has been updated to include more information. Also important to note is that |
I have been unable to get the solutions suggested in my previous comment to work in our table. In theory, we should be able to use a useEffect(() => {
toggleAllRowsExpanded(true);
}, [isAllRowsExpanded]); It seems that the I also need to look into how we can display grouped information in a way similar to the current webqueue. Here is how it looks in the current webqueue vs webqueue2. This is important because we want to keep the workflow as close to the existing one as possible. Further research is needed to seehow custom rendering of groups in |
To test if the |
Here is an update on the progress I've made so far. Default expanded viewInstead of trying to set the state of the When you group rows by a specific value those rows are grouped into rows based on that value that contains sub rows. Each row has a prop, row.canExpand ? row.toggleRowExpanded(true) : row.toggleRowExpanded(false) This still needs work as right now the grouped rows can't be collapsed.
|
In order to keep the workflow as close to the existing one as possible, I implemented a const getLeafColumns = (rootColumns) => {
return rootColumns.reduce((leafColumns, column) => {
if (column.columns) {
return [...leafColumns, ...getLeafColumns(column.columns)] ;
} else {
return [...leafColumns, column];
}
}, []);
} Next is the code for the UI. It takes advantage of these components from Material-UI:
Here is how these component come together in code and how they appear in the UI:
<Paper elevation={0} classes={{ root: classes.Paper_root }}>
<FormControl classes={{ root: classes.formControl_root }} variant="outlined" size="small">
<InputLabel id="Group-By-Select">Group By</InputLabel>
<Select
classes={{ root: classes.Select_root }}
value={value}
onChange={onChange}
label="Group By"
autoWidth
>
<MenuItem value="">None</MenuItem>
{getLeafColumns(tableColumns).map(column => (
<MenuItem key={column.id} value={column.id}>{column.Header}</MenuItem>
))}
</Select>
</FormControl>
</Paper>
<TableContainer>
+ <GroupBySelector
+ value={groupBy[0]}
+ onChange={e => { setGroupBy([e.target.value]) }}
+ tableColumns={allColumns}
+ />
<Table stickyHeader {...getTableProps()} size="small">
///The rest of the code... UI Screenshots |
With some extra UI code from us, we might be able to acheive the same view as the existing webqueue for grouping with |
This will not be completed by the current team. At present the To the next person who looks at this issue, see these resources in this order:
|
I use the group by priority in the current webqueue and would like to see a way for that to implemented in this version. I need some sort of break between priorities to distinguish when they change.
The text was updated successfully, but these errors were encountered: