-
Notifications
You must be signed in to change notification settings - Fork 479
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
Inline edit controls - start editing and cancel editing #20029
Conversation
caleybrock
commented
Jan 16, 2018
•
edited
edited
- Edit button has an action that puts rows in editing state.
- Password section has an editing state.
- Cancel button stops editing.
- Add redux tests for new actions and fix storybook
Is it weird that here we click the quick actions menu, select edit, and get an inline experience. But on the homepage, for the sections table, if we click on the quick actions menu, select "Edit section" we get a modal edit experience? |
@@ -4,6 +4,8 @@ import PopUpMenu, {MenuBreak} from "@cdo/apps/lib/ui/PopUpMenu"; | |||
import color from "../../util/color"; | |||
import FontAwesome from '../FontAwesome'; | |||
import Button from '../Button'; | |||
import {startEditingStudent, cancelEditingStudent} from './manageStudentsRedux'; | |||
import { connect } from 'react-redux'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: would be good to be consistent on whether or not we have styles before/after braces in a single file
@@ -15,6 +17,17 @@ class ManageStudentActionsCell extends Component { | |||
static propTypes = { | |||
id: PropTypes.number.isRequired, | |||
isEditing: PropTypes.bool, | |||
//Provided by redux |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
supernit: throughout most of our code, we have a space after beginning a comment (though not actually true everywhere and it doesn't actually matter that much)
cancelEditingStudent(id) { | ||
dispatch(cancelEditingStudent(id)); | ||
}, | ||
}))(ManageStudentActionsCell); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can actually just use a shortcut version of matchPropsToDispatch:
export default connect(state => {}, {startEditingStudent, cancelEditingStudent})(ManageStudentActionsCell)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really good to know, although way less readable to me, so I'm going to leave it as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find it interesting to hear that you find the short form less readable (though I'm absolutely fine with you leaving this as is given that you think so).
@@ -1,6 +1,15 @@ | |||
import React from 'react'; | |||
import {UnconnectedManageStudentsTable} from './ManageStudentsTable'; | |||
import {SectionLoginType} from '@cdo/apps/util/sharedConstants'; | |||
import {combineReducers, createStore} from 'redux'; | |||
import manageStudents from './manageStudentsRedux'; | |||
import { Provider } from 'react-redux'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: similar comment about brace/space consistency
@@ -31,13 +35,33 @@ export default function manageStudents(state=initialState, action) { | |||
studentData: action.studentData, | |||
}; | |||
} | |||
if (action.type === START_EDITING_STUDENT) { | |||
let updatedStudentData = state.studentData; | |||
updatedStudentData[action.studentId].isEditing = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is mutating existing state (updatedStudentData is a reference to state.studentData, not a copy of it)
return { | ||
...state, | ||
studentData: updatedStudentData, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a way to do this without mutating (that isn't super understandable) is
return {
...state,
studentData: {
...state.studentData,
[action.studentId]: {
...state.studentData[action.studentId],
isEditing: true
}
}
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue for cancel
let studentDataArray = []; | ||
for (var id in studentData) { | ||
studentDataArray.push(studentData[id]); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can just be Object.values(studentDataArray)
?
|
||
// Converts key/value id/student pairs to an array of student objects for the | ||
// component to display | ||
// TODO: memoize this - sections could be a few thousand students |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should attach name to TODO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly nits, but will want to fix mutating state in the reducer.
I asked the same question about the edit experience. Many of the fields in the sections table require explanatory text, where as the student table fields are self explanatory and require quick editing, often of many rows at a time. Making this table have a dialog would be a worse experience for teachers, and making the sections table inline would probably cause confusion. |
I would agree that it makes sense for these tables to have different edit experiences. I wonder if they should also have different ways to begin the edit experience? Prob not a big deal either way. |
PTAL |
isEditing: true | ||
} | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: An alternative to this would be to use Immutable.js, which I think would allow you to do something like
return state.set(['studentData', action.studentId, isEditing'], true);
Doing some googling, I think you could also accomplish this with some lodashing, doing something like:
return _.set(_.clone(state), `studentData.${action.studentId}.isEditing`, true);
I haven't validated that this works, and am mostly just sharing as an FYI. The pattern currently used here is one we use elsewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turns out this was bad advice. Clone only makes a shallow copy, so this still ends up doing a mutation.
Consider the following code:
var foo = {
parent: {
x: 1,
y: 2
}
};
console.log(foo.parent.x); // prints 1
var foo2 = _.set(_.clone(foo), 'parent.x', 3);
console.log(foo.parent.x); // prints 3, foo and _.clone(foo) are both using the same parent object
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The following does appear to work, but I'm not sure I grok it well enough to recommend it's usage:
var foo2 = _.setWith(_.clone(foo), 'parent.x', 3, _.clone)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alright, but it sounds like they way it is currently works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. Current approach is 👍