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

Section Action Dropdown #18058

Merged
merged 49 commits into from
Nov 20, 2017
Merged

Section Action Dropdown #18058

merged 49 commits into from
Nov 20, 2017

Conversation

audreyclark
Copy link
Contributor

@audreyclark audreyclark commented Sep 29, 2017

This section table action dropdown removes buttons from the section table and replaces with an expandable list of actions.

@caleybrock is planning to refactor this functionality as she works on react-ing other tables.

[Before]
oldbuttons

[After - Google Classroom section]
screenshot from 2017-10-18 11-58-01

[After - deletable section]
screenshot from 2017-10-18 11-57-21

[Confirm Delete Dialog]
deletesectiondialog

@epeach epeach changed the title Fixed small issues Section Action Dropdown Oct 13, 2017
@islemaster
Copy link
Contributor

❤️ This looks so much better!

@islemaster
Copy link
Contributor

I have two visual nits with this dialog:

  1. There's a lot of extra whitespace at the top. Can we even out the margins?

  2. Both buttons shouldn't be orange call-to-action buttons. "Cancel" should probably be gray/secondary. Orange/CTA is probably okay for "Delete" but I wonder if Red/danger would be better? Since it's an irreversible action.

deletesectiondialog

Copy link
Contributor

@islemaster islemaster left a comment

Choose a reason for hiding this comment

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

This is great and I love that we get to tear out a bunch of code as part of this change. The new dropdown is a pretty big component - I have some comments there and generally wonder if there are other ways we can break it up a bit.

{i18n.deleteSection()}
</div>
</a>
<BaseDialog
Copy link
Contributor

Choose a reason for hiding this comment

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

Even if you leave it at the end of this file, it'd help readability to extract this delete confirmation dialog as its own component. Fortunately there's very little in the way of props you'd need to pass through.

style={{padding:20}}
>
<h2>{i18n.deleteSection()}</h2>
<div>{i18n.deleteSectionConfirm()}</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

This dialog should include the section name somewhere in its title or description text - otherwise we're depending on the user remembering which section they picked before the dialog opened, which isn't obvious after the fact.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also note that we're making a dialog for every section row. For users with a ton of sections it may work better to render the dialog once at the page level and show/hide it based on redux state. After all, you shouldn't be able to show more than one delete dialog at a time.

};

onConfirmDelete = () => {
const {removeSection } = this.props;
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Unbalanced whitespace.

// While we are embedded in an angular page, reloading is the easiest
// way to pick up roster changes. Once everything is React maybe we
// won't need to do this.
utils.reload();
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably should be considered out-of-scope of this PR, but it'd be nice to address this comment and allow syncing without a page reload. Might also want some kind of progress or loading spinner intermediate state.

onConfirmDelete = () => {
const {removeSection } = this.props;
const section = this.props.sectionData;
$.ajax({
Copy link
Contributor

Choose a reason for hiding this comment

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

We should handle the intermediate state while this request is in flight gracefully - at least disable the confirm delete button so we can't request this twice, possibly hide the dialog immediately but put the row in a 'pending' state until it gets removed, that sort of thing.

@@ -0,0 +1,57 @@
@no_mobile
@dashboard_db_access
@pegasus_db_access
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we actually need both of these tags?

@no_mobile
@dashboard_db_access
@pegasus_db_access
Feature: Using the SectionActionDropdown
Copy link
Contributor

Choose a reason for hiding this comment

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

Great new tests! I suspect we had some UI tests elsewhere that depended on the buttons we're removing with this change. Have you checked for this?

@islemaster
Copy link
Contributor

Also I'll pull this and give it a try.

@islemaster
Copy link
Contributor

I haven't tracked down a root cause, but dismissing the dropdown feels sluggish. The delay between deselecting the menu and having it vanish isn't great.
out

@islemaster
Copy link
Contributor

islemaster commented Oct 18, 2017

I also get different cursors for menu items that are implemented as hyperlinks and those that are implemented with onClick handlers. We should also make this text unselectable to avoid the text selection cursor and accidental selection instead of clicking on a menu item. It be nice to unify this.

Underline for the current menu item is also a little weird - I think convention for a context menu like this is usually to highlight the currently selected row. IMO that might look better. Obviously defer to Tanya on this.

out

import SectionActionBox from "./SectionActionBox";

const styles = {
actionButton:{
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add cursor:pointer to the chevron button. and maybe a hover style on the button; it doesn't feel super discoverable right now.

@epeach
Copy link

epeach commented Nov 16, 2017

@islemaster I think this is ready for another code review, when you get the chance. Thanks!

@@ -116,46 +120,84 @@ class MenuBubbleUnwrapped extends Component {
<div style={style} className={className}>
{this.renderMenuItems()}
{/* These elements are used to draw the 'tail' with CSS */}
<span style={tailBorderStyle}/>
<span style={tailFillStyle}/>
{!this.props.minimalStyle &&
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it'd be nice to have Mark/Poorva choose one style for these. As discussed, the carrot on/off is a reasonable flag, but it feels like we would want these to be the same anyways.

first: PropTypes.bool,
last: PropTypes.bool,
color: PropTypes.string,
heightDivisor: PropTypes.number,
Copy link
Contributor

Choose a reason for hiding this comment

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

This part in particular would be great to not have.

Copy link
Contributor

Choose a reason for hiding this comment

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

Reading this props list without the component implementation, I don't really know what heightDivisor does. At least having a comment documenting this prop would be nice, so someone wanting to reuse Item wouldn't need to read its whole implementation.

};

const Tag = href ? 'a' : 'div';
Copy link
Contributor

Choose a reason for hiding this comment

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

I did not know you could do this. It feels a bit weird to have a href="null" for a div tag, but apparently this is what we do with Button.

<PopUpMenu.Item>Option One</PopUpMenu.Item>
<PopUpMenu.Item>Option Two</PopUpMenu.Item>
<PopUpMenu.Item>Option Three</PopUpMenu.Item>
<PopUpMenu.Item onClick={() => {}}>Option One</PopUpMenu.Item>
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see these as required in props, why do we need to add these here?

Copy link

Choose a reason for hiding this comment

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

They aren't marked as required, but the item will through an exception if an href/onclick is not provided.

};

// Menu open
open = () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

We chatted offline about these functions being able to be pulled apart into a separate component to be used for pop up actions in tables.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'll probably own in a separate PR.

Copy link
Contributor

@islemaster islemaster left a comment

Choose a reason for hiding this comment

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

Great progress on this! It's a big change. Very good reuse of color constants and other style constants throughout. I like that we are updating and replacing some older components instead of just producing redundant ones.

My comments break down into style nits, some React gotchas, and I think there's some work we should do now to make testing more thorough. I see Caley has called out some places where we could break large components apart a bit more, I agree that's also a good thing to look at here.

}
}

PopUpMenu.MenuBreak = Radium(MenuBreak);
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this component get any benefit from Radium? I don't see any style arrays, hover behaviors, or styles that need browser-prefixing.

If not, and especially because this has no props, this would make a great functional stateless component.

Copy link

Choose a reason for hiding this comment

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

There is one ":hover" in here (line 177) so I would be hesitant to remove Radium.

Copy link
Contributor

Choose a reason for hiding this comment

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

But that's on the PopUpMenu.Item component, not on the PopUpMenu.MenuBreak component.

first: PropTypes.bool,
last: PropTypes.bool,
color: PropTypes.string,
heightDivisor: PropTypes.number,
Copy link
Contributor

Choose a reason for hiding this comment

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

Reading this props list without the component implementation, I don't really know what heightDivisor does. At least having a comment documenting this prop would be nice, so someone wanting to reuse Item wouldn't need to read its whole implementation.

sectionName,
removeSection,
toggleSectionHidden,
importOrUpdateRoster} from './teacherSectionsRedux';
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: We usually avoid aligned indentation, would prefer

import {
  sectionCode,
  //...
  importOrUpdateRoster,
} from './teacherSectionsRedux';

Bonus points if you can find the eslint rule that would enforce and/or autofix this 😁

// Menu open
open = () => {
this.updateMenuLocation();
window.addEventListener("resize", this.updateMenuLocation);
Copy link
Contributor

Choose a reason for hiding this comment

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

Resize events can fire a ton during a window resize, so it can affect performance to do much work in response to them. It would be good to throttle the updateMenuLocation callback here.

beforeClose = (_, resetPortalState) => {
resetPortalState();
this.setState({open: false});
window.setTimeout(() => this.setState({canOpen: true}), 0);
Copy link
Contributor

Choose a reason for hiding this comment

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

What's with the setTimeout(_, 0)? Would it work to make this the async callback from setState instead?

And I click selector "#ui-test-edit-section" once I see it
And I press the save button to create a new section

# This should adequately test section down
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't understand this comment.

Given I am a teacher
And I am on "http://studio.code.org/"
And I create a new section
And I click selector ".fa-chevron-down" once I see it
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd go ahead and make a "I open the section action dropdown" step that aliases this, all these tests would read better.

And I create a new section
And I click selector ".fa-chevron-down" once I see it
And I click selector "#ui-test-hide-section" once I see it
And I click selector ".ui-test-show-hide" once I see it
Copy link
Contributor

Choose a reason for hiding this comment

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

Could stop and check between these steps that we can't see the section after it's hidden.

And I click selector "#ui-test-hide-section" once I see it
And I click selector ".ui-test-show-hide" once I see it
And I click selector ".fa-chevron-down" once I see it
And I click selector "a:contains('Show Section')" once I see it
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, let's assert a final state of the site - check that the section moved back up into the regular sections area.

);
expect(wrapper.text()).to.include(msg.enableMaker());
});

it('renders with enable maker option if maker is available and disabled', () => {
it('renders with disable maker option if maker is available and ensabled', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: ensabled

@epeach
Copy link

epeach commented Nov 17, 2017

@islemaster @caleybrock Ready for another review when you get a chance.

Copy link
Contributor

@islemaster islemaster left a comment

Choose a reason for hiding this comment

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

Awesome. Let's ship this and do incremental improvements afterward. Great work!

@caleybrock
Copy link
Contributor

👏 👏 so excited for this - it looks good!

@epeach epeach merged commit 2496471 into staging Nov 20, 2017
@islemaster
Copy link
Contributor

🎉

@epeach epeach deleted the SectionActionBoxDropdown branch November 21, 2017 22:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants