Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edit LookupAutocompleteComponent to update related field #1552

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5d29e83
add options to docstring and remove outdated params
roseeichelmann Feb 28, 2025
688f020
filter to only include team members that arent duplicates
roseeichelmann Feb 28, 2025
0c28d4d
add workgroup_name to row.moped_workgroup so we dont have the flashin…
roseeichelmann Mar 4, 2025
b3f1bb8
use currentRowMember to add current team member as option when editin…
roseeichelmann Mar 4, 2025
a7b3fb0
add comments
roseeichelmann Mar 4, 2025
fc445be
add docstring for workgrouplookup
roseeichelmann Mar 4, 2025
4327216
make the milestones autocomplete look more like the other ones
chiaberry Mar 4, 2025
252bad5
actually save the updated milestone
chiaberry Mar 4, 2025
cb9f943
memoize and move existingteamemmbers up in scope, use find instead of…
roseeichelmann Mar 4, 2025
798d261
apdate var name
roseeichelmann Mar 4, 2025
cfa6013
Merge branch 'rose/21199_duplicate_team_members' into 21358-autocompl…
chiaberry Mar 5, 2025
7919ee9
fallback to blank if no workgroup name
chiaberry Mar 5, 2025
e5be20c
Merge branch 'rose/21199_duplicate_team_members' into 21358-autocompl…
chiaberry Mar 5, 2025
d77c0ce
use the new component wip
chiaberry Mar 5, 2025
61d94b9
update team autocomplete to use autocompleteprops
chiaberry Mar 5, 2025
aa83f98
use textfield props
chiaberry Mar 5, 2025
c58c188
move dependent fields out
chiaberry Mar 5, 2025
de2edb6
milestone to generic autocomplete too
chiaberry Mar 6, 2025
375bc53
remove unused lookups from usememo
chiaberry Mar 6, 2025
f0ca5a8
add dependent fields to lookup autocomplete
chiaberry Mar 6, 2025
fdcb3ca
use the lookup one
chiaberry Mar 6, 2025
1749aa3
use lookupautocomplete in teams table
chiaberry Mar 7, 2025
c32746e
remove other autocomplete components
chiaberry Mar 7, 2025
9fd4d50
move the props into a different file
chiaberry Mar 7, 2025
c343d7d
cleaning up some comments and docstrings
chiaberry Mar 7, 2025
7730fc1
one more thing to remove
chiaberry Mar 7, 2025
e23992e
need to delete the thing i made up
chiaberry Mar 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ import { filterOptions } from "src/utils/autocompleteHelpers";
* @param {Boolean} hasFocus - does field have focus in table
* @param {String} name - name of lookup table relationship
* @param {Array|Objects} options - the lookup table data
* @param {Object} autocompleteProps - props passed to the MUI Autcomplete Component
* @param {Boolean} fullWidthPopper - should component use custom Popper component
* @param {Object} autocompleteProps - props passed to the MUI Autocomplete Component
* @param {Object} textFieldProps - props passed to the renderInput TextField
* @param {string} dependentFieldName - optional, if another field should be updated on change, name of field
* @param {function} dependentFieldValue - optional, takes newValue as input and returns the dependent fields change
*
* @returns {React component}
*/
Expand All @@ -26,6 +29,9 @@ const LookupAutocompleteComponent = ({
options,
fullWidthPopper,
autocompleteProps,
textFieldProps,
dependentFieldName,
dependentFieldValue,
}) => {
const apiRef = useGridApiContext();
const ref = React.useRef(null);
Expand All @@ -42,6 +48,13 @@ const LookupAutocompleteComponent = ({
field,
value: newValue,
});
if (dependentFieldName) {
apiRef.current.setEditCellValue({
id,
field: dependentFieldName,
value: dependentFieldValue(newValue),
});
}
};

const defaultGetOptionLabel = useCallback(
Expand All @@ -64,7 +77,12 @@ const LookupAutocompleteComponent = ({
filterOptions={filterOptions}
options={options}
renderInput={(params) => (
<TextField variant="standard" {...params} inputRef={ref} />
<TextField
variant="standard"
{...params}
inputRef={ref}
{...textFieldProps}
/>
)}
{...autocompleteProps}
getOptionLabel={
Expand Down
61 changes: 28 additions & 33 deletions moped-editor/src/views/projects/projectView/ProjectMilestones.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import dataGridProStyleOverrides from "src/styles/dataGridProStylesOverrides";
import ProjectMilestoneToolbar from "./ProjectMilestones/ProjectMilestoneToolbar";
import DataGridTextField from "src/components/DataGridPro/DataGridTextField";
import ViewOnlyTextField from "src/components/DataGridPro/ViewOnlyTextField";
import LookupAutocompleteComponent from "src/components/DataGridPro/LookupAutocompleteComponent";

import {
UPDATE_PROJECT_MILESTONES_MUTATION,
Expand All @@ -21,7 +22,6 @@ import parseISO from "date-fns/parseISO";
import { usePhaseNameLookup } from "./ProjectPhase/helpers";
import ToggleEditComponent from "./ToggleEditComponent";
import MilestoneTemplateModal from "./ProjectMilestones/MilestoneTemplateModal";
import MilestoneAutocompleteComponent from "./ProjectMilestones/MilestoneAutocompleteComponent";
import DataGridDateFieldEdit from "./ProjectMilestones/DataGridDateFieldEdit";
import DeleteConfirmationModal from "./DeleteConfirmationModal";
import DataGridActions from "src/components/DataGridPro/DataGridActions";
Expand All @@ -40,51 +40,42 @@ const useMilestoneNameLookup = (data) =>
);
}, [data]);

const useMilestoneRelatedPhaseLookup = (data) =>
useMemo(() => {
if (!data) {
return {};
}
return data.moped_milestones.reduce(
(obj, item) =>
Object.assign(obj, {
[item.milestone_id]: item.related_phase_id,
}),
{}
);
}, [data]);

const requiredFields = ["milestone_id"];
const requiredFields = ["moped_milestone"];

const useColumns = ({
data,
rowModesModel,
handleEditClick,
handleSaveClick,
handleCancelClick,
handleDeleteOpen,
milestoneNameLookup,
relatedPhaseLookup,
usingShiftKey,
phaseNameLookup,
}) =>
useMemo(() => {
return [
{
headerName: "Milestone",
field: "milestone_id",
field: "moped_milestone",
renderCell: ({ row }) => row.moped_milestone?.milestone_name,
// input validation:
preProcessEditCellProps: (params) => ({
...params.props,
error: !params.props.value,
error: !params.props.value?.milestone_id,
}),
editable: true,
renderEditCell: (props) => (
<MilestoneAutocompleteComponent
<LookupAutocompleteComponent
{...props}
milestoneNameLookup={milestoneNameLookup}
relatedPhaseLookup={relatedPhaseLookup}
error={props.error}
name={"milestone"}
options={data?.moped_milestones}
textFieldProps={{
error: props.error,
}}
dependentFieldName="moped_milestone_related_phase"
dependentFieldValue={(newValue) => ({
related_phase_id: newValue?.related_phase_id,
})}
/>
),
width: 250,
Expand All @@ -98,16 +89,16 @@ const useColumns = ({
},
{
headerName: "Related phase",
field: "moped_milestone",
field: "moped_milestone_related_phase",
editable: true, // this is to be able to use the renderEditCell option to update the related phase
// during editing -- the input field is always disabled
valueFormatter: (value) => {
return phaseNameLookup[value?.related_phase_id] ?? "";
},
renderCell: (props) =>
phaseNameLookup[props.row.moped_milestone?.related_phase_id] ?? "",
width: 150,
renderEditCell: (props) => (
<ViewOnlyTextField
{...props}
value={props.row.moped_milestone}
lookupTable={phaseNameLookup}
usingShiftKey={usingShiftKey}
previousColumnField="description"
Expand Down Expand Up @@ -176,13 +167,12 @@ const useColumns = ({
},
];
}, [
data,
rowModesModel,
handleSaveClick,
handleCancelClick,
handleEditClick,
handleDeleteOpen,
milestoneNameLookup,
relatedPhaseLookup,
usingShiftKey,
phaseNameLookup,
]);
Expand Down Expand Up @@ -224,7 +214,6 @@ const ProjectMilestones = ({
}, [data]);

const milestoneNameLookup = useMilestoneNameLookup(data);
const relatedPhaseLookup = useMilestoneRelatedPhaseLookup(data);
const phaseNameLookup = usePhaseNameLookup(data?.moped_phases || []);

const handleDeleteOpen = useCallback(
Expand Down Expand Up @@ -302,6 +291,13 @@ const ProjectMilestones = ({
? null
: updatedMilestoneData.description;

updatedMilestoneData.milestone_id =
updatedMilestoneData.moped_milestone?.milestone_id || null;

// "moped_milestone_related_phase" is a column name only for rendering in DataGrid, the pertinent information is in the
// moped_milestone object. Deleting from the payload since the db is not expecting it in this shape
delete updatedMilestoneData.moped_milestone_related_phase;

if (updatedRow.isNew) {
delete updatedMilestoneData.isNew;
delete updatedMilestoneData.id;
Expand Down Expand Up @@ -402,13 +398,12 @@ const ProjectMilestones = ({
);

const dataGridColumns = useColumns({
data,
rowModesModel,
handleDeleteOpen,
handleSaveClick,
handleCancelClick,
handleEditClick,
milestoneNameLookup,
relatedPhaseLookup,
usingShiftKey,
phaseNameLookup,
});
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ import {
import dataGridProStyleOverrides from "src/styles/dataGridProStylesOverrides";
import ProjectTeamToolbar from "./ProjectTeamToolbar";
import ProjectTeamRoleMultiselect from "./ProjectTeamRoleMultiselect";
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";
import LookupAutocompleteComponent from "src/components/DataGridPro/LookupAutocompleteComponent";
import { mopedUserAutocompleteProps } from "./utils";

const useStyles = makeStyles((theme) => ({
infoIcon: {
Expand All @@ -49,6 +50,14 @@ const useWorkgroupLookup = (data) =>
}, {});
}, [data]);

// returns a list of user ids for the existing team members on this project
const useExistingTeamMembers = (data) =>
useMemo(() => {
return data?.moped_project_by_pk?.moped_proj_personnel.map(
(option) => option.moped_user.user_id
);
}, [data]);

const requiredFields = ["moped_user", "moped_proj_personnel_roles"];

const useColumns = ({
Expand All @@ -61,6 +70,7 @@ const useColumns = ({
classes,
usingShiftKey,
workgroupLookup,
existingTeamMembers,
}) =>
useMemo(() => {
return [
Expand All @@ -73,13 +83,35 @@ const useColumns = ({
return user ? `${user.first_name} ${user.last_name}` : "";
},
renderEditCell: (props) => {
// the team member object for the current row
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I merged Rose's branch into mine, this is from her PR

const currentRowMember =
data?.moped_project_by_pk?.moped_proj_personnel.find(
(user) => user.project_personnel_id === props.id
);
// filter out existing team members from list of options unless they are the current row member
// that way the current member remains an option when editing a row
const unassignedTeamMembers = data?.moped_users.filter((user) => {
return (
!existingTeamMembers.includes(user.user_id) ||
user.user_id === currentRowMember?.moped_user.user_id
);
});
return (
<TeamAutocompleteComponent
<LookupAutocompleteComponent
{...props}
name={"user"}
value={props.row.moped_user}
options={data.moped_users}
error={props.error}
options={unassignedTeamMembers}
autocompleteProps={mopedUserAutocompleteProps}
textFieldProps={{
error: props.error,
helperText: "Required",
}}
dependentFieldName="moped_workgroup"
dependentFieldValue={(newValue) => ({
workgroup_id: newValue?.workgroup_id,
workgroup_name: workgroupLookup[newValue?.workgroup_id],
})}
/>
);
},
Expand All @@ -95,7 +127,7 @@ const useColumns = ({
field: "moped_workgroup",
editable: true,
width: 200,
valueFormatter: (workgroup) => workgroup?.workgroup_name,
valueFormatter: (workgroup) => workgroup?.workgroup_name ?? "",
renderEditCell: (props) => (
<ViewOnlyTextField
{...props}
Expand Down Expand Up @@ -194,6 +226,7 @@ const useColumns = ({
classes,
usingShiftKey,
workgroupLookup,
existingTeamMembers,
]);

const ProjectTeamTable = ({ projectId, handleSnackbar }) => {
Expand Down Expand Up @@ -233,6 +266,8 @@ const ProjectTeamTable = ({ projectId, handleSnackbar }) => {

const workgroupLookup = useWorkgroupLookup(data);

const existingTeamMembers = useExistingTeamMembers(data);

/**
* Construct a moped_project_personnel object that can be passed to an insert mutation
* @param {Object} newData - a table row object with { moped_user, notes, roleIds }
Expand Down Expand Up @@ -496,6 +531,7 @@ const ProjectTeamTable = ({ projectId, handleSnackbar }) => {
classes,
usingShiftKey,
workgroupLookup,
existingTeamMembers,
});

const processRowUpdateMemoized = useCallback(
Expand Down
Loading