Skip to content

Commit

Permalink
Merge pull request #1529 from cityofaustin/20328-update-team-table
Browse files Browse the repository at this point in the history
Update Team table to update workgroup on user select
  • Loading branch information
mddilley authored Jan 30, 2025
2 parents e5050f2 + 92a3348 commit 40d8ef2
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 13 deletions.
76 changes: 76 additions & 0 deletions moped-editor/src/components/DataGridPro/ViewOnlyTextField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from "react";
import { TextField } from "@mui/material";
import { makeStyles } from "@mui/styles";
import { useGridApiContext } from "@mui/x-data-grid-pro";

const useStyles = makeStyles((theme) => ({
readOnlyInput: {
width: "90%",
paddingTop: "inherit",
paddingLeft: theme.spacing(1),
},
}));

/**
* @param {String} field - name of field
* @param {Object} value - field value, should have an entry for the id and the corresponding string
* @param {Integer} id - Data Grid row id (same as record id)
* @param {Boolean} hasFocus - does this field have focus
* @param {Boolean} usingShiftKey - if shift key is depressed
* @param {string} previousColumnField - name of previous column in table
* @param {string} nextColumnField - name of next column in table
* @param {string} valueIdName - name of id key, ex: workgroup_id
* @param {Object} lookupTable - mapping of lookup ids to their corresponding name
* @return {JSX.Element}
*/
const ViewOnlyTextField = ({
field,
value,
id,
hasFocus,
usingShiftKey,
previousColumnField,
nextColumnField,
valueIdName,
lookupTable,
}) => {
const ref = React.useRef(null);
const apiRef = useGridApiContext();
const classes = useStyles();

// Because this field not editable, it cannot be focused and if a user is tabbing across the cells
// the focus should be forwarded to the next one in the row
React.useEffect(() => {
if (hasFocus) {
// Check if shift key is pressed, and user is trying to tab "backwards"
if (usingShiftKey) {
apiRef.current.setCellFocus(id, previousColumnField);
} else {
apiRef.current.setCellFocus(id, nextColumnField);
}
ref.current.focus();
}
}, [
apiRef,
hasFocus,
id,
usingShiftKey,
nextColumnField,
previousColumnField,
]);

return (
<TextField
variant="standard"
className={classes.readOnlyInput}
id={field}
inputRef={ref}
name={field}
type="text"
value={lookupTable[value?.[valueIdName]] || ""}
InputProps={{ readOnly: true, disableUnderline: true }}
/>
);
};

export default ViewOnlyTextField;
7 changes: 7 additions & 0 deletions moped-editor/src/queries/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,13 @@ export const TEAM_QUERY = gql`
user_id
is_deleted
}
moped_workgroup(
order_by: { workgroup_id: asc }
where: { is_deleted: { _eq: false } }
) {
workgroup_id
workgroup_name
}
}
`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { DataGridPro, GridRowModes, useGridApiRef } from "@mui/x-data-grid-pro";
import dataGridProStyleOverrides from "src/styles/dataGridProStylesOverrides";
import ProjectMilestoneToolbar from "./ProjectMilestones/ProjectMilestoneToolbar";
import DataGridTextField from "src/components/DataGridPro/DataGridTextField";
import RelatedPhaseTextField from "./ProjectMilestones/RelatedPhaseTextField";
import ViewOnlyTextField from "src/components/DataGridPro/ViewOnlyTextField";

import {
UPDATE_PROJECT_MILESTONES_MUTATION,
Expand Down Expand Up @@ -106,10 +106,13 @@ const useColumns = ({
},
width: 150,
renderEditCell: (props) => (
<RelatedPhaseTextField
<ViewOnlyTextField
{...props}
phaseNameLookupData={phaseNameLookup}
lookupTable={phaseNameLookup}
usingShiftKey={usingShiftKey}
previousColumnField="description"
nextColumnField="date_estimate"
valueIdName="related_phase_id"
/>
),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,38 @@ import {
Typography,
} from "@mui/material";
import { useGridApiContext } from "@mui/x-data-grid-pro";

import theme from "src/theme";

const ProjectTeamRoleMultiselect = ({ id, field, roles, value, error }) => {
/**
* @param {Integer} id - Data Grid row id (same as record id)
* @param {String} value - field value
* @param {String} field - name of field
* @param {[Object]} roles - array of role objects: {project_role_id, project_role_name, project_role_description}
* @param {Boolean} hasFocus - does this field have focus
* @param {Boolean} error - toggles error style in textfield
* @return {JSX.Element}
*/
const ProjectTeamRoleMultiselect = ({
id,
field,
roles,
value,
error,
hasFocus,
}) => {
const ref = React.useRef(null);
const rolesArray = React.useMemo(
() => value.map((role) => role.project_role_id),
[value]
);
const [selectedValues, setSelectedValues] = React.useState(rolesArray || []);

React.useEffect(() => {
if (hasFocus) {
ref.current.focus();
}
}, [hasFocus]);

const apiRef = useGridApiContext();

const handleChange = (event) => {
Expand Down Expand Up @@ -48,7 +70,7 @@ const ProjectTeamRoleMultiselect = ({ id, field, roles, value, error }) => {
error={error}
value={selectedValues}
onChange={handleChange}
input={<Input id="select-multiple" />}
input={<Input id="select-multiple" inputRef={ref} />}
renderValue={() => {
const selectedRoles = roles.filter((role) =>
selectedValues.includes(role.project_role_id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import TeamAutocompleteComponent from "./TeamAutocompleteComponent";
import DataGridActions from "src/components/DataGridPro/DataGridActions";
import DataGridTextField from "src/components/DataGridPro/DataGridTextField";
import DeleteConfirmationModal from "../DeleteConfirmationModal";
import ViewOnlyTextField from "src/components/DataGridPro/ViewOnlyTextField";

const useStyles = makeStyles((theme) => ({
infoIcon: {
Expand All @@ -48,13 +49,24 @@ const useTeamNameLookup = (data) =>
}, {});
}, [data]);

const useRoleNameLookup = (data) =>
const useWorkgroupLookup = (data) =>
useMemo(() => {
if (!data) {
return {};
}
return data.moped_project_roles.reduce((obj, item) => {
obj[item.project_role_id] = item.project_role_name;
return data.moped_workgroup.reduce((obj, item) => {
obj[item.workgroup_id] = item.workgroup_name;
return obj;
}, {});
}, [data]);

const useUserWorkgroupLookup = (data) =>
useMemo(() => {
if (!data) {
return {};
}
return data.moped_users.reduce((obj, item) => {
obj[item.user_id] = item.workgroup_id;
return obj;
}, {});
}, [data]);
Expand All @@ -70,7 +82,9 @@ const useColumns = ({
handleDeleteOpen,
classes,
teamNameLookup,
roleNameLookup,
usingShiftKey,
workgroupLookup,
userWorkgroupLookup,
}) =>
useMemo(() => {
return [
Expand All @@ -90,6 +104,7 @@ const useColumns = ({
value={props.row.moped_user}
nameLookup={teamNameLookup}
error={props.error}
userWorkgroupLookup={userWorkgroupLookup}
/>
);
},
Expand All @@ -103,8 +118,19 @@ const useColumns = ({
{
headerName: "Workgroup",
field: "moped_workgroup",
editable: true,
width: 200,
valueGetter: (workgroup) => workgroup?.workgroup_name,
valueFormatter: (workgroup) => workgroup?.workgroup_name,
renderEditCell: (props) => (
<ViewOnlyTextField
{...props}
lookupTable={workgroupLookup}
usingShiftKey={usingShiftKey}
previousColumnField="moped_user"
nextColumnField="moped_proj_personnel_roles"
valueIdName="workgroup_id"
/>
),
},
{
headerName: "Role",
Expand Down Expand Up @@ -192,6 +218,9 @@ const useColumns = ({
handleDeleteOpen,
classes,
teamNameLookup,
usingShiftKey,
workgroupLookup,
userWorkgroupLookup,
]);

const ProjectTeamTable = ({ projectId }) => {
Expand All @@ -212,6 +241,7 @@ const ProjectTeamTable = ({ projectId }) => {
const [isDeleteConfirmationOpen, setIsDeleteConfirmationOpen] =
useState(false);
const [deleteConfirmationId, setDeleteConfirmationId] = useState(null);
const [usingShiftKey, setUsingShiftKey] = useState(false);

useEffect(() => {
if (data?.moped_project_by_pk?.moped_proj_personnel?.length > 0) {
Expand All @@ -229,7 +259,8 @@ const ProjectTeamTable = ({ projectId }) => {
}, [data]);

const teamNameLookup = useTeamNameLookup(data);
const roleNameLookup = useRoleNameLookup(data);
const workgroupLookup = useWorkgroupLookup(data);
const userWorkgroupLookup = useUserWorkgroupLookup(data);

/**
* Construct a moped_project_personnel object that can be passed to an insert mutation
Expand Down Expand Up @@ -486,7 +517,9 @@ const ProjectTeamTable = ({ projectId }) => {
handleDeleteOpen,
classes,
teamNameLookup,
roleNameLookup,
usingShiftKey,
workgroupLookup,
userWorkgroupLookup,
});

const processRowUpdateMemoized = useCallback(
Expand All @@ -499,6 +532,12 @@ const ProjectTeamTable = ({ projectId }) => {

if (loading || !data) return <CircularProgress />;

const checkIfShiftKey = (params, event) => {
if (params.cellMode === GridRowModes.Edit && event.key === "Tab") {
setUsingShiftKey(event.shiftKey);
}
};

return (
<ApolloErrorHandler errors={error}>
<DataGridPro
Expand All @@ -514,6 +553,7 @@ const ProjectTeamTable = ({ projectId }) => {
onRowModesModelChange={setRowModesModel}
processRowUpdate={processRowUpdateMemoized}
onProcessRowUpdateError={handleProcessUpdateError}
onCellKeyDown={checkIfShiftKey}
disableRowSelectionOnClick
toolbar
density="comfortable"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useTheme } from "@mui/material/styles";
* @param {Object} nameLookup - maps user id to user name
* @param {Boolean} error - toggles error style in textfield
* @param {Object} name - name of the field
* @param {Object} userWorkgroupLookup - mapping of user ids to their corresponding workgroup ids
* @return {JSX.Element}
*/
const TeamAutocompleteComponent = ({
Expand All @@ -21,6 +22,7 @@ const TeamAutocompleteComponent = ({
nameLookup,
error,
name,
userWorkgroupLookup,
}) => {
const theme = useTheme();
const apiRef = useGridApiContext();
Expand All @@ -39,6 +41,12 @@ const TeamAutocompleteComponent = ({
field,
value: personnelValue ?? null,
});
// Also update the corresponding workgroup field with the selected user's workgroup id
apiRef.current.setEditCellValue({
id,
field: "moped_workgroup",
value: { workgroup_id: userWorkgroupLookup[newValue] },
});
};

const options = Object.keys(nameLookup);
Expand Down

0 comments on commit 40d8ef2

Please sign in to comment.