Commit b77e65cd by Andy Armstrong

Assign cohorts to groups in the instructor dashboard

TNL-653
parent 674bfc4f
......@@ -28,9 +28,6 @@ LMS: Student Notes: Toggle single note visibility. TNL-660
LMS: Student Notes: Add Notes page. TNL-797
LMS: Student Notes: Add possibility to add/edit/remove notes. TNL-655
=======
LMS: Extend preview to support cohorted courseware. TNL-651
>>>>>>> Extend preview to support cohorted courseware
Platform: Add group_access field to all xblocks. TNL-670
......
......@@ -28,7 +28,6 @@ class CourseMetadata(object):
'graded',
'hide_from_toc',
'pdf_textbooks',
'user_partitions',
'name', # from xblock
'tags', # from xblock
'visible_to_staff_only',
......
......@@ -153,7 +153,7 @@ class MembershipPageCohortManagementSection(PageObject):
Adds a new manual cohort with the specified name.
"""
self.q(css=self._bounded_selector("div.cohort-management-nav .action-create")).first.click()
textinput = self.q(css=self._bounded_selector("#cohort-create-name")).results[0]
textinput = self.q(css=self._bounded_selector("#cohort-name")).results[0]
textinput.send_keys(cohort_name)
self.q(css=self._bounded_selector("div.form-actions .action-save")).first.click()
......
......@@ -3,6 +3,7 @@ Helper functions and classes for discussion tests.
"""
from uuid import uuid4
import json
from ...fixtures.discussion import (
SingleThreadViewFixture,
......@@ -68,11 +69,11 @@ class CohortTestMixin(object):
"""
Adds a cohort group by name, returning the ID for the group.
"""
url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/cohorts/add'
data = {"name": cohort_name}
url = LMS_BASE_URL + "/courses/" + course_fixture._course_key + '/cohorts/'
data = json.dumps({"name": cohort_name})
response = course_fixture.session.post(url, data=data, headers=course_fixture.headers)
self.assertTrue(response.ok, "Failed to create cohort")
return response.json()['cohort']['id']
return response.json()['id']
def add_user_to_cohort(self, course_fixture, username, cohort_id):
"""
......
var edx = edx || {};
(function(Backbone) {
'use strict';
edx.groups = edx.groups || {};
edx.groups.ContentGroupModel = Backbone.Model.extend({
idAttribute: 'id',
defaults: {
name: ''
}
});
}).call(this, Backbone);
var edx = edx || {};
(function(Backbone, _, $, gettext, ngettext, interpolate_text, NotificationModel, NotificationView) {
(function(Backbone, _, $, gettext, ngettext, interpolate_text, CohortFormView, NotificationModel, NotificationView) {
'use strict';
edx.groups = edx.groups || {};
edx.groups.CohortEditorView = Backbone.View.extend({
events : {
"submit .cohort-management-group-add-form": "addStudents"
'click .wrapper-tabs .tab': 'selectTab',
'click .tab-content-settings .action-save': 'saveSettings',
'submit .cohort-management-group-add-form': 'addStudents'
},
initialize: function(options) {
this.template = _.template($('#cohort-editor-tpl').text());
this.cohorts = options.cohorts;
this.cohortUserPartitionId = options.cohortUserPartitionId;
this.contentGroups = options.contentGroups;
this.advanced_settings_url = options.advanced_settings_url;
},
......@@ -24,11 +28,35 @@ var edx = edx || {};
render: function() {
this.$el.html(this.template({
cohort: this.model,
cohortUserPartitionId: this.cohortUserPartitionId,
contentGroups: this.contentGroups,
advanced_settings_url: this.advanced_settings_url
}));
this.cohortFormView = new CohortFormView({
model: this.model,
cohortUserPartitionId: this.cohortUserPartitionId,
contentGroups: this.contentGroups
});
this.cohortFormView.render();
this.$('.tab-content-settings').append(this.cohortFormView.$el);
return this;
},
selectTab: function(event) {
var tabElement = $(event.currentTarget),
tabName = tabElement.data('tab');
event.preventDefault();
this.$('.wrapper-tabs .tab').removeClass('is-selected');
tabElement.addClass('is-selected');
this.$('.tab-content').addClass('is-hidden');
this.$('.tab-content-' + tabName).removeClass('is-hidden');
},
saveSettings: function(event) {
event.preventDefault();
this.cohortFormView.saveForm();
},
setCohort: function(cohort) {
this.model = cohort;
this.render();
......@@ -208,4 +236,5 @@ var edx = edx || {};
}
}
});
}).call(this, Backbone, _, $, gettext, ngettext, interpolate_text, NotificationModel, NotificationView);
}).call(this, Backbone, _, $, gettext, ngettext, interpolate_text, edx.groups.CohortFormView,
NotificationModel, NotificationView);
var edx = edx || {};
(function($, _, Backbone, gettext, interpolate_text, CohortModel, NotificationModel, NotificationView) {
'use strict';
edx.groups = edx.groups || {};
edx.groups.CohortFormView = Backbone.View.extend({
events : {
'change .cohort-management-details-association-course input': 'onRadioButtonChange',
'change .input-cohort-group-association': 'onGroupAssociationChange',
'click .tab-content-settings .action-save': 'saveSettings',
'submit .cohort-management-group-add-form': 'addStudents'
},
initialize: function(options) {
this.template = _.template($('#cohort-form-tpl').text());
this.cohortUserPartitionId = options.cohortUserPartitionId;
this.contentGroups = options.contentGroups;
},
showNotification: function(options, beforeElement) {
var model = new NotificationModel(options);
this.removeNotification();
this.notification = new NotificationView({
model: model
});
this.notification.render();
if (!beforeElement) {
beforeElement = this.$('.cohort-management-group');
}
beforeElement.before(this.notification.$el);
},
removeNotification: function() {
if (this.notification) {
this.notification.remove();
}
},
render: function() {
this.$el.html(this.template({
cohort: this.model,
contentGroups: this.contentGroups
}));
return this;
},
onRadioButtonChange: function(event) {
var target = $(event.currentTarget),
groupsEnabled = target.val() === 'yes';
if (!groupsEnabled) {
// If the user has chosen 'no', then clear the selection by setting
// it to the first option ('Choose a content group to associate').
this.$('.input-cohort-group-association').val('None');
}
},
onGroupAssociationChange: function(event) {
// Since the user has chosen a content group, click the 'Yes' button too
this.$('.cohort-management-details-association-course .radio-yes').click();
},
getSelectedGroupId: function() {
var selectValue = this.$('.input-cohort-group-association').val();
if (!this.$('.radio-yes').prop('checked') || selectValue === 'None') {
return null;
}
return parseInt(selectValue);
},
getUpdatedCohortName: function() {
var cohortName = this.$('.cohort-name').val();
return cohortName ? cohortName.trim() : this.model.get('name');
},
saveForm: function() {
var self = this,
cohort = this.model,
saveOperation = $.Deferred(),
cohortName, groupId, showMessage, showAddError;
this.removeNotification();
showMessage = function(message, type) {
self.showNotification(
{type: type || 'confirmation', title: message},
self.$('.form-fields')
);
};
showAddError = function(message, type) {
showMessage(message, 'error');
};
cohortName = this.getUpdatedCohortName();
if (cohortName.length === 0) {
showAddError(gettext('Please enter a name for your new cohort group.'));
saveOperation.reject();
} else {
groupId = this.getSelectedGroupId();
cohort.save(
{name: cohortName, user_partition_id: this.cohortUserPartitionId, group_id: groupId},
{patch: true}
).done(function(result) {
if (!result.error) {
cohort.id = result.id;
showMessage(gettext('Saved cohort group.'));
saveOperation.resolve();
} else {
showAddError(result.error);
saveOperation.reject();
}
}).fail(function(result) {
var errorMessage = null;
try {
var jsonResponse = JSON.parse(result.responseText);
errorMessage = jsonResponse.error;
} catch(e) {
// Ignore the exception and show the default error message instead.
}
if (!errorMessage) {
errorMessage = gettext("We've encountered an error. Please refresh your browser and then try again.");
}
showAddError(errorMessage);
saveOperation.reject();
});
}
return saveOperation.promise();
}
});
}).call(this, $, _, Backbone, gettext, interpolate_text, edx.groups.CohortModel, NotificationModel, NotificationView);
var edx = edx || {};
(function($, _, Backbone, gettext, interpolate_text, CohortEditorView,
(function($, _, Backbone, gettext, interpolate_text, CohortModel, CohortEditorView, CohortFormView,
NotificationModel, NotificationView, FileUploaderView) {
'use strict';
......@@ -13,8 +13,8 @@ var edx = edx || {};
events : {
'change .cohort-select': 'onCohortSelected',
'click .action-create': 'showAddCohortForm',
'click .action-cancel': 'cancelAddCohortForm',
'click .action-save': 'saveAddCohortForm',
'click .cohort-management-add-modal .action-save': 'saveAddCohortForm',
'click .cohort-management-add-modal .action-cancel': 'cancelAddCohortForm',
'click .link-cross-reference': 'showSection',
'click .toggle-cohort-management-secondary': 'showCsvUpload'
},
......@@ -24,9 +24,10 @@ var edx = edx || {};
this.template = _.template($('#cohorts-tpl').text());
this.selectorTemplate = _.template($('#cohort-selector-tpl').text());
this.addCohortFormTemplate = _.template($('#add-cohort-form-tpl').text());
this.advanced_settings_url = options.advanced_settings_url;
this.upload_cohorts_csv_url = options.upload_cohorts_csv_url;
this.cohortUserPartitionId = options.cohortUserPartitionId;
this.contentGroups = options.contentGroups;
model.on('sync', this.onSync, this);
// Update cohort counts when the user clicks back on the membership tab
......@@ -52,13 +53,17 @@ var edx = edx || {};
}));
},
onSync: function() {
onSync: function(model, response, options) {
var selectedCohort = this.lastSelectedCohortId && this.model.get(this.lastSelectedCohortId),
hasCohorts = this.model.length > 0,
cohortNavElement = this.$('.cohort-management-nav'),
additionalCohortControlElement = this.$('.wrapper-cohort-supplemental');
additionalCohortControlElement = this.$('.wrapper-cohort-supplemental'),
isModelUpdate = options && options.patch && response.hasOwnProperty('user_partition_id');
this.hideAddCohortForm();
if (hasCohorts) {
if (isModelUpdate) {
// Refresh the selector in case the model's name changed
this.renderSelector(selectedCohort);
} else if (hasCohorts) {
cohortNavElement.removeClass(hiddenClass);
additionalCohortControlElement.removeClass(hiddenClass);
this.renderSelector(selectedCohort);
......@@ -99,6 +104,8 @@ var edx = edx || {};
el: this.$('.cohort-management-group'),
model: cohort,
cohorts: this.model,
cohortUserPartitionId: this.cohortUserPartitionId,
contentGroups: this.contentGroups,
advanced_settings_url: this.advanced_settings_url
});
this.editor.render();
......@@ -122,21 +129,32 @@ var edx = edx || {};
if (this.notification) {
this.notification.remove();
}
if (this.cohortFormView) {
this.cohortFormView.removeNotification();
}
},
showAddCohortForm: function(event) {
var newCohort;
event.preventDefault();
this.removeNotification();
this.addCohortForm = $(this.addCohortFormTemplate({}));
this.addCohortForm.insertAfter(this.$('.cohort-management-nav'));
newCohort = new CohortModel();
newCohort.url = this.model.url;
this.cohortFormView = new CohortFormView({
model: newCohort,
cohortUserPartitionId: this.cohortUserPartitionId,
contentGroups: this.contentGroups
});
this.cohortFormView.render();
this.$('.cohort-management-add-modal').append(this.cohortFormView.$el);
this.setCohortEditorVisibility(false);
},
hideAddCohortForm: function() {
this.setCohortEditorVisibility(true);
if (this.addCohortForm) {
this.addCohortForm.remove();
this.addCohortForm = null;
if (this.cohortFormView) {
this.cohortFormView.remove();
this.cohortFormView = null;
}
},
......@@ -151,42 +169,23 @@ var edx = edx || {};
},
saveAddCohortForm: function(event) {
event.preventDefault();
var self = this,
showAddError,
cohortName = this.$('.cohort-create-name').val().trim();
showAddError = function(message) {
self.showNotification(
{type: 'error', title: message},
self.$('.cohort-management-create-form-name label')
);
};
newCohort = this.cohortFormView.model;
event.preventDefault();
this.removeNotification();
if (cohortName.length > 0) {
$.post(
this.model.url + '/add',
{name: cohortName}
).done(function(result) {
if (result.success) {
self.lastSelectedCohortId = result.cohort.id;
self.model.fetch().done(function() {
self.showNotification({
type: 'confirmation',
title: interpolate_text(
gettext('The {cohortGroupName} cohort group has been created. You can manually add students to this group below.'),
{cohortGroupName: cohortName}
)
});
});
} else {
showAddError(result.msg);
}
}).fail(function() {
showAddError(gettext("We've encountered an error. Please refresh your browser and then try again."));
this.cohortFormView.saveForm()
.done(function() {
self.lastSelectedCohortId = newCohort.id;
self.model.fetch().done(function() {
self.showNotification({
type: 'confirmation',
title: interpolate_text(
gettext('The {cohortGroupName} cohort group has been created. You can manually add students to this group below.'),
{cohortGroupName: newCohort.get('name')}
)
});
});
} else {
showAddError(gettext('Please enter a name for your new cohort group.'));
}
});
},
cancelAddCohortForm: function(event) {
......@@ -234,5 +233,5 @@ var edx = edx || {};
return ".instructor-nav .nav-item a[data-section='" + section + "']";
}
});
}).call(this, $, _, Backbone, gettext, interpolate_text, edx.groups.CohortEditorView,
NotificationModel, NotificationView, FileUploaderView);
}).call(this, $, _, Backbone, gettext, interpolate_text, edx.groups.CohortModel, edx.groups.CohortEditorView,
edx.groups.CohortFormView, NotificationModel, NotificationView, FileUploaderView);
......@@ -65,8 +65,10 @@
'js/views/file_uploader': 'js/views/file_uploader',
'js/views/notification': 'js/views/notification',
'js/groups/models/cohort': 'js/groups/models/cohort',
'js/groups/models/content_group': 'js/groups/models/content_group',
'js/groups/collections/cohort': 'js/groups/collections/cohort',
'js/groups/views/cohort_editor': 'js/groups/views/cohort_editor',
'js/groups/views/cohort_form': 'js/groups/views/cohort_form',
'js/groups/views/cohorts': 'js/groups/views/cohorts',
'js/student_account/account': 'js/student_account/account',
'js/student_account/views/FormView': 'js/student_account/views/FormView',
......@@ -284,17 +286,28 @@
exports: 'edx.groups.CohortModel',
deps: ['backbone']
},
'js/groups/models/content_group': {
exports: 'edx.groups.ContentGroupModel',
deps: ['backbone']
},
'js/groups/collections/cohort': {
exports: 'edx.groups.CohortCollection',
deps: ['backbone', 'js/groups/models/cohort']
},
'js/groups/views/cohort_editor': {
exports: 'edx.groups.CohortsEditor',
'js/groups/views/cohort_form': {
exports: 'edx.groups.CohortFormView',
deps: [
'backbone', 'jquery', 'underscore', 'js/views/notification', 'js/models/notification',
'string_utils'
]
},
'js/groups/views/cohort_editor': {
exports: 'edx.groups.CohortEditorView',
deps: [
'backbone', 'jquery', 'underscore', 'js/views/notification', 'js/models/notification',
'string_utils', 'js/groups/views/cohort_form'
]
},
'js/groups/views/cohorts': {
exports: 'edx.groups.CohortsView',
deps: [
......
.msg {
&.inline {
@extend %t-copy-sub2;
display: inline-block;
margin: 0 0 0 $baseline;
padding: 0;
}
&.error {
@extend %t-copy-sub2;
color: $error-red;
}
}
.cohort-management {
.has-option-unavailable { // Given to <selects> that have some options that are unavailable
......@@ -59,34 +44,40 @@
@include clearfix();
background: $gray-l5;
.group-header-title {
padding: $baseline;
margin-bottom: 0;
border-bottom: 1px solid $gray-l3;
text-transform: none;
letter-spacing: normal;
}
.cohort-management-group-setup {
padding: $baseline;
.cohort-manage-group-header {
padding: 0;
border-bottom: 0;
.cohort-management-group-text {
display: inline-block;
width: flex-grid(9);
.group-header-title {
padding: $baseline;
margin-bottom: 0;
border-bottom: 1px solid $gray-l3;
text-transform: none;
letter-spacing: normal;
}
.cohort-management-group-actions {
display: inline-block;
width: flex-grid(3);
vertical-align: top;
.cohort-management-group-setup {
padding: $baseline;
.float-right {
float: right;
.cohort-management-group-text {
display: inline-block;
width: flex-grid(9);
}
.cohort-management-group-actions {
display: inline-block;
width: flex-grid(3);
vertical-align: top;
.float-right {
float: right;
}
}
}
}
.cohort-management-details {
.cohort-management-details,
.cohort-management-group-add {
border-top: ($baseline/5) solid $gray-l4;
background: $white;
......@@ -149,4 +140,4 @@
}
}
}
}
\ No newline at end of file
}
......@@ -17,7 +17,6 @@
.instructor-dashboard-wrapper-2 {
position: relative;
// display: table;
.olddash-button-wrapper {
position: absolute;
......@@ -56,6 +55,14 @@
}
}
// TYPE: inline
.msg-inline {
@extend %t-copy-sub2;
display: inline-block;
margin: 0 0 0 $baseline;
padding: 0;
}
// TYPE: warning
.msg-warning {
border-top: 2px solid $warning-color;
......@@ -125,16 +132,11 @@
// instructor dashboard 2
// ====================
section.instructor-dashboard-content-2 {
.instructor-dashboard-content-2 {
@extend .content;
// position: relative;
padding: 40px;
width: 100%;
// .has-event-handler-for-click {
// border: 1px solid blue;
// }
.wrap-instructor-info {
display: inline;
top: 0;
......@@ -222,6 +224,7 @@ section.instructor-dashboard-content-2 {
// messages
.message {
margin-top: $baseline;
margin-bottom: $baseline;
display: block;
border-radius: 1px;
......@@ -426,6 +429,7 @@ section.instructor-dashboard-content-2 {
}
// view - membership
// --------------------
.instructor-dashboard-wrapper-2 section.idash-section#membership {
.membership-section {
......@@ -538,11 +542,17 @@ section.instructor-dashboard-content-2 {
}
// create or edit cohort group
.cohort-management-create, .cohort-management-edit {
.cohort-management-settings,
.cohort-management-edit {
@extend %cohort-management-form;
border: 1px solid $gray-l5;
margin-bottom: $baseline;
.message {
margin-left: $baseline;
margin-right: $baseline;
}
.form-title {
@extend %t-title5;
@extend %t-weight4;
......@@ -551,7 +561,7 @@ section.instructor-dashboard-content-2 {
padding: $baseline;
}
.form-fields {
.form-field {
padding: $baseline;
}
......@@ -640,6 +650,9 @@ section.instructor-dashboard-content-2 {
@extend %t-title6;
@extend %t-weight4;
margin-bottom: ($baseline/4);
border: none;
background: transparent;
padding: 0;
}
.form-introduction {
......@@ -957,7 +970,148 @@ section.instructor-dashboard-content-2 {
}
}
}
/*
* Begin additional/override styles for cohort management.
* Placed for merge, but will need to be cleaned up and
* refactored in this stylesheet.
*/
.has-other-input-text { // Given to groups which have an 'other' input that appears when needed
display: inline-block;
label {
display: inline-block;
}
.input-group-other {
display: inline;
position: relative;
overflow: auto;
width: 100%;
height: auto;
margin: 0 0 0 $baseline;
padding: inherit;
border: inherit;
clip: auto;
&.is-hidden {
display: none;
}
.input-cohort-group-association {
display: inline;
}
}
}
.cohort-management-nav {
margin-bottom: $baseline;
}
.cohort-management-settings {
@include clearfix();
background: $gray-l5;
.cohort-management-group-header {
padding: 0;
border-bottom: 0;
.group-header-title {
padding: $baseline;
margin-bottom: 0;
border-bottom: 1px solid $gray-l3;
text-transform: none;
letter-spacing: normal;
}
.cohort-management-group-setup {
padding: $baseline;
.cohort-management-group-text {
display: inline-block;
width: flex-grid(9);
}
.cohort-management-group-actions {
display: inline-block;
width: flex-grid(3);
vertical-align: top;
text-align: right;
}
}
}
.cohort-management-details,
.cohort-management-group-add {
border-top: ($baseline/5) solid $gray-l4;
background: $white;
.cohort-management-settings {
margin-bottom: 0;
border-top: 0;
background: $white;
}
.cohort-details-name {
@extend %t-action1;
display: block;
width: 100%;
padding: ($baseline/2);
margin-bottom: ($baseline*2);
}
.cohort-section-header {
margin-top: ($baseline*1.5);
padding: $baseline 0 ($baseline/2) 0;
}
.cohort-section-header > .form-field {
padding-bottom: $baseline;
}
}
}
.wrapper-tabs { // This applies to the tab-like interface that toggles between the student management and the group settings
@extend %ui-no-list;
@extend %ui-depth1;
position: relative;
top: (($baseline/5));
padding: 0 $baseline;
.tab {
position: relative;
display: inline-block;
a {
display: inline-block;
padding: $baseline;
-webkit-transition: none;
-moz-transition: none;
-ms-transition: none;
-o-transition: none;
transition: none;
}
&.is-selected { // Active or selected tabs (<li>) get this class. Also useful for aria stuff if ever implemented in the future.
a {
padding-bottom: ($baseline+($baseline/5));
border-style: solid;
border-width: ($baseline/5) ($baseline/5) 0 ($baseline/5);
border-color: $gray-l4;
background: $white;
color: inherit;
cursor: default;
}
}
}
}
}
/*
* End of additions/overrides
* Don't forget to refactor.
*/
// view - student admin
// --------------------
......@@ -1771,5 +1925,3 @@ input[name="subject"] {
left: 2em;
right: auto;
}
@import '_cohort-management';
\ No newline at end of file
<div class="cohort-management-create">
<form action="" method="post" name="" id="cohort-management-create-form" class="cohort-management-create-form">
<h3 class="form-title"><%- gettext('Add a New Cohort Group') %></h3>
<div class="form-fields">
<div class="cohort-management-create-form-name field field-text">
<label for="cohort-create-name" class="label">
<%- gettext('New Cohort Name') %> *
<span class="sr"><%- gettext('(Required Field)')%></span>
</label>
<input type="text" name="cohort-create-name" value="" class="input cohort-create-name"
id="cohort-create-name"
placeholder="<%- gettext("Enter Your New Cohort Group's Name") %>" required="required" />
</div>
</div>
<div class="form-actions">
<button class="form-submit button action-primary action-save">
<i class="icon fa fa-plus"></i>
<%- gettext('Save') %>
</button>
<a href="" class="form-cancel action-secondary action-cancel"><%- gettext('Cancel') %></a>
</div>
</form>
</div>
<header class="cohort-management-group-header">
<h3 class="group-header-title">
<span class="title-value"><%- cohort.get('name') %></span>
<span class="group-count"><%-
interpolate(
ngettext('(contains %(student_count)s student)', '(contains %(student_count)s students)', cohort.get('user_count')),
{ student_count: cohort.get('user_count') },
true
)
%></span>
</h3>
<div class="cohort-management-group-setup">
<div class="setup-value">
<% if (cohort.get('assignment_type') == "none") { %>
<%= gettext("Students are added to this group only when you provide their email addresses or usernames on this page.") %>
<a href="http://edx.readthedocs.org/projects/edx-partner-course-staff/en/latest/cohorts/cohort_config.html#assign-students-to-cohort-groups-manually" class="incontext-help action-secondary action-help"><%= gettext("What does this mean?") %></a>
<% } else { %>
<%= gettext("Students are added to this group automatically.") %>
<a href="http://edx.readthedocs.org/projects/edx-partner-course-staff/en/latest/cohorts/cohorts_overview.html#all-automated-assignment" class="incontext-help action-secondary action-help"><%= gettext("What does this mean?") %></a>
<% } %>
</div>
<div class="setup-actions">
<% if (advanced_settings_url != "None") { %>
<a href="<%= advanced_settings_url %>" class="action-secondary action-edit"><%= gettext("Edit settings in Studio") %></a>
<% } %>
<section class="cohort-management-settings has-tabs">
<header class="cohort-management-group-header">
<h3 class="group-header-title">
<span class="title-value"><%- cohort.get('name') %></span>
<span class="group-count"><%-
interpolate(
ngettext('(contains %(student_count)s student)', '(contains %(student_count)s students)', cohort.get('user_count')),
{ student_count: cohort.get('user_count') },
true
)
%></span>
</h3>
<div class="cohort-management-group-setup">
<div class="setup-value">
<% if (cohort.get('assignment_type') == "none") { %>
<%- gettext("Students are added to this group only when you provide their email addresses or usernames on this page.") %>
<a href="http://edx.readthedocs.org/projects/edx-partner-course-staff/en/latest/cohorts/cohort_config.html#assign-students-to-cohort-groups-manually" class="incontext-help action-secondary action-help"><%= gettext("What does this mean?") %></a>
<% } else { %>
<%- gettext("Students are added to this group automatically.") %>
<a href="http://edx.readthedocs.org/projects/edx-partner-course-staff/en/latest/cohorts/cohorts_overview.html#all-automated-assignment" class="incontext-help action-secondary action-help"><%- gettext("What does this mean?") %></a>
<% } %>
</div>
<div class="setup-actions">
<% if (advanced_settings_url != "None") { %>
<a href="<%= advanced_settings_url %>" class="action-secondary action-edit"><%- gettext("Edit settings in Studio") %></a>
<% } %>
</div>
</div>
</div>
</header>
</header>
<!-- individual group - form -->
<div class="cohort-management-group-add">
<form action="" method="post" id="cohort-management-group-add-form" class="cohort-management-group-add-form">
<ul class="wrapper-tabs">
<li class="tab tab-manage_students is-selected" data-tab="manage_students"><a href="#"><%- gettext("Manage Students") %></a></li>
<li class="tab tab-settings" data-tab="settings"><a href="#"><%- gettext("Settings") %></a></li>
</ul>
<h4 class="form-title"><%- gettext('Add students to this cohort group') %></h4>
<div class="cohort-management-group-add tab-content tab-content-manage_students">
<form action="" method="post" id="cohort-management-group-add-form" class="cohort-management-group-add-form">
<div class="form-introduction">
<p><%- gettext('Note: Students can only be in one cohort group. Adding students to this group overrides any previous group assignment.') %></p>
</div>
<h4 class="form-title"><%- gettext('Add students to this cohort group') %></h4>
<div class="form-introduction">
<p><%- gettext('Note: Students can only be in one cohort group. Adding students to this group overrides any previous group assignment.') %></p>
</div>
<div class="cohort-confirmations"></div>
<div class="cohort-errors"></div>
<div class="cohort-confirmations"></div>
<div class="cohort-errors"></div>
<div class="form-fields">
<div class="field field-textarea is-required">
<label for="cohort-management-group-add-students" class="label">
<%- gettext('Enter email addresses and/or usernames separated by new lines or commas for students to add. *') %>
<span class="sr"><%- gettext('(Required Field)') %></span>
</label>
<textarea name="cohort-management-group-add-students" id="cohort-management-group-add-students"
class="input cohort-management-group-add-students"
placeholder="<%- gettext('e.g. johndoe@example.com, JaneDoe, joeydoe@example.com') %>"></textarea>
<div class="form-fields">
<div class="field field-textarea is-required">
<label for="cohort-management-group-add-students" class="label">
<%- gettext('Enter email addresses and/or usernames separated by new lines or commas for students to add. *') %>
<span class="sr"><%- gettext('(Required Field)') %></span>
</label>
<textarea name="cohort-management-group-add-students" id="cohort-management-group-add-students"
class="input cohort-management-group-add-students"
placeholder="<%- gettext('e.g. johndoe@example.com, JaneDoe, joeydoe@example.com') %>"></textarea>
<span class="tip"><%- gettext('You will not get notification for emails that bounce, so please double-check spelling.') %></span>
<span class="tip"><%- gettext('You will not get notification for emails that bounce, so please double-check spelling.') %></span>
</div>
</div>
</div>
<div class="form-actions">
<button class="form-submit button action-primary action-view">
<i class="button-icon icon fa fa-plus"></i> <%- gettext('Add Students') %>
</button>
</div>
</form>
</div>
<div class="form-actions">
<button class="form-submit button action-primary action-view">
<i class="button-icon icon fa fa-plus"></i> <%- gettext('Add Students') %>
</button>
</div>
</form>
</div>
<div class="cohort-management-details tab-content tab-content-settings is-hidden">
</div>
</section>
<% var isNewCohort = cohort.id == null; %>
<div class="cohort-management-settings">
<form action="" method="post" name="" id="cohort-management-settings-form" class="cohort-management-settings-form">
<% if (isNewCohort) { %>
<h3 class="form-title"><%- gettext('Add a New Cohort Group') %></h3>
<% } %>
<div class="form-fields">
<%
// Don't allow renaming of existing cohorts yet as it doesn't interact well with
// the course's advanced setting for auto cohorting.
if (isNewCohort) {
%>
<div class="form-field">
<div class="cohort-management-settings-form-name field field-text">
<label for="cohort-name" class="label">
<%- gettext('Cohort Name') %> *
<span class="sr"><%- gettext('(Required Field)')%></span>
</label>
<input type="text" name="cohort-name" value="<%- cohort ? cohort.get('name') : '' %>" class="input cohort-name"
id="cohort-name"
placeholder="<%- gettext("Enter Your Cohort Group's Name") %>" required="required" />
</div>
</div>
<% } %>
<%
var foundSelected = false;
var selectedContentGroupId = cohort.get('group_id');
var hasSelectedContentGroup = selectedContentGroupId != null;
%>
<div class="form-field">
<div class="cohort-management-details-association-course field field-radio">
<label class="label">
<%- gettext('Is this cohort group associated with course-based content groups?') %>
</label>
<label><input type="radio" class="radio-no" name="cohort-association-course" value="no" <%- !hasSelectedContentGroup ? 'checked="checked"' : '' %>/> <%- gettext("No") %></label>
<div class="input-group has-other-input-text">
<label><input type="radio" class="radio-yes" name="cohort-association-course" value="yes" <%- hasSelectedContentGroup ? 'checked="checked"' : '' %> /> <%- gettext("Yes") %></label>
<% if (contentGroups.length > 0) { %>
<div class="input-group-other">
<label class="sr" for="cohort-group-association"><%- gettext("Choose a content group to associate") %></label>
<select name="cohort-group-association" class="input input-lg has-option-unavailable input-cohort-group-association">
<option value="None"><%- gettext("Choose a content group to associate") %></option>
<%
var orderedContentGroups = _.sortBy(
contentGroups,
function(group) { return group.get('name'); }
);
for (var i=0; i < orderedContentGroups.length; i++) {
var contentGroup = orderedContentGroups[i];
var contentGroupId = contentGroup.get('id');
var isSelected = contentGroupId == selectedContentGroupId;
if (isSelected) {
foundSelected = true;
}
%>
<option value="<%- contentGroupId %>" <%- isSelected ? 'selected="selected"' : '' %>><%- contentGroup.get('name') %></option>
<%
}
%>
<% if (hasSelectedContentGroup && !foundSelected) { %>
<option value="<%- contentGroupId %>" class="option-unavailable" selected="selected"><%- gettext("Some content group that's been deleted") %></option>
<% } %>
</select>
<% if (hasSelectedContentGroup && !foundSelected) { %>
<div class="msg-inline">
<p class="copy-error"><i class="icon icon-warning-sign"></i><%- gettext("The selected content group has been deleted, you may wish to reassign this cohort group.") %></p>
</div>
<% } %>
</div>
<% } else { // no content groups available %>
<div class="input-group-other is-visible">
<div class="msg-inline">
<p class="copy-error"><i class="icon icon-warning-sign"></i> You haven't configured any content groups yet. You need to create a content group before you can create assignments. <a href="#">Create a content group</a></p>
</div>
</div>
<% } %>
</div>
</div>
</div>
</div>
<div class="form-actions">
<button class="form-submit button action-primary action-save">
<i class="icon fa fa-plus"></i>
<%- gettext('Save') %>
</button>
<% if (isNewCohort) { %>
<a href="" class="form-cancel action-secondary action-cancel"><%- gettext('Cancel') %></a>
<% } %>
</div>
</form>
</div>
......@@ -24,6 +24,9 @@
</a>
</div>
<!-- Add modal -->
<div class="cohort-management-add-modal"></div>
<!-- individual group -->
<div class="cohort-management-group"></div>
......
......@@ -58,14 +58,16 @@
<script type="text/javascript" src="${static.url('js/views/notification.js')}"></script>
<script type="text/javascript" src="${static.url('js/views/file_uploader.js')}"></script>
<script type="text/javascript" src="${static.url('js/groups/models/cohort.js')}"></script>
<script type="text/javascript" src="${static.url('js/groups/models/content_group.js')}"></script>
<script type="text/javascript" src="${static.url('js/groups/collections/cohort.js')}"></script>
<script type="text/javascript" src="${static.url('js/groups/views/cohort_form.js')}"></script>
<script type="text/javascript" src="${static.url('js/groups/views/cohort_editor.js')}"></script>
<script type="text/javascript" src="${static.url('js/groups/views/cohorts.js')}"></script>
</%block>
## Include Underscore templates
<%block name="header_extras">
% for template_name in ["cohorts", "cohort-editor", "cohort-selector", "add-cohort-form", "notification"]:
% for template_name in ["cohorts", "cohort-editor", "cohort-selector", "cohort-form", "notification"]:
<script type="text/template" id="${template_name}-tpl">
<%static:include path="instructor/instructor_dashboard_2/${template_name}.underscore" />
</script>
......
<%! from django.utils.translation import ugettext as _ %>
<%page args="section_data"/>
<%! from microsite_configuration import microsite %>
<%! from openedx.core.djangoapps.course_groups.partition_scheme import get_cohorted_user_partition %>
<script type="text/template" id="member-list-widget-template">
<div class="member-list-widget">
......@@ -244,7 +245,7 @@
</div>
%if course.is_cohorted:
% if course.is_cohorted:
<hr class="divider" />
<div class="cohort-management membership-section"
data-ajax_url="${section_data['cohorts_ajax_url']}"
......@@ -254,15 +255,29 @@
</div>
<%block name="headextra">
<%
cohorted_user_partition = get_cohorted_user_partition(course.id)
content_groups = cohorted_user_partition.groups if cohorted_user_partition else []
%>
<script>
$(document).ready(function() {
var cohortManagementElement = $('.cohort-management');
if (cohortManagementElement.length > 0) {
var cohorts = new edx.groups.CohortCollection();
var cohorts = new edx.groups.CohortCollection(),
contentGroups = [
% for content_group in content_groups:
new edx.groups.ContentGroupModel({
id: ${content_group.id},
name: "${content_group.name | h}"
}),
% endfor
];
cohorts.url = cohortManagementElement.data('ajax_url');
var cohortsView = new edx.groups.CohortsView({
el: cohortManagementElement,
model: cohorts,
cohortUserPartitionId: ${cohorted_user_partition.id if cohorted_user_partition else 'null'},
contentGroups: contentGroups,
advanced_settings_url: cohortManagementElement.data('advanced-settings-url'),
upload_cohorts_csv_url: cohortManagementElement.data('upload_cohorts_csv_url')
});
......
......@@ -43,7 +43,6 @@
<section class="instructor-dashboard-content-2" id="instructor-dashboard-content">
<h1>Instructor Dashboard</h1>
<section class="idash-section active-section" id="membership">
<div class="cohort-management membership-section">
<h2 class="section-title">
<span class="value">Cohort Group Management</span>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment