add users from courses/:id/users page
test plan: 1. go to /courses/:id/users 2. click 'add users' 3. should work much like the add users UI in the course settings -> users tab, but look a little different Change-Id: Icec24a41385e595d8b79dc5a7232545f0aff926e Reviewed-on: https://gerrit.instructure.com/18888 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Ryan Florence <ryanf@instructure.com> Product-Review: Ryan Florence <ryanf@instructure.com> QA-Review: Ryan Florence <ryanf@instructure.com>
This commit is contained in:
parent
3552fb3020
commit
b18af81c24
|
@ -141,12 +141,12 @@ define [
|
|||
_afterRender: ->
|
||||
@cacheEls()
|
||||
@createBindings()
|
||||
@afterRender()
|
||||
# TODO: remove this when `options.views` is removed
|
||||
@renderViews() if @options.views
|
||||
# renderChildViews must come last! so we don't cache all the
|
||||
# renderChildViews must come after cacheEls so we don't cache all the
|
||||
# child views elements, bind them to model data, etc.
|
||||
@renderChildViews()
|
||||
@afterRender()
|
||||
|
||||
##
|
||||
# Define in subclasses to add behavior to your view, ie. creating
|
||||
|
@ -295,5 +295,9 @@ define [
|
|||
view.render()
|
||||
@[selector] ?= view
|
||||
|
||||
hide: -> @$el.hide()
|
||||
show: -> @$el.show()
|
||||
toggle: -> @$el.toggle()
|
||||
|
||||
Backbone.View
|
||||
|
||||
|
|
|
@ -16,16 +16,18 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
require [
|
||||
'compiled/models/CreateUserList'
|
||||
'compiled/views/courses/roster/CreateUsersView'
|
||||
'compiled/views/SelectView'
|
||||
'jst/courses/roster/rosterUsers'
|
||||
'compiled/collections/RosterUserCollection'
|
||||
'compiled/collections/SectionCollection'
|
||||
'compiled/views/InputFilterView'
|
||||
'compiled/views/PaginatedCollectionView'
|
||||
'compiled/views/courses/RosterUserView'
|
||||
'compiled/views/courses/RosterView'
|
||||
'compiled/views/courses/roster/RosterUserView'
|
||||
'compiled/views/courses/roster/RosterView'
|
||||
'jquery'
|
||||
], (SelectView, rosterUsersTemplate, RosterUserCollection, SectionCollection, InputFilterView, PaginatedCollectionView, RosterUserView, RosterView, $) ->
|
||||
], (CreateUserList, CreateUsersView, SelectView, rosterUsersTemplate, RosterUserCollection, SectionCollection, InputFilterView, PaginatedCollectionView, RosterUserView, RosterView, $) ->
|
||||
|
||||
fetchOptions =
|
||||
include: ['avatar_url', 'enrollments', 'email']
|
||||
|
@ -43,12 +45,20 @@ require [
|
|||
template: rosterUsersTemplate
|
||||
roleSelectView = new SelectView
|
||||
collection: users
|
||||
createUsersView = new CreateUsersView
|
||||
model: new CreateUserList
|
||||
sections: ENV.SECTIONS
|
||||
roles: ENV.ALL_ROLES
|
||||
readURL: ENV.USER_LISTS_URL
|
||||
updateURL: ENV.ENROLL_USERS_URL
|
||||
@app = new RosterView
|
||||
usersView: usersView
|
||||
inputFilterView: inputFilterView
|
||||
roleSelectView: roleSelectView
|
||||
createUsersView: createUsersView
|
||||
collection: users
|
||||
roles: ENV.ALL_ROLES
|
||||
permissions: ENV.permissions
|
||||
|
||||
@app.render()
|
||||
@app.$el.appendTo $('#content')
|
||||
|
|
|
@ -9,7 +9,10 @@ require [
|
|||
], ($, preventDefault) ->
|
||||
|
||||
do ->
|
||||
dialog = $('#dialog-buttons-dialog').dialog(autoOpen: false).data('dialog')
|
||||
dialog = $('#dialog-buttons-dialog').dialog({
|
||||
autoOpen: false
|
||||
height: 200
|
||||
}).data('dialog')
|
||||
$('#show-dialog-buttons-dialog').click -> dialog.open()
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ define [
|
|||
buttons = $.map $buttons.toArray(), (button) ->
|
||||
$button = $(button)
|
||||
classes = $button.attr('class') ? ''
|
||||
id = $button.attr('id')
|
||||
|
||||
# if you add the class 'dialog_closer' to any of the buttons,
|
||||
# clicking it will cause the dialog to close
|
||||
|
@ -32,8 +33,9 @@ define [
|
|||
"data-text-while-loading": $button.data("textWhileLoading")
|
||||
click: -> $button.click()
|
||||
class: classes
|
||||
id: id
|
||||
}
|
||||
# put the primary button(s) on the far right
|
||||
buttons = _.sortBy buttons, (button) ->
|
||||
if button.class.match(/btn-primary/) then 1 else 0
|
||||
$dialog.dialog "option", "buttons", buttons
|
||||
$dialog.dialog "option", "buttons", buttons
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
define ['Backbone', 'underscore'], ({Model}, _) ->
|
||||
|
||||
class CreateUserList extends Model
|
||||
|
||||
defaults:
|
||||
roles: null
|
||||
sections: null
|
||||
course_section_id: null
|
||||
enrollment_type: null
|
||||
user_list: null
|
||||
readURL: null
|
||||
updateURL: null
|
||||
step: 1
|
||||
enrolledUsers: null
|
||||
|
||||
present: ->
|
||||
json = @attributes
|
||||
json.course_section_id = parseInt json.course_section_id, 10
|
||||
json
|
||||
|
||||
toJSON: ->
|
||||
attrs = [
|
||||
'course_section_id'
|
||||
'enrollment_type'
|
||||
'user_list'
|
||||
'limit_privileges_to_course_section'
|
||||
]
|
||||
json = _.pick @attributes, attrs...
|
||||
|
||||
url: ->
|
||||
if @get('step') is 1
|
||||
@get 'readURL'
|
||||
else
|
||||
@get 'updateURL'
|
||||
|
||||
incrementStep: ->
|
||||
@set 'step', @get('step') + 1
|
||||
|
||||
startOver: ->
|
||||
@set 'users', null
|
||||
@set 'step', 1
|
||||
|
||||
parse: (data) ->
|
||||
if _.isArray(data)
|
||||
enrolledUsers: data
|
||||
else
|
||||
data
|
||||
|
|
@ -39,6 +39,12 @@ define [
|
|||
# will figure out the title from the trigger if null
|
||||
title: null
|
||||
|
||||
width: null
|
||||
|
||||
height: null
|
||||
|
||||
fixDialogButtons: true
|
||||
|
||||
$dialogAppendTarget: $ 'body'
|
||||
|
||||
className: 'dialogFormView'
|
||||
|
@ -98,8 +104,14 @@ define [
|
|||
@$el.appendTo @$dialogAppendTarget
|
||||
|
||||
##
|
||||
# @api private
|
||||
setTrigger: ->
|
||||
# If your trigger isn't rendered after this view (like a parent view
|
||||
# contains the trigger) then you can set this manually (like in the
|
||||
# parent views afterRender), otherwise it'll use the options.
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
setTrigger: (el) ->
|
||||
@options.trigger = el if el
|
||||
return unless @options.trigger
|
||||
@$trigger = $ @options.trigger
|
||||
@attachTrigger()
|
||||
|
@ -112,7 +124,7 @@ define [
|
|||
##
|
||||
# @api private
|
||||
renderEl: =>
|
||||
@$el.html @wrapperTemplate()
|
||||
@$el.html @wrapperTemplate @toJSON()
|
||||
@renderOutlet()
|
||||
# reassign: only render the outlout now
|
||||
@renderEl = @renderOutlet
|
||||
|
@ -120,7 +132,7 @@ define [
|
|||
##
|
||||
# @api private
|
||||
renderOutlet: =>
|
||||
html = @template @model.toJSON()
|
||||
html = @template @toJSON()
|
||||
@$el.find('.outlet').html html
|
||||
|
||||
##
|
||||
|
@ -137,10 +149,15 @@ define [
|
|||
##
|
||||
# @api private
|
||||
setupDialog: ->
|
||||
@$el.dialog
|
||||
opts =
|
||||
autoOpen: false
|
||||
title: @getDialogTitle()
|
||||
.fixDialogButtons()
|
||||
close: => @trigger 'close'
|
||||
open: => @trigger 'open'
|
||||
opts.width = @options.width
|
||||
opts.height = @options.height
|
||||
@$el.dialog(opts)
|
||||
@$el.fixDialogButtons() if @options.fixDialogButtons
|
||||
@dialog = @$el.data 'dialog'
|
||||
|
||||
##
|
||||
|
|
|
@ -7,7 +7,7 @@ define [
|
|||
'jquery.toJSON'
|
||||
'jquery.disableWhileLoading'
|
||||
'jquery.instructure_forms'
|
||||
], (Backbone, ValidatedMixin, $, _, preventDefault) ->
|
||||
], (Backbone, ValidatedMixin, $, _) ->
|
||||
|
||||
##
|
||||
# Sets model data from a form, saves it, and displays errors returned in a
|
||||
|
@ -45,7 +45,8 @@ define [
|
|||
#
|
||||
# @api public
|
||||
# @returns jqXHR
|
||||
submit: preventDefault ->
|
||||
submit: (event) ->
|
||||
event?.preventDefault()
|
||||
@$el.hideErrors()
|
||||
|
||||
data = @getFormData()
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
define [
|
||||
'compiled/models/CreateUserList'
|
||||
'underscore'
|
||||
'i18n!create_users_view'
|
||||
'compiled/views/DialogFormView'
|
||||
'jst/courses/roster/createUsers'
|
||||
'jst/courses/roster/createUsersWrapper'
|
||||
'vendor/jquery.placeholder'
|
||||
], (CreateUserList, _, I18n, DialogFormView, template, wrapper) ->
|
||||
|
||||
class CreateUsersView extends DialogFormView
|
||||
|
||||
defaults:
|
||||
width: 700
|
||||
height: 500
|
||||
|
||||
els:
|
||||
'#privileges': '$privileges'
|
||||
'#user_list_textarea': '$textarea'
|
||||
|
||||
events: _.extend({}, @::events,
|
||||
'click .createUsersStartOver': 'startOver'
|
||||
'click .createUsersStartOverFrd': 'startOverFrd'
|
||||
'change #enrollment_type': 'changeEnrollment'
|
||||
'click #enrollment_type': 'changeEnrollment'
|
||||
'click .dialog_closer': 'close'
|
||||
)
|
||||
|
||||
template: template
|
||||
|
||||
wrapperTemplate: wrapper
|
||||
|
||||
initialize: ->
|
||||
@model ?= new CreateUserList
|
||||
super
|
||||
|
||||
attach: ->
|
||||
@model.on 'change:step', @render, this
|
||||
@model.on 'change:enrollment_type', @maybeShowPrivileges
|
||||
|
||||
maybeShowPrivileges: =>
|
||||
if @model.get('enrollment_type') in ['TeacherEnrollment', 'TaEnrollment']
|
||||
@$privileges.show()
|
||||
else
|
||||
@$privileges.hide()
|
||||
|
||||
changeEnrollment: (event) ->
|
||||
@model.set 'enrollment_type', event.target.value
|
||||
|
||||
openAgain: ->
|
||||
@startOverFrd()
|
||||
super
|
||||
|
||||
hasUsers: ->
|
||||
@model.get('users')?.length
|
||||
|
||||
onSaveSuccess: ->
|
||||
@model.incrementStep()
|
||||
|
||||
validateBeforeSave: (data) ->
|
||||
if @model.get('step') is 1 and !data.user_list
|
||||
user_list: [{
|
||||
type: 'required'
|
||||
message: I18n.t('required', 'Please enter some email addresses')
|
||||
}]
|
||||
else
|
||||
{}
|
||||
|
||||
startOver: ->
|
||||
@model.startOver()
|
||||
|
||||
startOverFrd: ->
|
||||
@model.startOver()
|
||||
@$textarea?.val ''
|
||||
|
||||
afterRender: ->
|
||||
@$('[placeholder]').placeholder()
|
||||
@maybeShowPrivileges()
|
||||
|
|
@ -15,12 +15,29 @@ define [
|
|||
|
||||
@child 'roleSelectView', '[data-view=roleSelect]'
|
||||
|
||||
@child 'createUsersView', '[data-view=createUsers]'
|
||||
|
||||
@optionProperty 'roles'
|
||||
|
||||
@optionProperty 'permissions'
|
||||
|
||||
template: template
|
||||
|
||||
els:
|
||||
'#addUsers': '$addUsersButton'
|
||||
|
||||
afterRender: ->
|
||||
# its a child view so it gets rendered automatically, need to stop it
|
||||
@createUsersView.hide()
|
||||
# its trigger would not be rendered yet, set it manually
|
||||
@createUsersView.setTrigger @$addUsersButton
|
||||
|
||||
attach: ->
|
||||
@collection.on 'setParam deleteParam', @fetch
|
||||
@createUsersView.on 'close', @fetchOnCreateUsersClose
|
||||
|
||||
fetchOnCreateUsersClose: =>
|
||||
@collection.fetch() if @createUsersView.hasUsers()
|
||||
|
||||
fetch: =>
|
||||
@lastRequest?.abort()
|
|
@ -303,10 +303,24 @@ class ContextController < ApplicationController
|
|||
|
||||
if @context.is_a?(Course)
|
||||
sections = @context.course_sections.select([:id, :name])
|
||||
all_roles = Role.custom_roles_and_counts_for_course(@context, @current_user)
|
||||
all_roles = Role.role_data(@context, @current_user)
|
||||
js_env({
|
||||
:ALL_ROLES => all_roles,
|
||||
:SECTIONS => sections.map { |s| { :id => s.id, :name => s.name } }
|
||||
:SECTIONS => sections.map { |s| { :id => s.id, :name => s.name } },
|
||||
:USER_LISTS_URL => polymorphic_path([@context, :user_lists], :format => :json),
|
||||
:ENROLL_USERS_URL => course_enroll_users_url(@context),
|
||||
:permissions => {
|
||||
:manage_students => (manage_students = @context.grants_right?(@current_user, session, :manage_students)),
|
||||
:manage_admin_users => (manage_admins = @context.grants_right?(@current_user, session, :manage_admin_users)),
|
||||
:add_users => manage_students || manage_admins
|
||||
},
|
||||
:course => {
|
||||
:completed => (completed = @context.completed?),
|
||||
:soft_concluded => (soft_concluded = @context.soft_concluded?),
|
||||
:concluded => completed || soft_concluded,
|
||||
:teacherless => @context.teacherless?,
|
||||
:available => @context.available?
|
||||
}
|
||||
})
|
||||
elsif @context.is_a?(Group)
|
||||
@users = @context.participating_users.order_by_sortable_name.uniq
|
||||
|
|
|
@ -126,6 +126,34 @@ class Role < ActiveRecord::Base
|
|||
@enrollment_types
|
||||
end
|
||||
|
||||
def self.manageable_roles_by_user(user, course)
|
||||
manageable = ['ObserverEnrollment', 'DesignerEnrollment']
|
||||
if course.grants_right?(user, :manage_students)
|
||||
manageable << 'StudentEnrollment'
|
||||
end
|
||||
if course.grants_right?(user, :manage_admin_users)
|
||||
manageable << 'TeacherEnrollment'
|
||||
manageable << 'TaEnrollment'
|
||||
elsif course.teacherless?
|
||||
manageable << 'TeacherEnrollment'
|
||||
end
|
||||
manageable.sort
|
||||
end
|
||||
|
||||
def self.role_data(course, user, include_inactive=false)
|
||||
manageable = Role.manageable_roles_by_user(user, course)
|
||||
self.custom_roles_and_counts_for_course(course, user, include_inactive).inject([]) { |roles, role|
|
||||
is_manageable = manageable.include?(role[:base_role_name])
|
||||
role[:manageable_by_user] = is_manageable
|
||||
roles << role
|
||||
role[:custom_roles].each do |custom_role|
|
||||
custom_role[:manageable_by_user] = is_manageable
|
||||
roles << custom_role
|
||||
end
|
||||
roles
|
||||
}
|
||||
end
|
||||
|
||||
def self.built_in_role_names
|
||||
@built_in_role_names ||= %w(AccountAdmin) + Enrollment.valid_types
|
||||
end
|
||||
|
|
|
@ -14,3 +14,4 @@
|
|||
@import "jquery.ui.theme";
|
||||
|
||||
@import "jquery.ui.menu";
|
||||
@import "overrides";
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
@import "environment";
|
||||
|
||||
.ui-widget {
|
||||
font-size: $baseFontSize;
|
||||
}
|
||||
|
|
@ -63,33 +63,59 @@ We want to deprecate this in favor of `form-horizontal`.
|
|||
}
|
||||
}
|
||||
|
||||
/* @styleguide Forms: Dialog Buttons
|
||||
/* @styleguide Forms: Dialog Form
|
||||
|
||||
Elements with the `.form-controls` class in dialogs will be displayed properly,
|
||||
no need to use `fixDialogButtons` on them.
|
||||
Add the class `form-dialog` to get the `form-controls` to display properly in a
|
||||
dialog form and proper overflow scrolling of content. No need to use
|
||||
`$.fn.fixDialogButtons`.
|
||||
|
||||
**Note**: You must wrap your content in `.form-dialog-content` and use the
|
||||
height option for jQuery UI dialog. To get the scrolling and fixed form
|
||||
controls on the bottom required this.
|
||||
|
||||
```html
|
||||
<button id="show-dialog-buttons-dialog" class="btn">Show Dialog</button>
|
||||
<div id="dialog-buttons-dialog">
|
||||
<form class="form-inline">
|
||||
<p>Aren't the form controls beautiful?</p>
|
||||
<div class="form-controls">
|
||||
<button class="btn btn-primary" type="button">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<form id="dialog-buttons-dialog" class="form-dialog">
|
||||
<div class="form-dialog-content">
|
||||
<p style="height: 1000px;">Aren't the form controls beautiful?<br> Scroll down ↓</p>
|
||||
<p>Hooray for scrolling</p>
|
||||
</div>
|
||||
<div class="form-controls">
|
||||
<button class="btn btn-primary" type="button">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
```
|
||||
|
||||
*/
|
||||
|
||||
.ui-dialog .form-controls {
|
||||
padding: 10px;
|
||||
margin: 0 -1em !important;
|
||||
background-color: #EFEFEF;
|
||||
border-top: 1px solid #DDD;
|
||||
box-shadow: inset 0 1px 0 white;
|
||||
text-align: right;
|
||||
position: relative;
|
||||
bottom: -26px;
|
||||
.form-dialog {
|
||||
padding-bottom: 70px !important;
|
||||
margin-bottom: 0;
|
||||
|
||||
.form-controls {
|
||||
padding: 10px;
|
||||
margin: 0;
|
||||
background-color: #EFEFEF;
|
||||
border-top: 1px solid #DDD;
|
||||
box-shadow: inset 0 1px 0 white;
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
.form-dialog-content {
|
||||
// jQuery UI handles overflow on its own, but our buttons are inside the
|
||||
// default scroll area, this gives us our own scrollable content area
|
||||
// while still allowing us to use the height option in $.fn.dialog
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 51px;
|
||||
overflow: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<% content_for :right_side, render(:partial => 'context/roster_right_side') %>
|
||||
|
||||
<% if @context.is_a?(Course) %>
|
||||
<% jammit_css :roster %>
|
||||
<% js_bundle :roster %>
|
||||
<% else %>
|
||||
<% content_for :stylesheets do %>
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
{{#ifEqual step 1}}
|
||||
<div class="form-dialog-content" id="create-users-step-1">
|
||||
<p>
|
||||
{{#t "form_instructions"}}
|
||||
Type or paste a list of email addresses below:
|
||||
{{/t}}<br>
|
||||
</p>
|
||||
<div class="row-fluid content-box">
|
||||
<textarea id="user_list_textarea" name="user_list" class="span12" rows=7 placeholder='"Example Student" <student@example.com>, "Lastname, Firstname" <firstlast@example.com>, justAnEmailAddress@example.com'>{{user_list}}</textarea>
|
||||
</div>
|
||||
<div class="form-horizontal">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="enrollment_type">{{#t "user_role"}}Role:{{/t}}</label>
|
||||
<div class="controls">
|
||||
<select name="enrollment_type" id="enrollment_type">
|
||||
{{#each roles}}
|
||||
{{#if manageable_by_user}}
|
||||
<option value="{{name}}" {{#ifEqual name ../../enrollment_type}}selected{{/ifEqual}}>{{label}}</option>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="course_section_id">{{#t "section"}}Section{{/t}}</label>
|
||||
<div class="controls">
|
||||
<select name="course_section_id" id="course_section_id">
|
||||
{{#each sections}}
|
||||
<option value="{{id}}" {{#ifEqual id ../course_section_id}}selected{{/ifEqual}}>{{name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group" id="privileges">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" id="limit_privileges_to_course_section" name="limit_privileges_to_course_section" value="1" {{#if limit_privileges_to_course_section}}checked{{/if}}>
|
||||
{{#t "can_only_grade_students_in_section"}}Can grade students in their section only{{/t}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-controls">
|
||||
<button
|
||||
id="next-step"
|
||||
class="btn btn-primary"
|
||||
data-text-while-loading='{{#t "validating"}}Validating...{{/t}}'
|
||||
type="submit"
|
||||
>{{#t "next"}}Next{{/t}}</button>
|
||||
</div>
|
||||
{{/ifEqual}}
|
||||
|
||||
{{#ifEqual step 2}}
|
||||
<div class="form-dialog-content" id="create-users-step-2">
|
||||
{{#if errored_users.length}}
|
||||
<div class="alert alert-error content-box">
|
||||
<p>
|
||||
{{#t "will_not_be_added"}}These users had errors and will not be added. Please ensure they are formatted correctly.{{/t}}<br>
|
||||
<small>{{#t "example_formats"}}Examples: user@example.com, "First Last" <user@example.com>, "Last, First" <user@example.com>{{/t}}</small>
|
||||
</p>
|
||||
<ul class="createUsersErroredUsers">
|
||||
{{#each errored_users}}
|
||||
<li>{{name}} {{address}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if users.length}}
|
||||
<div class="alert alert-notify content-box">
|
||||
{{#t "adding_n_users"}}Validated and ready to add {{users.length}} users:{{/t}}
|
||||
{{#if duplicates.length}}
|
||||
{{#t "duplicates_removed"}}Some duplicates were removed.{{/t}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<table class="table table-bordered table-striped table-condensed" id="create-users-verified">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{#t "name"}}Name{{/t}}</th>
|
||||
<th>{{#t "email"}}Email{{/t}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each users}}
|
||||
<tr>
|
||||
<td>{{name}}</td>
|
||||
<td>{{address}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="form-controls">
|
||||
<button
|
||||
type="button"
|
||||
class="btn createUsersStartOver {{#unless users.length}}btn-primary{{/unless}}"
|
||||
>{{#t "go_back"}}Start Over{{/t}}</button>
|
||||
{{#if users.length}}
|
||||
<button
|
||||
id="createUsersAddButton"
|
||||
class="btn btn-primary"
|
||||
data-text-while-loading='{{#t "adding"}}Adding...{{/t}}'
|
||||
type="submit"
|
||||
>{{#t "add_these_users"}}Add Users{{/t}}</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/ifEqual}}
|
||||
|
||||
{{#ifEqual step 3}}
|
||||
<div class="form-dialog-content" id="create-users-step-3">
|
||||
<p class="content-box alert alert-success">{{#t "have_been_enrolled"}}The following users have been enrolled{{/t}}</p>
|
||||
<table class="table table-bordered table-striped table-condensed" id="create-users-results">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{#t "name"}}Name{{/t}}</th>
|
||||
<th>{{#t "email"}}Email{{/t}}</th>
|
||||
<th>{{#t "section"}}Section{{/t}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each enrolledUsers}}
|
||||
<tr>
|
||||
<td>{{enrollment.name}}</td>
|
||||
<td>{{enrollment.email}}</td>
|
||||
<td>{{enrollment.section}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="form-controls">
|
||||
<button
|
||||
class="btn show-if-step-3 createUsersStartOverFrd"
|
||||
>{{#t "add_more_users"}}Add More Users{{/t}}</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary show-if-step-3 dialog_closer"
|
||||
>{{#t "close"}}Done{{/t}}</button>
|
||||
</div>
|
||||
{{/ifEqual}}
|
|
@ -0,0 +1,2 @@
|
|||
<div class="outlet"></div>
|
||||
|
|
@ -14,10 +14,24 @@
|
|||
>
|
||||
<option value="">{{#t "all_roles"}}All Roles{{/t}}</option>
|
||||
{{#each roles}}
|
||||
<option value="{{name}}">{{plural_label}}</option>
|
||||
<option value="{{name}}">{{label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
|
||||
{{#if permissions.add_users}}
|
||||
{{#if course.concluded}}
|
||||
<a class="btn" title='{{#t "cannot_add_users"}}New users can not be added because this course is concluded{{/t}}' disabled data-tooltip>
|
||||
{{else}}
|
||||
<a
|
||||
class="btn btn-primary pull-right icon-add"
|
||||
id="addUsers"
|
||||
title='{{#t "add_people"}}Add People{{/t}}'
|
||||
>{{#t "add_people"}}Add People{{/t}}</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<form data-view="createUsers" class="form-dialog"></form>
|
||||
|
||||
<div data-view="users" class="v-gutter"></div>
|
||||
|
||||
|
|
|
@ -102,9 +102,6 @@ stylesheets:
|
|||
- public/stylesheets/compiled/grading_standards.css
|
||||
login:
|
||||
- public/stylesheets/compiled/login.css
|
||||
roster:
|
||||
- public/stylesheets/compiled/course_settings.css
|
||||
- public/stylesheets/compiled/roster.css
|
||||
roster_user:
|
||||
- public/stylesheets/compiled/roster_user.css
|
||||
learning_outcomes:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
define ['jquery'], ($) ->
|
||||
|
||||
$.fn.toString = ->
|
||||
return '' unless this.length
|
||||
id = this.attr 'id'
|
||||
className = this.attr('class').replace(/\s/g, '.')
|
||||
tag = this[0].tagName.toLowerCase()
|
||||
|
@ -9,12 +10,15 @@ define ['jquery'], ($) ->
|
|||
str += ".#{className}" if className
|
||||
"<#{str}>"
|
||||
|
||||
isVisible: ($el, message) ->
|
||||
isVisible: ($el, message = '') ->
|
||||
ok $el.length, "elements found"
|
||||
ok $el.is(':visible'), "#{$el} is visible " + message
|
||||
|
||||
isHidden: ($el, message) ->
|
||||
ok $el.length, "elements found"
|
||||
ok !$el.is(':visible'), "#{$el} is hidden " + message
|
||||
|
||||
hasClass: ($el, className, message) ->
|
||||
ok $el.length, "elements found"
|
||||
ok $el.hasClass(className), "#{$el} has class #{className} " + message
|
||||
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
define [
|
||||
'compiled/views/courses/roster/CreateUsersView'
|
||||
'compiled/models/CreateUserList'
|
||||
'helpers/assertions'
|
||||
], (CreateUsersView, CreateUserList, assert) ->
|
||||
|
||||
view = null
|
||||
server = null
|
||||
|
||||
module 'CreateUsersView',
|
||||
setup: ->
|
||||
server = sinon.fakeServer.create()
|
||||
server.respondWith("POST", "/read",
|
||||
[200, { "Content-Type": "application/json" }, JSON.stringify({
|
||||
users: [{address: 'joe@joe.com', name: null, type: 'email'}],
|
||||
errored_users: [],
|
||||
duplicates: []
|
||||
})])
|
||||
server.respondWith("POST", "/update",
|
||||
[200, { "Content-Type": "application/json" }, JSON.stringify([
|
||||
enrollment: {
|
||||
name: 'joe@joe.com'
|
||||
email: 'joe@joe.com'
|
||||
section: 'MWF'
|
||||
}
|
||||
])])
|
||||
view = new CreateUsersView
|
||||
trigger: false
|
||||
title: 'test'
|
||||
model: new CreateUserList
|
||||
sections: [
|
||||
{id: 1, name: 'MWF'}
|
||||
{id: 2, name: 'TTh'}
|
||||
]
|
||||
roles: [
|
||||
{label: 'Teacher', name: 'TeacherEnrollment', manageable_by_user: true}
|
||||
{label: 'Student', name: 'StudentEnrollment', manageable_by_user: true}
|
||||
{label: 'Fake', name: 'Fake', manageable_by_user: false}
|
||||
]
|
||||
readURL: '/read'
|
||||
updateURL: '/update'
|
||||
$('#fixtures').append view.$el
|
||||
view.open()
|
||||
|
||||
teardown: ->
|
||||
server.restore()
|
||||
view.remove()
|
||||
|
||||
addUserText = ->
|
||||
view.$textarea.val "joe@joe.com"
|
||||
|
||||
goToStep2 = ->
|
||||
$('#next-step').click()
|
||||
server.respond()
|
||||
|
||||
goToStep3 = ->
|
||||
$('#createUsersAddButton').click()
|
||||
server.respond()
|
||||
|
||||
assertVerifiedUsers = ->
|
||||
ok $('#create-users-verified').html().match('joe@joe.com'), 'verified users matched'
|
||||
|
||||
assertEnrolledUsers = ->
|
||||
ok $('#create-users-results').html().match('joe@joe.com'), 'enrolled users matched'
|
||||
|
||||
assertStepVisible = (step) ->
|
||||
assert.isVisible $("#create-users-step-#{step}")
|
||||
|
||||
startOver = ->
|
||||
view.$('.createUsersStartOver').click()
|
||||
|
||||
startOverFrd = ->
|
||||
view.$('.createUsersStartOverFrd').click()
|
||||
|
||||
assertTextareaValue = (text) ->
|
||||
equal view.$textarea.val(), text, 'textarea matches text'
|
||||
|
||||
test 'moves through the steps', ->
|
||||
assertStepVisible 1
|
||||
addUserText()
|
||||
goToStep2()
|
||||
assertStepVisible 2
|
||||
assertVerifiedUsers()
|
||||
goToStep3()
|
||||
assertStepVisible 3
|
||||
assertEnrolledUsers()
|
||||
view.close()
|
||||
|
||||
test 'starts over on step 2', ->
|
||||
addUserText()
|
||||
goToStep2()
|
||||
assertStepVisible 2
|
||||
startOver()
|
||||
assertStepVisible 1
|
||||
assertTextareaValue 'joe@joe.com'
|
||||
view.close()
|
||||
|
||||
test 'starts over on step 3', ->
|
||||
addUserText()
|
||||
goToStep2()
|
||||
goToStep3()
|
||||
assertStepVisible 3
|
||||
startOverFrd()
|
||||
assertStepVisible 1
|
||||
assertTextareaValue ''
|
||||
|
||||
test 'resets data on close and reopen', ->
|
||||
addUserText()
|
||||
assertTextareaValue 'joe@joe.com'
|
||||
view.close()
|
||||
view.open()
|
||||
assertTextareaValue ''
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
<meta http-equiv=Content-type content="text/html; charset=utf-8">
|
||||
<title>Tests</title>
|
||||
<link rel="stylesheet" href="support/qunit/qunit.css" type="text/css">
|
||||
<link rel="stylesheet" href="../../public/stylesheets/compiled/g_base.css" type="text/css">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Helvetica', 'Verdana';
|
||||
|
|
|
@ -246,6 +246,20 @@ describe Role do
|
|||
end
|
||||
end
|
||||
|
||||
describe "Role.role_data" do
|
||||
it "returns the roles with custom roles flattened as siblings to the main roles" do
|
||||
course(:account => @sub_account)
|
||||
|
||||
@base_types.each do |bt|
|
||||
@course.enroll_user(user, bt)
|
||||
@course.enroll_user(user, bt, :role_name => "custom #{bt}")
|
||||
end
|
||||
|
||||
roles = Role.role_data(@course, @course.teachers.first)
|
||||
roles.length.should == 10
|
||||
end
|
||||
end
|
||||
|
||||
it "should include inactive roles" do
|
||||
@account.roles.each{|r| r.deactivate! }
|
||||
all = Role.all_enrollment_roles_for_account(@sub_account, true)
|
||||
|
|
|
@ -277,6 +277,7 @@ describe "announcements" do
|
|||
create_announcement_manual('input[type=checkbox][name=delay_posting]')
|
||||
f('.ui-datepicker-trigger').click
|
||||
datepicker_next
|
||||
f('.ui-datepicker-time .ui-datepicker-ok').click
|
||||
expect_new_page_load { submit_form('.form-actions') }
|
||||
f('.discussion-fyi').should include_text('This topic will not be visible')
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue