Skip to content

Commit 9ebb185

Browse files
landonwilkinsLandon Wilkins
authored andcommitted
add randomly assign unassigned users functionality to new group ui
fixes CNVS-6732 normal test plan: 0) change the "true" on the first line of app/coffeescripts/bundles/manage_groups.coffee to "false" to enable the test bed (feel free to change the GroupCategory ID as well) 1) go to the new group ui test bed (http://localhost:3000/courses/1/groups) 2) ensure that the GroupCategory you pick is not student organized, nor self signup restricted 3) click the cog 4) click "Randomly Assign Students" 5) click "Okay" 6) verify that everything in the #content area is replaced with a progress bar 7) wait for the progress bar to reach 100% 8) verify that the #content area changes back to show the groups, with the previously unassigned students distributed among the available groups api test plan: 1) ensure delayed jobs is not running 2) navigate to the new group ui test bed 3) perform a random assignment, which should result in being stuck in progress 4) open up Postman in another tab 5) perform a GET request to http://localhost:3000/api/v1/group_categories/1 (replace the 1 with your test GroupCategory's ID) 6) verify that the response includes a progress 7) verify that if you refresh the tab you did the random assignment in, you still see a progress bar 8) start delayed jobs and verify that the progress bar completes 9) verify the api documentation for a GroupCategory now includes a progress description (look in the box under "A Group Category object looks like:") Change-Id: Ia8b24d899f428ad8ed50a9790a03802ca60d746d Reviewed-on: https://gerrit.instructure.com/22288 Reviewed-by: Mark Ericksen <marke@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> Product-Review: Marc LeGendre <marc@instructure.com> QA-Review: Marc LeGendre <marc@instructure.com>
1 parent 894ff18 commit 9ebb185

15 files changed

Lines changed: 413 additions & 28 deletions

File tree

app/coffeescripts/models/GroupCategory.coffee

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
define [
2+
'underscore'
23
'Backbone'
34
'compiled/collections/GroupCollection'
45
'compiled/collections/GroupUserCollection'
5-
], ({Model}, GroupCollection, GroupUserCollection) ->
6+
'compiled/models/progressable'
7+
], (_, {Model}, GroupCollection, GroupUserCollection, progressable) ->
68

79
class GroupCategory extends Model
10+
11+
urlRoot: '/api/v1/group_categories'
12+
13+
@mixin progressable
14+
815
groups: ->
916
@_groups = new GroupCollection(null)
1017
@_groups.url = "/api/v1/group_categories/#{@id}/groups?per_page=50"
@@ -21,3 +28,14 @@ define [
2128
@_unassignedUsers.url = "/api/v1/group_categories/#{@id}/users?unassigned=true&per_page=50"
2229
@unassignedUsers = -> @_unassignedUsers
2330
@_unassignedUsers
31+
32+
assignUnassignedMembers: ->
33+
$.ajaxJSON "/api/v1/group_categories/#{@id}/assign_unassigned_members", 'POST', {}, @setUpProgress
34+
35+
setUpProgress: (response) =>
36+
@set progress_url: response.url
37+
38+
present: =>
39+
data = _.extend {}, @attributes
40+
data.progress = @progressModel.toJSON()
41+
data

app/coffeescripts/models/Progress.coffee

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ define ['Backbone', 'jquery'], ({Model}, $) ->
1313

1414
defaults:
1515

16+
completion: 0
17+
1618
# The url to poll
1719
url: null
1820

app/coffeescripts/views/PaginatedCollectionView.coffee

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ define [
107107
# @api public
108108

109109
checkScroll: =>
110-
return if @collection.fetchingPage or @collection.fetchingNextPage
110+
return if @collection.fetchingPage or @collection.fetchingNextPage or not @$el.length
111111
elementBottom = @$el.position().top +
112112
@$el.height() -
113113
@heightContainer.position().top
Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
11
define [
22
'i18n!groups'
33
'Backbone'
4+
'compiled/views/groups/manage/RandomlyAssignMembersView'
45
'jst/groups/manage/groupCategoryDetail'
5-
], (I18n, {View}, template) ->
6+
], (I18n, {View}, RandomlyAssignMembersView, template) ->
67

78
class GroupCategoryDetailView extends View
89

910
template: template
1011

12+
els:
13+
'.randomly-assign-members': '$randomlyAssignMembersLink'
14+
15+
initialize: (options) ->
16+
super
17+
@randomlyAssignUsersView = new RandomlyAssignMembersView
18+
model: options.model
19+
1120
attach: ->
1221
@collection.on 'add remove reset', @render
22+
@collection.on 'remove', => @model.unassignedUsers().fetch()
23+
24+
afterRender: ->
25+
# its trigger will not be rendered yet, set it manually
26+
@randomlyAssignUsersView.setTrigger @$randomlyAssignMembersLink
1327

1428
toJSON: ->
1529
json = super
1630
json.groupCountText = I18n.t "group_count", {one: "1 group", other: "%{count} groups"}, count: @model.groupsCount()
31+
json.studentOrganizedOrSelfSignupRestricted = @model.get('role') is "student_organized" or @model.get('self_signup') is "restricted"
1732
json

app/coffeescripts/views/groups/manage/GroupCategoryView.coffee

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ define [
1818
template: template
1919

2020
@optionProperty 'groupCount'
21+
@optionProperty 'randomlyAssignStudentsInProgress'
2122

2223
@child 'groupCategoryDetailView', '[data-view=groupCategoryDetail]'
2324
@child 'unassignedUsersView', '[data-view=unassignedUsers]'
@@ -35,6 +36,9 @@ define [
3536
collection: @groups
3637
options.groupsView ?= @groupsView(options)
3738
options.unassignedUsersView ?= @unassignedUsersView(options)
39+
if progress = @model.get('progress')
40+
@model.progressModel.set progress
41+
@randomlyAssignStudentsInProgress = true
3842
super
3943

4044
groupsView: (options) ->
@@ -58,6 +62,15 @@ define [
5862

5963
attach: ->
6064
@model.on 'destroy', @remove, this
65+
@model.progressModel.on 'change:url', =>
66+
@model.progressModel.set({'completion': 0})
67+
@randomlyAssignStudentsInProgress = true
68+
@model.progressModel.on 'change', @render
69+
@model.on 'progressResolved', =>
70+
@model.groups().fetch()
71+
@model.unassignedUsers().fetch()
72+
@randomlyAssignStudentsInProgress = false
73+
@render()
6174

6275
deleteCategory: (e) =>
6376
e.preventDefault()
@@ -74,3 +87,9 @@ define [
7487
@groups.add(new_group)
7588
@createView.model = new_group
7689
@createView.toggle()
90+
91+
toJSON: ->
92+
json = @model.present()
93+
json.randomlyAssignStudentsInProgress = @randomlyAssignStudentsInProgress
94+
json
95+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
define [
2+
'i18n!groups'
3+
'compiled/views/DialogFormView'
4+
'jst/groups/manage/randomlyAssignMembers'
5+
'jst/EmptyDialogFormWrapper'
6+
], (I18n, DialogFormView, template, wrapper) ->
7+
8+
class RandomlyAssignMembersView extends DialogFormView
9+
10+
defaults:
11+
title: I18n.t "randomly_assigning_members", "Randomly Assigning Students"
12+
width: 450
13+
height: 200
14+
15+
template: template
16+
17+
wrapperTemplate: wrapper
18+
19+
className: 'form-dialog'
20+
21+
events:
22+
'click .dialog_closer': 'close'
23+
'click .randomly-assign-members-confirm': 'randomlyAssignMembers'
24+
25+
randomlyAssignMembers: (e) ->
26+
e.preventDefault()
27+
e.stopPropagation()
28+
@model.assignUnassignedMembers()
29+
@close()

app/controllers/group_categories_controller.rb

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,24 @@
5454
# // in each group. If null, there is no limit.
5555
# group_limit: null
5656
#
57+
# // If the group category has not yet finished a randomly student assignment request,
58+
# // a progress object will be attached, which will contain information related to the
59+
# // progress of the assignment request.
60+
# // Refer to the Progress API for more information
61+
# "progress": {
62+
# "completion": 0,
63+
# "context_id": 25,
64+
# "context_type": "GroupCategory",
65+
# "created_at": "2013-07-25T14:16:04-06:00",
66+
# "id": 217,
67+
# "message": null,
68+
# "tag": "assign_unassigned_members",
69+
# "updated_at": "2013-07-25T14:16:04-06:00",
70+
# "user_id": null,
71+
# "workflow_state": "running",
72+
# "url": "http://localhost:3000/api/v1/progress/217"
73+
# }
74+
#
5775
# }
5876
#
5977
class GroupCategoriesController < ApplicationController
@@ -86,7 +104,7 @@ def index
86104
if authorized_action(@context, @current_user, :manage_groups)
87105
path = send("api_v1_#{@context.class.to_s.downcase}_group_categories_url")
88106
paginated_categories = Api.paginate(@categories, self, path)
89-
render :json => paginated_categories.map { |c| group_category_json(c, @current_user, session) }
107+
render :json => paginated_categories.map { |c| group_category_json(c, @current_user, session, :include => ['progress_url']) }
90108
end
91109
end
92110
end
@@ -106,7 +124,7 @@ def show
106124
respond_to do |format|
107125
format.json do
108126
if authorized_action(@group_category.context, @current_user, :manage_groups)
109-
render :json => group_category_json(@group_category, @current_user, session)
127+
render :json => group_category_json(@group_category, @current_user, session, :include => ['progress_url'])
110128
end
111129
end
112130
end
@@ -181,7 +199,7 @@ def update
181199
if api_request?
182200
process_group_category_api_params
183201
if populate_group_category_from_params
184-
render :json => group_category_json(@group_category, @current_user, session)
202+
render :json => group_category_json(@group_category, @current_user, session, :include => ['progress_url'])
185203
end
186204
else
187205
return render(:json => {'status' => 'not found'}, :status => :not_found) unless @group_category
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.progress-title
2+
text-align: center
3+
font-weight: bold
4+
5+
.progressbar
6+
margin-left: auto
7+
margin-right: auto
8+
width: 60%
Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,34 @@
11
<div data-view="groupCategoryDetail"></div>
22

3-
{{#if ENV.IS_LARGE_ROSTER}}
4-
<div data-view="groups"></div>
5-
{{else}}
6-
<div class="row-fluid">
7-
<div class="well span4">
8-
<h3 class="h5">
9-
<strong>
10-
{{#ifEqual ENV.group_user_type "student"}}
11-
{{#t "unassigned_students"}}Unassigned Students{{/t}}
12-
{{else}}
13-
{{#t "unassigned_users"}}Unassigned Users{{/t}}
14-
{{/ifEqual}}
15-
</strong>
16-
</h3>
17-
<div data-view="unassignedUsers"></div>
3+
{{#if randomlyAssignStudentsInProgress}}
4+
<div class="progress-container">
5+
<h5 class="progress-title">{{#t "randomly_assigning_students"}}Randomly Assigning Students{{/t}}</h5>
6+
<div class="progressbar ui-progressbar ui-widget ui-widget-content ui-corner-all" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="{{progress.completion}}">
7+
<div class="ui-progressbar-value ui-widget-header ui-corner-left" style="width: {{progress.completion}}%;"></div>
188
</div>
19-
<div class="span8" data-view="groups"></div>
209
</div>
10+
{{else}}
11+
12+
{{#if ENV.IS_LARGE_ROSTER}}
13+
<div data-view="groups"></div>
14+
{{else}}
15+
16+
<div class="row-fluid">
17+
<div class="well span4">
18+
<h3 class="h5">
19+
<strong>
20+
{{#ifEqual ENV.group_user_type "student"}}
21+
{{#t "unassigned_students"}}Unassigned Students{{/t}}
22+
{{else}}
23+
{{#t "unassigned_users"}}Unassigned Users{{/t}}
24+
{{/ifEqual}}
25+
</strong>
26+
</h3>
27+
<div data-view="unassignedUsers"></div>
28+
</div>
29+
<div class="span8" data-view="groups"></div>
30+
</div>
31+
{{/if}}
2132
{{/if}}
2233

34+

app/views/jst/groups/manage/groupCategoryDetail.handlebars

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,17 @@
33
<span>
44
<a class="al-trigger btn">
55
<i class="icon-settings"></i><i class="icon-mini-arrow-down"></i>
6-
<span class="screenreader-only">Settings</span>
6+
<span class="screenreader-only">{{#t "category_settings"}}Settings{{/t}}</span>
77
</a>
88
<ul class="al-options">
9-
<li><a href="#" class="icon-edit edit-category">Edit</a></li>
10-
<li><a href="#" class="icon-trash delete-category">Delete</a></li>
9+
{{#unless studentOrganizedOrSelfSignupRestricted}}
10+
<li><a href="#"
11+
class="icon-user randomly-assign-members">{{#t "randomly_assign_students_option"}}Randomly Assign Students{{/t}}</a></li>
12+
{{/unless}}
13+
<li><a href="#"
14+
class="icon-edit edit-category">{{#t "edit_category_option"}}Edit{{/t}}</a></li>
15+
<li><a href="#"
16+
class="icon-trash delete-category">{{#t "delete_category_option"}}Delete{{/t}}</a></li>
1117
</ul>
1218
</span>
1319
</div>
@@ -39,5 +45,4 @@
3945

4046
{{#if studentOrganized}}
4147
<div class="alert"><i class="icon-warning-sign"></i> {{#t "self_organized_warning"}}These groups are self-organized by students. Unlike other types of groups, students can belong to more than one of these groups at a time, so these groups may not be the best solution for graded assignments.{{/t}}</div>
42-
{{/if}}
43-
48+
{{/if}}

0 commit comments

Comments
 (0)