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 rounds ui! #1856

Merged
merged 42 commits into from
Sep 17, 2017
Merged

Edit rounds ui! #1856

merged 42 commits into from
Sep 17, 2017

Conversation

jfly
Copy link
Contributor

@jfly jfly commented Aug 23, 2017

Now that #1619 is finally merged (afer over 4 months =(), we now have a PATCH /competitions/:id/wcif/events endpoint!

This PR introduces a React based UI to edit the events and rounds of a competition. @Laura-O was kind enough to help out with the design of the UI components, which you can see in this google doc.

You can try this out on staging!

This PR is meant to be the minimum functionality required to let users input rounds and round attributes. I will address non critical stuff like UI polishing and validations in a later PR. I am tracking ideas for improvement in issue #1916.

TODO

  • Do not allow delegates to add or remove events to a confirmed competition
  • Figure out bullet warnings, or at least add them to the whitelist here.

@jfly jfly added the STATUS: in-progress Actively assigned to someone / expected to be resolved by another issue/PR already in progress label Aug 23, 2017
@pedrosino
Copy link
Contributor

Can't see the google doc link.

@jfly
Copy link
Contributor Author

jfly commented Aug 24, 2017

Oops! Updated the original post.

@jfly jfly force-pushed the edit-rounds-ui branch 4 times, most recently from 5513dc7 to 5872ff4 Compare August 29, 2017 04:21
@jfly jfly removed the STATUS: in-progress Actively assigned to someone / expected to be resolved by another issue/PR already in progress label Sep 2, 2017
@jfly jfly requested a review from viroulep September 2, 2017 00:40
@coder13
Copy link
Contributor

coder13 commented Sep 2, 2017

I'm initially concerned with the selection of saying if it's being held / how many rounds. With it being grayed out, I expect not to be able to interact with it even though I'm supposed to interact with it.

Maybe for fun, not being able to select certain cutoffs when certain round formats are selected.
I.E, best of 3 cutoff when round format is bo1.

image

@jfly
Copy link
Contributor Author

jfly commented Sep 3, 2017

Thanks for the feedback, @coder13! I've fixed up the advancement condition UI. I've also added a feature spec of editing events/rounds, which required adding an annoying amount of polyfill junk just to make PhantomJS happy.

@jfly jfly force-pushed the edit-rounds-ui branch 2 times, most recently from 74155f3 to 14b3627 Compare September 7, 2017 02:05
@Laura-O
Copy link
Member

Laura-O commented Sep 7, 2017

Sorry for the delay, here is my feedback:

  • The "To Advance" column is hidden for me:

bildschirmfoto 2017-09-07 um 11 41 35

  • Updating/saving changes:
    Seeing this as a whole interface, I think the "save"-button in the modals might be misleading. The schedule is only updated after clicking the "Update Competition"-button on the bottom of the page. Currently, the button changes the color after edits, but if you do not scroll to the bottom, you will not see the button.
    I think an alert on the top of the page after a round was changed would help (something like "Rounds edited, click 'Update Competition' to update the schedule").

  • The event panels are neat!
    What do you think about letting the user add the individual panels manually?
    When creating schedules with only a small number of events but many rounds, the empty panels look confusing to me.
    Another alternative: I can't remember if there were any plans by the Board to let delegates select events when they create competitions. If there are, this data could be used to create the default panels (e.g., if the delegate selects 222-555 as events, the panels for 222-555 are displayed).

  • The requirement to advance in percent should be limited to a maximum of 75% (it's even possible to enter >100%).

  • Cutoffs can be set to 0 centiseconds.

  • The reset button doesn't work when you have saved the conditions once and then open the modal again.

  • The explanations in the modals for the time limit and the advance requirements are helpful (like "Competitors have 5 minutes for each of their solves."). Adding something similar to the cutoff modal would be nice.

  • It's not possible to set limits to >60 minutes. This is relevant for cumulative time limits (e.g. 90 minutes for 5BLD).

@jfly jfly force-pushed the edit-rounds-ui branch 2 times, most recently from c02c0a3 to 074c297 Compare September 7, 2017 15:05
@jfly jfly mentioned this pull request Sep 7, 2017
6 tasks
@jfly
Copy link
Contributor Author

jfly commented Sep 7, 2017

Thanks for the feedback, @Laura-O! Some responses:

  • The "To Advance" column is hidden for me:

Ah, you must be at an unfortunate screen size, then. If I make this look good for you (2 columns of events instead of 3), it will be wasted space for someone with my screen size. With some work, we can probably find something that's good for both of us, but for now, I don't think it's worth the effort right now. Let's address this later in #1916. Just to be clear, the page is still usable for you, right? There should be horizontal scrollbars when stuff doesn't fit, but I don't see them in your screenshot, which I'm hoping is because you're on a mac and they hide scrollbars, not because the scrollbars don't exist.

I think an alert on the top of the page after a round was changed would help (something like "Rounds edited, click 'Update Competition' to update the schedule").

I like this idea! I've gone ahead and made this change in jfly@03def6c. I figured it would be more useful to just put the button in the alert, how does this look?

image

What do you think about letting the user add the individual panels manually?

Sorry, I'm not sure what you mean here. Maybe it would be best to chat in real time about this?

When creating schedules with only a small number of events but many rounds, the empty panels look confusing to me.

So I tried setting the opacity of events that are not being held to 50% to try to reduce visual clutter, but I guess that's not good enough =(

Another alternative: I can't remember if there were any plans by the Board to let delegates select events when they create competitions

Haha, that's not merely something we allow delegate to do, we require them to do it! Currently competitions are required to have at least 1 event before being confirmed.

If there are, this data could be used to create the default panels (e.g., if the delegate selects 222-555 as events, the panels for 222-555 are displayed).

The new UI you see is an update of the current /events/edit page, so that page you're thinking of does not exist anymore. Just to be clear, here's what I currently see on https://www.worldcubeassociation.org/competitions/BerkeleyWinter2017/events/edit:

image

When we merge this PR, the above page will change to have all the event panels you've been playing around with.

The requirement to advance in percent should be limited to a maximum of 75% (it's even possible to enter >100%).

Done in jfly@ab57c0b.

Cutoffs can be set to 0 centiseconds.

This is a little tricky to implement, and I didn't build the infrastructure for validations yet. I'm going to suggest that we address this in #1916.

The reset button doesn't work when you have saved the conditions once and then open the modal again.

The reset button resets the modal back to the state it was in at the time you opened the modal dialog. It sounds like you expect it to reset the modal back to the state the WCIF was in when you first visited the page? I personally think the current behavior is more useful, because if you want to reset the WCIF back to the state it was in when you first visited the page, you can refresh the page. However if this is just too confusing, maybe we should get rid of the reset buttons entirely?

The explanations in the modals for the time limit and the advance requirements are helpful (like "Competitors have 5 minutes for each of their solves."). Adding something similar to the cutoff modal would be nice.

Done in jfly@f67cf2c. How does this look?

image

It's not possible to set limits to >60 minutes. This is relevant for cumulative time limits (e.g. 90 minutes for 5BLD).

Ah, good point! Fixed in jfly@abcd254.

@jfly
Copy link
Contributor Author

jfly commented Sep 7, 2017

Updated in response to review comments. I pushed some non-critical suggested out into #1916, which I'll address in a later PR. For now, I believe this is ready to go, and I hope to merge this up on Monday (but I'd really love some people to take a look at the code first!)

@coder13
Copy link
Contributor

coder13 commented Sep 8, 2017

Code looks good to me. 👍

@Laura-O
Copy link
Member

Laura-O commented Sep 8, 2017

Skipping some comments as I was confused and @jfly already enlightened me when we chatted about this. 😄

Ah, you must be at an unfortunate screen size, then. If I make this look good for you (2 columns of events instead of 3), it will be wasted space for someone with my screen size. With some work, we can probably find something that's good for both of us, but for now, I don't think it's worth the effort right now. Let's address this later in #1916. Just to be clear, the page is still usable for you, right? There should be horizontal scrollbars when stuff doesn't fit, but I don't see them in your screenshot, which I'm hoping is because you're on a mac and they hide scrollbars, not because the scrollbars don't exist.

Yes, the screenshot was on a 13" MBP. It's still usable.

The reset button resets the modal back to the state it was in at the time you opened the modal dialog. It sounds like you expect it to reset the modal back to the state the WCIF was in when you first visited the page? I personally think the current behavior is more useful, because if you want to reset the WCIF back to the state it was in when you first visited the page, you can refresh the page. However if this is just too confusing, maybe we should get rid of the reset buttons entirely?

Yes, maybe removing is the best solution.
If there is a "reset"-button I expect it to have some functionality. I think showing a reset button, but not allowing resets is weird and I am sure users will report this as a bug.

Done in jfly/worldcubeassociation.org@f67cf2c. How does this look?

Looks good! 👍

@jfly
Copy link
Contributor Author

jfly commented Sep 9, 2017

If there is a "reset"-button I expect it to have some functionality. I think showing a reset button, but not allowing resets is weird and I am sure users will report this as a bug.

(It's very possible I'm misunderstanding you here, so please tell me if I am.) I don't think it's fair to describe this as "not allowing resets". It seems to me that we just have different definitions of "reset". My definition is "reset takes you back to the state the modal was in when you opened the modal". Your definition is "reset takes you back to the state this was in when you first loaded the page". I'd like to get some other people's opinions on what they think makes sense here.

@FatBoyXPC
Copy link
Contributor

Reset should reset to when I first started interacted with whatever thing I am trying to reset.

@coder13
Copy link
Contributor

coder13 commented Sep 9, 2017

It works exactly as I expect it to, does something that I want but I can see where Laura is coming from and maybe it's not the most properly named? Sometimes I do some changes and want to go back to where it was. I might close out of the dialog and reopen it, or hit the reset button.
Maybe add a "default" button? Or remove the Reset button? If anything at all.

@jfly
Copy link
Contributor Author

jfly commented Sep 9, 2017

I had a chat with @FatBoyXPC and @coder13 and we agreed that the behavior of the dialogs was confusing. Here's the system we decided is best:

i'm getting rid of the save button and the reset button
we're going to have an OK and a Close button
close, clicking X, and clicking in the black background will all ask you if you are sure you want to discard your changes before discarding your changes and closing the dialog. if you don't have any changes in the dialog, then you won't be prompted before the dialog is closed
the OK button will "save" your changes, which doesn't mean writing to the database
you still have to hit the save button on the main page to write to the db
(we all agreed that currenty, the save button is very poorly named because it doesn't actually write to the db)

I've implemented this in dca0f2b, and you can see it live on staging now!

Copy link
Member

@jonatanklosko jonatanklosko left a comment

Choose a reason for hiding this comment

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

The first portion of comments, I will continue reviewing tomorrow =)


function normalizeWcifEvents(wcifEvents) {
return events.official.map(event => {
return wcifEvents.find(wcifEvent => wcifEvent.id == event.id) || { id: event.id, rounds: [] };
Copy link
Member

Choose a reason for hiding this comment

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

What about _.find(wcifEvents, { id: event.id }) || ...?


export default {
official: <%= Event.official.to_json.html_safe %>.map(extend),
byId: mapObjectValues(<%= Event.all.index_by(&:id).to_json.html_safe %>, extend),
Copy link
Member

Choose a reason for hiding this comment

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

Let's use Lodash neat function =)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice, done!


function deepEqual(obj1, obj2) {
return JSON.stringify(obj1) == JSON.stringify(obj2);
}
Copy link
Member

Choose a reason for hiding this comment

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

I believe Lodash have these functions (cloneDeep and isEqual accordingly).

this.setState({ savedWcifEvents: clone(this.props.wcifEvents), saving: false });
}).catch(e => {
this.setState({ saving: false });
alert("Something went wrong while saving.\n" + e.message);
Copy link
Member

Choose a reason for hiding this comment

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

A template string, please =)

this.setState({ saving: true });
promiseSaveWcif(wcif).then(response => {
return response.json().then(json => [ response, json ]);
}).then(([response, json]) => {
Copy link
Member

Choose a reason for hiding this comment

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

A matter of preference, but I would write this like that:

promiseSaveWcif(wcif)
  .then(response => Promise.all([response, response.json()]))
  .then(([response, json]) => {
    /* ... */
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like the use of Promise.all here!

Not sure if you also meant to make a point about indentation here, but I do not really like indenting my chained thens, because it looks weird when the chain ends and the level of indentation is more than 1 level off from the next one. See here for a discussion including some folks who also have my school of thought on this.

I also don't want this PR to devolve into a discussion about javascript code formatting. I would like for us to get a linter and style checker set up, and then we can discuss how we want that thing to be configured. I've created #1924 to continue this discussion.

});
});
return roundsSharingTimeLimit;
}
Copy link
Member

Choose a reason for hiding this comment

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

What about this?

function findRoundsSharingTimeLimitWithRound(wcifEvents, wcifRound) {
  return _.flatMap(wcifEvents, 'rounds').filter(otherWcifRound =>
    otherWcifRound !== wcifRound
    && otherWcifRound.timeLimit
    && otherWcifRound.timeLimit.cumulativeRoundIds.includes(wcifRound.id)
  );
}

});
});
return wcifRounds;
}
Copy link
Member

Choose a reason for hiding this comment

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

What about this?

function findRounds(wcifEvents, roundIds) {
  return _.flatMap(wcifEvents, 'rounds').filter(wcifRound => roundIds.include(wcifRound.id));
}

}

hasUnsavedChanges = () => {
return JSON.stringify(this.getSavedValue()) != JSON.stringify(this.state.value);
Copy link
Member

Choose a reason for hiding this comment

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

Let's Lodash do the trick return _.isEqual(this.getSavedValue(), this.state.value);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nit, we want to check if they're not equal, not if if they are equal =)

}

onChange = (value) => {
this.setState({ value: value });
Copy link
Member

Choose a reason for hiding this comment

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

You can simply do this.setState({ value }); as the key name matches the variable name =)

throw new Error();
}
otherWcifRound.timeLimit.cumulativeRoundIds.splice(index, 1);
});
Copy link
Member

Choose a reason for hiding this comment

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

I think this could simply be:

findRoundsSharingTimeLimitWithRound(this.props.wcifEvents, wcifRound).forEach(otherWcifRound => {
  _.pull(otherWcifRound.timeLimit.cumulativeRoundIds, wcifRound.id);
});

jfly and others added 24 commits September 17, 2017 11:11
The AttemptResultInput component still needs to be implemented, but I
think it provides the right abstraction.
Also formatting our selects consistently.
Also updated the error message dialog to include the error from the
server, so the user has some idea what's going on.
message before removing existing rounds of an event.
- Spread the rounds across multiple rows instead of columns.
- Improved explanation for cutoff and time limit.
A competition event with 0 rounds means "yes, we're holding this
event, but the number of rounds has not been decided yet or has not been
announced yet"
@jfly jfly merged commit daddce7 into thewca:master Sep 17, 2017
@jfly jfly deleted the edit-rounds-ui branch September 17, 2017 18:24
@lgarron
Copy link
Member

lgarron commented Sep 19, 2017

The requirement to advance in percent should be limited to a maximum of 75% (it's even possible to enter >100%).
Done in jfly/worldcubeassociation.org@ab57c0b.

It seems that the demo competition still has 100% set for the first round of multi. ;-)

@jfly
Copy link
Contributor Author

jfly commented Sep 19, 2017

Yeah, it's just a silly ui input max right now. Later improvement will be to validate this server side.

@viroulep viroulep mentioned this pull request Jul 1, 2018
4 tasks
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.

8 participants