From fa98c30c003efd5228b8f2f4ec8ddc8fc4b95344 Mon Sep 17 00:00:00 2001 From: Dylan Ross Date: Fri, 28 Aug 2015 16:05:11 -0600 Subject: [PATCH] show spinner and enable assignment muting fixes CNVS-22027 test plan - mute an assignment - ensure menu item displays 'Mute Assignment' - ensure the 'muted assignment' icon shows up next to the assignment name - click the menu again - ensure the menu item displays 'Unmute Assignment' - click unmute and verify the mute assignment icon has been removed. - verify a spinner displays as the gradebook is loading Change-Id: I80b4701ceb6905c9e0c48a9b5ddc6fc9975a7124 Reviewed-on: https://gerrit.instructure.com/63177 Reviewed-by: Spencer Olson Tested-by: Jenkins QA-Review: Jason Carter Product-Review: Dylan Ross --- app/coffeescripts/AssignmentMuter.coffee | 15 +++-- .../grid/actions/assignmentGroupsActions.jsx | 3 +- .../column_types/headerRenderer.jsx | 8 ++- .../assignmentHeaderDropdownOptions.jsx | 12 ++-- .../muteAssignmentOption.jsx | 62 +++++++++++++++++++ .../gradebook/grid/components/gradebook.jsx | 27 ++++++-- .../grid/stores/assignmentGroupsStore.jsx | 10 +++ .../muteAssignmentOptionSpec.coffee | 62 +++++++++++++++++++ 8 files changed, 181 insertions(+), 18 deletions(-) create mode 100644 app/jsx/gradebook/grid/components/dropdown_components/muteAssignmentOption.jsx create mode 100644 spec/coffeescripts/jsx/gradebook/grid/components/dropdown_components/muteAssignmentOptionSpec.coffee diff --git a/app/coffeescripts/AssignmentMuter.coffee b/app/coffeescripts/AssignmentMuter.coffee index f863b4b200b..e282f8e981b 100644 --- a/app/coffeescripts/AssignmentMuter.coffee +++ b/app/coffeescripts/AssignmentMuter.coffee @@ -9,12 +9,15 @@ define [ ], (I18n, $, mute_dialog_template) -> class AssignmentMuter - constructor: (@$link, @assignment, @url, @setter) -> - @$link = $(@$link) - @updateLink() - @$link.click (event) => - event.preventDefault() + constructor: (@$link, @assignment, @url, @setter, @options) -> + if @options?.openDialogInstantly if @assignment.muted then @confirmUnmute() else @showDialog() + else + @$link = $(@$link) + @updateLink() + @$link.click (event) => + event.preventDefault() + if @assignment.muted then @confirmUnmute() else @showDialog() updateLink: => @$link.text(if @assignment.muted then I18n.t('unmute_assignment', 'Unmute Assignment') else I18n.t('mute_assignment', 'Mute Assignment')) @@ -37,7 +40,7 @@ define [ @setter @assignment, 'muted', serverResponse.assignment.muted else @assignment.muted = serverResponse.assignment.muted - @updateLink() + @updateLink() unless @options?.openDialogInstantly @$dialog.dialog('close') $.publish('assignment_muting_toggled', [@assignment]) diff --git a/app/jsx/gradebook/grid/actions/assignmentGroupsActions.jsx b/app/jsx/gradebook/grid/actions/assignmentGroupsActions.jsx index f0eaaa8d50e..7b2cb73f2ba 100644 --- a/app/jsx/gradebook/grid/actions/assignmentGroupsActions.jsx +++ b/app/jsx/gradebook/grid/actions/assignmentGroupsActions.jsx @@ -4,7 +4,8 @@ define([ ], function (Reflux, $) { var AssignmentGroupsActions = Reflux.createActions({ load: { asyncResult: true }, - replaceAssignmentGroups: { asyncResult: false } + replaceAssignmentGroups: { asyncResult: false }, + replaceAssignment: {asyncResult: false} }); AssignmentGroupsActions.load.listen(function() { diff --git a/app/jsx/gradebook/grid/components/column_types/headerRenderer.jsx b/app/jsx/gradebook/grid/components/column_types/headerRenderer.jsx index dc390a4d70a..18a9ad3fc95 100644 --- a/app/jsx/gradebook/grid/components/column_types/headerRenderer.jsx +++ b/app/jsx/gradebook/grid/components/column_types/headerRenderer.jsx @@ -70,10 +70,14 @@ define([ label = this.props.label; if (assignment) { - var paddingAdjustment = GradebookConstants.DEFAULT_LAYOUTS.headers.paddingAdjustment; + var paddingAdjustment = GradebookConstants.DEFAULT_LAYOUTS.headers.paddingAdjustment, + className = "assignment-name" + ((assignment.muted) ? ' muted' : ''); + return (
- + { this.shouldDisplayAssignmentWarning() && } {label} diff --git a/app/jsx/gradebook/grid/components/dropdown_components/assignmentHeaderDropdownOptions.jsx b/app/jsx/gradebook/grid/components/dropdown_components/assignmentHeaderDropdownOptions.jsx index 07441626bb1..bd41d86d718 100644 --- a/app/jsx/gradebook/grid/components/dropdown_components/assignmentHeaderDropdownOptions.jsx +++ b/app/jsx/gradebook/grid/components/dropdown_components/assignmentHeaderDropdownOptions.jsx @@ -5,8 +5,9 @@ define([ 'i18n!gradebook', 'jsx/gradebook/grid/components/dropdown_components/headerDropdownOption', 'jsx/gradebook/grid/constants', - 'jsx/gradebook/grid/components/dropdown_components/setDefaultGradeOption' -], function (React, _, I18n, HeaderDropdownOption, GradebookConstants, SetDefaultGradeOption) { + 'jsx/gradebook/grid/components/dropdown_components/setDefaultGradeOption', + 'jsx/gradebook/grid/components/dropdown_components/muteAssignmentOption' +], function (React, _, I18n, HeaderDropdownOption, GradebookConstants, SetDefaultGradeOption, MuteAssignmentOption) { var AssignmentHeaderDropdownOptions = React.createClass({ @@ -46,9 +47,6 @@ define([ dropdownOptions.splice(1, 0, speedGraderOption); } - muteAssignmentOption = { title: I18n.t('Mute Assignment'), action: 'toggleMuting' }; - if (assignment.muted) muteAssignmentOption.title = I18n.t('Unmute Assignment'); - dropdownOptions.push(muteAssignmentOption); return dropdownOptions; }, @@ -83,6 +81,10 @@ define([ } }) } + + ); } diff --git a/app/jsx/gradebook/grid/components/dropdown_components/muteAssignmentOption.jsx b/app/jsx/gradebook/grid/components/dropdown_components/muteAssignmentOption.jsx new file mode 100644 index 00000000000..0df63950303 --- /dev/null +++ b/app/jsx/gradebook/grid/components/dropdown_components/muteAssignmentOption.jsx @@ -0,0 +1,62 @@ + +/** @jsx React.DOM */ +define([ + 'react', + 'jquery', + 'bower/reflux/dist/reflux', + 'underscore', + 'i18n!gradebook', + 'jsx/gradebook/grid/components/dropdown_components/headerDropdownOption', + 'compiled/AssignmentMuter', + 'jsx/gradebook/grid/constants', + 'jsx/gradebook/grid/actions/assignmentGroupsActions' +], function ( + React, + $, + Reflux, + _, + I18n, + HeaderDropdownOption, + AssignmentMuter, + GradebookConstants, + AssignmentGroupsActions +) { + + const MUTE = I18n.t('Mute Assignment'), + UNMUTE = I18n.t('Unmute Assignment'), + MUTING_EVENT = 'assignment_muting_toggled'; + + var MuteAssignmentOption = React.createClass({ + + propTypes: { + assignment: React.PropTypes.object.isRequired + }, + + openDialog() { + var assignment = this.props.assignment, + contextUrl = GradebookConstants.context_url, + options = {openDialogInstantly: true}, + id = assignment.id, + url = contextUrl + "/assignments/" + id + "/mute"; + + new AssignmentMuter(null, assignment, url, null, options); + + $.subscribe(MUTING_EVENT, (assignment) => { + AssignmentGroupsActions.replaceAssignment(assignment); + $.unsubscribe(MUTING_EVENT); + }); + }, + + render() { + var title = (this.props.assignment.muted) ? UNMUTE : MUTE; + return( + + ); + } + }); + + return MuteAssignmentOption; +}); diff --git a/app/jsx/gradebook/grid/components/gradebook.jsx b/app/jsx/gradebook/grid/components/gradebook.jsx index d00bfd23deb..e9ae02e4ace 100644 --- a/app/jsx/gradebook/grid/components/gradebook.jsx +++ b/app/jsx/gradebook/grid/components/gradebook.jsx @@ -21,7 +21,8 @@ define([ '../actions/submissionsActions', '../stores/keyboardNavigationStore', '../actions/keyboardNavigationActions', - '../helpers/columnArranger' + '../helpers/columnArranger', + 'vendor/spin' ], function ( React, FixedDataTable, @@ -44,12 +45,14 @@ define([ SubmissionsActions, KeyboardNavigationStore, KeyboardNavigationActions, - ColumnArranger + ColumnArranger, + Spinner ){ var Table = FixedDataTable.Table, Column = FixedDataTable.Column, - isColumnResizing = false; + isColumnResizing = false, + spinner; var Gradebook = React.createClass({ mixins: [ @@ -215,6 +218,15 @@ define([ || this.state.submissions.error; }, + renderSpinner() { + spinner = new Spinner(); + $(spinner.spin().el).css({ + opacity: 0.5, + top: '55px', + left: '50%' + }).addClass('use-css-transitions-for-show-hide').appendTo('#main'); + }, + renderNotesColumn() { if (!this.state.toolbarOptions.hideNotesColumn) { return this.renderColumn(I18n.t('Notes'), GradebookConstants.NOTES_COLUMN_ID); @@ -242,6 +254,9 @@ define([ } else if (this.state.submissions.data && this.state.assignmentGroups.data && this.state.studentEnrollments.data) { + + $(spinner.el).remove(); + return (
); } else { - return (

{I18n.t('Gradebook loading...replace this with a spinner?')}

); + if (!spinner) { + this.renderSpinner(); + } + + return
; } } }); diff --git a/app/jsx/gradebook/grid/stores/assignmentGroupsStore.jsx b/app/jsx/gradebook/grid/stores/assignmentGroupsStore.jsx index c9ec5ddb6c8..cf91fa9ea48 100644 --- a/app/jsx/gradebook/grid/stores/assignmentGroupsStore.jsx +++ b/app/jsx/gradebook/grid/stores/assignmentGroupsStore.jsx @@ -44,6 +44,16 @@ define([ }); }, + onReplaceAssignment(updatedAssignment) { + var assignmentGroups = this.assignmentGroups.data, + assignments = _.flatten(_.pluck(assignmentGroups, 'assignments')), + assignment = _.find(assignments, assignment => updatedAssignment.id === assignment.id); + + assignment.muted = updatedAssignment.muted; + this.assignmentGroups.data = assignmentGroups; + this.trigger(this.assignmentGroups); + }, + formatAssignmentGroups(groups) { return _.map(groups, (group) => { group.assignments = _.map( diff --git a/spec/coffeescripts/jsx/gradebook/grid/components/dropdown_components/muteAssignmentOptionSpec.coffee b/spec/coffeescripts/jsx/gradebook/grid/components/dropdown_components/muteAssignmentOptionSpec.coffee new file mode 100644 index 00000000000..7912e811f3a --- /dev/null +++ b/spec/coffeescripts/jsx/gradebook/grid/components/dropdown_components/muteAssignmentOptionSpec.coffee @@ -0,0 +1,62 @@ +define [ + 'jsx/gradebook/grid/components/dropdown_components/muteAssignmentOption', + 'compiled/gradebook2/SetDefaultGradeDialog' + 'jquery' +], (SetDefaultGradeOption, SetDefaultGradeDialog, $) -> + + wrapper = document.getElementById('fixtures') + + defaultProps = -> + assignment: { id: '1', muted: false } + + renderComponent = (props) -> + props = props || defaultProps() + componentFactory = React.createFactory(SetDefaultGradeOption) + React.render(componentFactory(props), wrapper) + + module 'MuteAssignmentOption', + setup: -> + $('.ui-dialog').remove() + @component = renderComponent() + teardown: -> + $('.ui-dialog').remove() + React.unmountComponentAtNode wrapper + + test 'mounts properly', -> + ok renderComponent().isMounted() + + test 'displays "Mute Assignment" when assignment is unmuted', -> + component = renderComponent() + text = component.getDOMNode().children[0].innerHTML + deepEqual(text, 'Mute Assignment') + + test 'displays "Unmute Assignment" when assignment is muted', -> + props = {assignment: {id: '1', muted: true}} + component = renderComponent(props) + text = component.getDOMNode().children[0].innerHTML + deepEqual(text, 'Unmute Assignment') + + test 'displays dialog on click', -> + component = renderComponent() + equal($('.ui-dialog').size(), 0) + component.openDialog() + equal($('.ui-dialog').size(), 1) + + test 'mute dialog displays when assignment is unmuted', -> + component = renderComponent() + component.openDialog() + title = $('.ui-dialog-title')[0].innerHTML + equal(title, 'Mute Assignment') + + test 'unmute dialog displays when assignment is muted', -> + props = {assignment: {id: '1', muted: true}} + component = renderComponent(props) + component.openDialog() + title = $('.ui-dialog-title')[0].innerHTML + equal(title, 'Unmute Assignment') + + test '$subscribe to assignment_muting_toggled event after dialog is opened', -> + subscribeStub = @stub($, 'subscribe') + component = renderComponent() + component.openDialog() + ok subscribeStub.calledWith('assignment_muting_toggled')