add total number of students to ember message students dialog

fixes CNVS-13153

test plan:
  - enable 'new quiz stats' flag
  - as a teacher
    - create a quiz
    - visit the quiz
    - the menu item for messaging a student has been adjusted to say
      "Message Students Who..."
    - click on this option
    - it should show the list of students who have taken the quiz up to 10
      stents. If more than 10 students are available, it should say
      "and {number} more students"
    - switching recipients between students who have taken the quiz, and students
      who have not taken the quiz should work. It should resize the dialog to
      allow for more room if more students are listed.
    - entering a message should send successfully
    - if you attempt to send the message with no message, the modal dialog will
      close and a warning message will tell you it didn't send

Change-Id: I964de663a5b84daaf5a723694e975eaa147505d7
Reviewed-on: https://gerrit.instructure.com/35870
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Jason Madsen <jmadsen@instructure.com>
QA-Review: Trevor deHaan <tdehaan@instructure.com>
Product-Review: Derek DeVries <ddevries@instructure.com>
This commit is contained in:
Derek DeVries 2014-06-03 17:22:52 -06:00
parent abf9d8f0cd
commit 47434d86ae
15 changed files with 196 additions and 98 deletions

View File

@ -42,6 +42,8 @@ define [
position: @get('position')
close: => @sendAction('_destroyAction')
@set("dialog", $el)
uiDialog = $el
.dialog('open')
.data('dialog')
@ -60,6 +62,11 @@ define [
).on 'didInsertElement'
adjustDimensions: (->
@get('dialog').dialog("option", "height", @get('height'))
@get('dialog').dialog("option", "width", @get('width'))
).observes('height', 'width')
_close: ->
@$().dialog 'close'

View File

@ -0,0 +1,74 @@
define [
'ember'
'ic-ajax'
'i18n!quiz_message_students'
], (Ember, ajax, I18n) ->
{equal} = Ember.computed
Ember.ArrayController.extend
needs: ['quiz']
quiz: Ember.computed.alias('controllers.quiz.model')
title: I18n.t('message_students_who', 'Message Students Who...')
recipientGroups: (->
[
Ember.Object.create({
id: 'submitted'
name: I18n.t('students_who_have_taken_the_quiz', 'Students Who Have Taken the Quiz'),
})
Ember.Object.create({
id: 'unsubmitted'
name: I18n.t('student_who_have_not_taken_the_quiz', 'Students Who Have Not Taken the Quiz')
})
]
).property('quiz.submittedStudents', 'quiz.unsubmittedStudents')
recipients: (->
if @get('selectedRecipientGroup') is 'submitted'
@get('quiz.submittedStudents')
else
@get('quiz.unsubmittedStudents')
).property('selectedRecipientGroup', 'quiz.submittedStudents', 'quiz.unsubmittedStudents')
showUnsubmitted: equal 'selectedRecipientGroup', 'unsubmitted'
noRecipients: equal 'recipients.length', 0
moreRecipientsLabel: (->
if @get('selectedRecipientGroup') is 'submitted'
pagination = @store.metadataFor("submittedStudent").pagination
shown = @get('quiz.submittedStudents.length')
else
pagination = @store.metadataFor("unsubmittedStudent").pagination
shown = @get('quiz.unsubmittedStudents.length')
total = if pagination then pagination.count else 0
if total > shown
I18n.t('and_num_more_students', 'and %{num} more students', num: total - shown)
).property('selectedRecipientGroup', 'quiz.submittedStudents', 'quiz.unsubmittedStudents')
# base height + 10px height for every student
modalHeight: (->
325 + @get('recipients.length') * 10
).property('recipients', 'recipients.isFulfilled')
actions:
submit: ->
if @get('messageBody')
ajax
url: @get('quiz.messageStudentsUrl')
data: JSON.stringify(
conversations: [
recipients: @get('selectedRecipientGroup')
body: @get('messageBody')
]
)
type: 'POST'
dataType: 'json'
contentType: 'application/json'
Ember.$.flashMessage I18n.t 'message_sent_successfully', 'Message sent successfully'
else
Ember.$.flashWarning I18n.t 'message_not_sent_because_empty', 'Message not sent because it was left empty'

View File

@ -6,9 +6,6 @@ define [
'compiled/jquery.rails_flash_notifications'
], (Ember, I18n, $, env) ->
{RSVP, K} = Ember
{equal} = Ember.computed
updateAllDates = (field) ->
date = new Date()
@set field, date
@ -19,7 +16,7 @@ define [
# override.set field, date
# override.save()
promises.pushObject(@get('model').save())
RSVP.all promises
Ember.RSVP.all promises
QuizController = Ember.ObjectController.extend
legacyQuizSubmissionVersionsReady: Ember.computed.and('quizSubmissionVersionsHtml', 'didLoadQuizSubmissionVersionsHtml')
@ -45,6 +42,10 @@ define [
@get('published') and @get('takeable') and !@get('lockedForUser')
).property('published', 'takeable', 'lockedForUser')
messageStudentsActive: (->
@get('published')
).property('published')
takeOrResumeMessage: (->
if @get('quizSubmission.isCompleted')
if @get('isSurvey')
@ -112,34 +113,6 @@ define [
I18n.t('time_limit_minutes', "%{limit} minutes", {limit: @get("timeLimit")})
).property('timeLimit')
# message students modal
recipientGroups: (->
[
Ember.Object.create({
id: 'submitted'
name: I18n.t('students_who_have_taken_the_quiz', 'Students Who Have Taken the Quiz'),
})
Ember.Object.create({
id: 'unsubmitted'
name: I18n.t('student_who_have_not_taken_the_quiz', 'Students Who Have Not Taken the Quiz')
})
]
).property('submittedStudents', 'unsubmittedStudents')
recipients: (->
if @get('selectedRecipientGroup') is 'submitted'
@get('submittedStudents')
else
@get('unsubmittedStudents')
).property('selectedRecipientGroup', 'submittedStudents', 'unsubmittedStudents')
showUnsubmitted: equal 'selectedRecipientGroup', 'unsubmitted'
noRecipients: equal 'recipients.length', 0
# /message students modal
actions:
takeQuiz: ->
if @get 'takeQuizActive'
@ -162,6 +135,12 @@ define [
else
$.flashWarning I18n.t('there_are_no_submissions_to_grade', 'There are no submissions to grade.')
messageStudents: ->
if !@get('messageStudentsActive')
$.flashWarning I18n.t('you_cannot_message_unpublished', 'You can not message students until this quiz is published.')
else
true
moderateQuiz: ->
window.location = @get 'moderateUrl'
@ -205,26 +184,6 @@ define [
model.save().then =>
@transitionToRoute 'quizzes'
# message students modal
sendMessageToStudents: ->
$.ajax
url: @get('messageStudentsUrl')
data: JSON.stringify(
conversations: [
recipients: @get('selectedRecipientGroup')
body: @get('messageBody')
]
)
type: 'POST'
dataType: 'json'
contentType: 'application/json'
$.flashMessage I18n.t 'message_sent', 'Message Sent'
# For modal, just do nothing.
cancel: K
# /message students modal
# Kind of a gross hack so we can get quiz arrows in...
addLegacyJS: (->
return unless @get('quizSubmissionHTML.html')

View File

@ -137,8 +137,8 @@ define [
Ember.A(dates.concat(overrides))
).property('lockAt', 'unlockAt', 'dueAt', 'sectionCount', 'assignmentOverrides.[]')
submittedStudents: hasMany 'user', polymporphic: true, async: true
unsubmittedStudents: hasMany 'user', polymorphic: true, async: true
submittedStudents: hasMany 'submitted_student', polymporphic: true, async: true
unsubmittedStudents: hasMany 'unsubmitted_student', polymorphic: true, async: true
messageStudentsUrl: attr()
quizExtensionsUrl: attr()
quizSubmission: belongsTo 'quiz_submission'

View File

@ -1,7 +1,7 @@
define [
'ember'
'ember-data'
], (Em, DS, ajax) ->
], (Em, DS) ->
{alias, equal, any} = Em.computed
computed = Em.computed

View File

@ -0,0 +1,6 @@
define [
'ember-data'
'./user'
], (DS, User) ->
SubmittedStudent = User.extend()

View File

@ -0,0 +1,6 @@
define [
'ember-data'
'./user'
], (DS, User) ->
UnsubmittedStudent = User.extend()

View File

@ -37,6 +37,6 @@ define [
outlet: 'modal'
messageStudents: ->
@render 'message_students',
@render 'quiz/message_students',
into: 'application'
outlet: 'modal'

View File

@ -0,0 +1,8 @@
define [
'ember-data'
'./user_serializer'
], (DS, UserSerializer) ->
SubmittedStudentSerializer = UserSerializer.extend
typeForRoot: (root) ->
return @_super('submitted_students')

View File

@ -0,0 +1,8 @@
define [
'ember-data'
'./user_serializer'
], (DS, UserSerializer) ->
UnsubmittedStudentSerializer = UserSerializer.extend
typeForRoot: (root) ->
return @_super('unsubmitted_students')

View File

@ -1,38 +0,0 @@
{{#form-dialog
title="Message Students"
on-submit="sendMessageToStudents"
submit-disabled=noRecipients
height=500
width=500
fix-dialog-buttons=false
}}
<div id="message-students-dialog">
<label for="select-recipient-group">
{{#t 'recipients'}}Recipients{{/t}}
</label>
{{fast-select
items=recipientGroups
value=selectedRecipientGroup
class="input-xlarge"
valuePath="id"
labelPath="name"
id="select-recipient-group"
}}
<div>
{{#if recipients.isFulfilled}}
{{#each recipients}}
<span class="label">{{shortName}}</span>
{{/each}}
{{else}}
<img src='/images/ajax-loader-medium-444.gif'/>
{{#t 'loading'}}Loading{{/t}}
{{/if}}
</div>
<label for=message-body>
Message
</label>
{{textarea value=messageBody id='message-body'}}
</div>
{{/form-dialog}}

View File

@ -58,9 +58,16 @@
{{/ic-menu-item}}
{{/unless}}
{{#ic-menu-item on-select="messageStudents" class="js-message-students"}}
{{#ic-menu-item on-select="messageStudents" classBinding=":js-message-students messageStudentsActive::disabled"}}
<i class="icon-discussion"></i>
{{#t 'Message Students'}}Message Students{{/t}}
{{#if messageStudentsActive}}
{{#t 'message_students_who'}}Message Students Who...{{/t}}
{{else}}
<span class="disabled">
{{#t 'message_students_who'}}Message Students Who...{{/t}}
<span class="screenreader-only">{{#t "option_is_disabled"}}this option is disabled{{/t}}</span>
</span>
{{/if}}
{{/ic-menu-item}}
{{#ic-menu-item on-select="showStudentResults"}}

View File

@ -0,0 +1,43 @@
{{#form-dialog
title=title
on-submit="submit"
submit-disabled=noRecipients
height=modalHeight
width=500
fix-dialog-buttons=false
}}
<div class="message-students-who-dialog">
<div class="field">
<label for="select-recipient-group">
{{#t 'recipients'}}Recipients{{/t}}
</label>
{{fast-select
items=recipientGroups
value=selectedRecipientGroup
class="input-xlarge"
valuePath="id"
labelPath="name"
id="select-recipient-group"
}}
</div>
<div class="recipients">
{{#if recipients.isFulfilled}}
{{#each recipients}}
<span class="label">{{shortName}}</span>
{{/each}}
<span class="more-label">
{{moreRecipientsLabel}}
</span>
{{else}}
<img src='/images/ajax-loader-medium-444.gif'/>
{{#t 'loading'}}Loading{{/t}}
{{/if}}
</div>
<label for="message-body">
{{#t 'message'}}Message{{/t}}
</label>
{{textarea value=messageBody id='message-body'}}
</div>
{{/form-dialog}}

View File

@ -63,7 +63,7 @@ define [
"mobile_url":"http://localhost:3000/courses/1/quizzes/1?force_user=1&persist_headless=1",
"message_students_url": "http://localhost:3000/courses/1/quizzes/1/submission_users/message",
"question_count":0,
"published":false,
"published":true,
"unpublishable":true,
"locked_for_user":false
"permissions":

View File

@ -249,12 +249,30 @@
// Dialogs - Put outside the #quiz_show scope because jQueryUI puts
// it in the body.
#message-students-dialog {
.message-students-who-dialog {
.field {
margin-bottom: 11px;
}
.recipients {
margin-bottom: 11px;
}
select {
margin-bottom: 0;
width: 300px;
}
.label {
margin: 2px 0;
}
.more-label {
font-size: 88%;
color: #666;
}
textarea {
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
width: 100%;
height: 90px;
}
}