Skip to content

Commit

Permalink
Merge pull request #1275 from cityofaustin/15353-refine-project-list-…
Browse files Browse the repository at this point in the history
…layout

Use Data Grid in the Projects List
chiaberry authored Feb 29, 2024
2 parents e250158 + e68844d commit 35cfcb4
Showing 10 changed files with 298 additions and 400 deletions.
1 change: 0 additions & 1 deletion moped-editor/src/components/GridTable/Search.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
import { useSearchParams } from "react-router-dom";

import { Box, Button, Grid, Paper, Popper } from "@mui/material";
import SaveAltIcon from "@mui/icons-material/SaveAlt";
import Filters from "src/components/GridTable/Filters";
1 change: 0 additions & 1 deletion moped-editor/src/components/GridTable/SearchBar.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from "react";
import PropTypes from "prop-types";
import { useSearchParams } from "react-router-dom";

import {
Button,
Box,
2 changes: 1 addition & 1 deletion moped-editor/src/components/Page.js
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ import PropTypes from "prop-types";

const Page = forwardRef(({ children, title = "", ...rest }, ref) => {
return (
<div ref={ref} {...rest}>
<div className="page" ref={ref} {...rest}>
<Helmet>
<title>{title}</title>
</Helmet>
2 changes: 0 additions & 2 deletions moped-editor/src/layouts/DashboardLayout/DashboardLayout.js
Original file line number Diff line number Diff line change
@@ -36,8 +36,6 @@ const DashboardLayout = () => {
const classes = useStyles();
const { user } = useUser();

// console.debug("user", user);

return user ? (
<div className={classes.root}>
<TopBar />
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@ const useColumns = ({ deleteInProgress, onDeleteActivity, setEditActivity }) =>
{
headerName: "Description",
field: "description",
minWidth: 150,
minWidth: 200,
flex: 1,
defaultVisible: true,
},
@@ -206,7 +206,7 @@ const ProjectWorkActivitiesTable = () => {
});

/**
* Initialize which columns should be visibile - must be memoized to safely
* Initialize which columns should be visible - must be memoized to safely
* be used with useHiddenColumnsSettings hook
*/
const defaultHiddenColumnSettings = useMemo(
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {
GridToolbarColumnsButton,
GridToolbarContainer,
GridToolbarDensitySelector,
} from "@mui/x-data-grid";

const ProjectListToolbar = () => (
<GridToolbarContainer>
<GridToolbarColumnsButton />
<GridToolbarDensitySelector />
</GridToolbarContainer>
);

export default ProjectListToolbar;
Original file line number Diff line number Diff line change
@@ -1,29 +1,17 @@
import React from "react";
import makeStyles from "@mui/styles/makeStyles";
import { ErrorBoundary } from "react-error-boundary";
import Page from "src/components/Page";
import ProjectsListViewTable from "./ProjectsListViewTable";
import FallbackComponent from "src/components/FallbackComponent";

// Styles
const useStyles = makeStyles((theme) => ({
root: {
minHeight: "100%",
paddingBottom: theme.spacing(1),
paddingTop: theme.spacing(1),
},
}));

/**
* Projects List View
* @return {JSX.Element}
* @constructor
*/
const ProjectsListView = () => {
const classes = useStyles();

return (
<Page className={classes.root} title="Projects">
<Page title="Projects">
<ErrorBoundary FallbackComponent={FallbackComponent}>
<ProjectsListViewTable title={"Projects"} />
</ErrorBoundary>
Original file line number Diff line number Diff line change
@@ -15,14 +15,12 @@ export const PROJECT_LIST_VIEW_QUERY_CONFIG = {
single_item: "/moped/projects",
new_item: "/moped/projects/new",
new_item_label: "New Project",
showSearchBar: true,
showFilters: false,
showExport: true,
showNewItemButton: false,
noResultsMessage: "No projects found.",
showPagination: true,
pagination: {
rowsPerPageOptions: [100, 250, 1000],
rowsPerPageOptions: [25, 50, 100], // we are limited to max 100 on the data grid community plan
defaultOffset: 0,
defaultLimit: 100,
},
@@ -68,10 +66,10 @@ export const PROJECT_LIST_VIEW_QUERY_CONFIG = {
type: "String",
},
project_description: {
hidden: true,
searchable: true,
sortable: true,
label: "Project description",
showInTable: false,
search: {
label: "Search by project description",
operator: "_ilike",
@@ -97,7 +95,6 @@ export const PROJECT_LIST_VIEW_QUERY_CONFIG = {
current_phase_key: {
searchable: false,
sortable: true,
hidden: true,
},
project_team_members: {
searchable: false,
@@ -149,7 +146,6 @@ export const PROJECT_LIST_VIEW_QUERY_CONFIG = {
type: "string",
},
ecapris_subproject_id: {
hidden: false,
searchable: true,
sortable: true,
label: "eCAPRIS ID",
@@ -164,7 +160,6 @@ export const PROJECT_LIST_VIEW_QUERY_CONFIG = {
},
},
updated_at: {
hidden: false,
searchable: false,
sortable: true,
defaultHidden: false,
@@ -276,7 +271,7 @@ export const PROJECT_LIST_VIEW_QUERY_CONFIG = {
},
parent_project_id: {
type: "Int",
sortable: true,
sortable: false,
defaultHidden: true,
showInTable: true,
},
@@ -306,7 +301,7 @@ export const DEFAULT_HIDDEN_COLS = Object.entries(
PROJECT_LIST_VIEW_QUERY_CONFIG.columns
).reduce((acc, [columnName, config]) => {
if (config.showInTable === true) {
acc[columnName] = config.defaultHidden;
acc[columnName] = !config.defaultHidden;
}
return acc;
}, {});
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { useState, useEffect, useContext, useCallback } from "react";
import { Box, Card, CircularProgress, Container, Paper } from "@mui/material";
import { Box, Container, Paper } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useQuery } from "@apollo/client";
import Search from "../../../components/GridTable/Search";
import ApolloErrorHandler from "../../../components/ApolloErrorHandler";
import MaterialTable from "@material-table/core";
import { useTableComponents, useColumns, useTableOptions } from "./helpers.js";
import { DataGrid } from "@mui/x-data-grid";
import { useColumns } from "./helpers.js";
import { useHiddenColumnsSettings } from "src/utils/localStorageHelpers";
import { useGetProjectListView } from "./useProjectListViewQuery/useProjectListViewQuery";
import {
@@ -23,30 +23,22 @@ import {
useCsvExport,
CsvDownloadDialog,
} from "./useProjectListViewQuery/useCsvExport";
import ProjectListToolbar from "./ProjectListToolbar";
import { useCurrentData } from "./useProjectListViewQuery/useCurrentData";

/**
* GridTable Style
*/
const useStyles = makeStyles((theme) => ({
root: {
width: "100%",
"& .MuiTableCell-head:nth-of-type(2)": {
left: "0px",
position: "sticky",
},
height: "90%"
},
paper: {
width: "100%",
marginBottom: theme.spacing(1),
},
table: {
minWidth: 750,
},
tableCell: {
"text-transform": "capitalize",
"white-space": "pre-wrap",
},
noResults: {
paddingTop: "25px",
paddingBottom: "16px",
@@ -92,26 +84,11 @@ const ProjectsListViewTable = () => {

const { hiddenColumns, setHiddenColumns } = useHiddenColumnsSettings({
defaultHiddenColumnSettings: DEFAULT_HIDDEN_COLS,
storageKey: "mopedColumnConfig",
storageKey: "mopedProjectListColumnConfig",
});

const { columns, columnsToReturnInQuery } = useColumns({ hiddenColumns });

/**
* Keeps localStorage column config in sync with UI interactions
* @param {Object} column - the MT column config with the `field` prop - aka the column name
* @param {Bool} hidden - the hidden state of the column
*/
const handleColumnChange = useCallback(
({ field }, hidden) => {
setHiddenColumns((prevHiddenColumns) => ({
...prevHiddenColumns,
[field]: hidden,
}));
},
[setHiddenColumns]
);

const { query: projectListViewQuery, exportQuery } = useGetProjectListView({
columnsToReturn: columnsToReturnInQuery,
exportColumnsToReturn: Object.keys(PROJECT_LIST_VIEW_EXPORT_CONFIG),
@@ -144,59 +121,39 @@ const ProjectsListViewTable = () => {
setQueryLimit,
});

const tableOptions = useTableOptions({ queryLimit, data });

const sortByColumnIndex = columns.findIndex(
(column) => column.field === orderByColumn
);

/**
* Handles the header click for sorting asc/desc.
* @param {int} columnId
* @param {string} newOrderDirection
* Note: this is a GridTable function that we are using to override a Material Table sorting function
* Their function call uses two variables, columnId and newOrderDirection. We only need the columnId
* @param {Array.Object} sortModel, [{field, sort}]
* Overrides a DataGrid sorting function
* Clicking the sort arrow on a column will toggle between asc, desc, then reset
* The Community version of DataGrid only supports sorting by one field, until we upgrade to Pro
* we can expect only one item in the array
**/
const handleTableHeaderClick = useCallback(
(columnId, newOrderDirection) => {
const columnName = columns[columnId]?.field;

const handleSortClick = useCallback(
(sortModel) => {
// Resets pagination offset to 0 when user clicks a header to display most relevant results
setQueryOffset(0);

if (orderByColumn === columnName) {
// If the current sortColumn is the same as the new
// then invert values and repeat sort on column
const direction = orderByDirection === "desc" ? "asc" : "desc";
setOrderByDirection(direction);
if (sortModel.length > 0) {
setOrderByColumn(sortModel[0]?.field);
setOrderByDirection(sortModel[0]?.sort);
} else {
// Sort different column in same order as previous column
setOrderByColumn(columnName);
setOrderByColumn(PROJECT_LIST_VIEW_QUERY_CONFIG.order.defaultColumn);
setOrderByDirection(
PROJECT_LIST_VIEW_QUERY_CONFIG.order.defaultDirection
);
}
},
[
setQueryOffset,
orderByColumn,
orderByDirection,
columns,
setOrderByDirection,
setOrderByColumn,
]
[setQueryOffset, setOrderByDirection, setOrderByColumn]
);

const tableComponents = useTableComponents({
data,
loading,
queryLimit,
queryOffset,
setQueryLimit,
setQueryOffset,
handleTableHeaderClick,
sortByColumnIndex,
orderByDirection,
rowsPerPageOptions:
PROJECT_LIST_VIEW_QUERY_CONFIG.pagination.rowsPerPageOptions,
});
const handlePagination = useCallback(
(paginationModel) => {
setQueryLimit(paginationModel.pageSize);
setQueryOffset(paginationModel.pageSize * paginationModel.page);
},
[setQueryLimit, setQueryOffset]
);

/**
* Store the most recent version of the query in app context so that it
@@ -227,22 +184,62 @@ const ProjectsListViewTable = () => {
/>
{/*Main Table Body*/}
<Paper className={classes.paper}>
<Box mt={3}>
{!data && !error ? (
<CircularProgress />
) : data && data.project_list_view ? (
<Card className={classes.root}>
<MaterialTable
onChangeColumnHidden={handleColumnChange}
data={data.project_list_view}
columns={columns}
title=""
options={tableOptions}
components={tableComponents}
/>
</Card>
) : (
<span>{error ? error : "Could not fetch data"}</span>
<Box
sx={{
height: "70vh",
minHeight: "400px",
marginTop: "14px",
}}
>
{data && data.project_list_view && (
<DataGrid
// per the docs: When the height of a row is set to "auto", the final height will follow exactly
// the content size and ignore the density. the docs recommend these styles in order to have density
// along with get row height auto
sx={{
"&.MuiDataGrid-root--densityCompact .MuiDataGrid-cell": {
py: "8px",
},
"&.MuiDataGrid-root--densityStandard .MuiDataGrid-cell": {
py: "15px",
},
"&.MuiDataGrid-root--densityComfortable .MuiDataGrid-cell": {
py: "22px",
},
}}
density="compact"
getRowHeight={() => "auto"}
columnVisibilityModel={hiddenColumns}
onColumnVisibilityModelChange={(newModel) => {
setHiddenColumns(newModel);
}}
slots={{
toolbar: ProjectListToolbar,
}}
slotProps={{
columnsPanel: {
// Hiding buttons because when I toggle "show all" its only setting one column to visible
// instead of including every column in the object
disableShowAllButton: true,
},
}}
columns={columns}
getRowId={(row) => row.project_id}
disableRowSelectionOnClick
rows={data.project_list_view}
onSortModelChange={handleSortClick}
disableColumnFilter
paginationMode="server"
paginationModel={{
page: queryOffset / queryLimit,
pageSize: queryLimit,
}}
onPaginationModelChange={handlePagination}
rowCount={data.project_list_view_aggregate?.aggregate.count}
pageSizeOptions={
PROJECT_LIST_VIEW_QUERY_CONFIG.pagination.rowsPerPageOptions
}
/>
)}
</Box>
</Paper>
476 changes: 192 additions & 284 deletions moped-editor/src/views/projects/projectsListView/helpers.js

Large diffs are not rendered by default.

0 comments on commit 35cfcb4

Please sign in to comment.