Assign cohorts to groups in the instructor dashboard
TNL-653
This commit is contained in:
@@ -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):
|
||||
"""
|
||||
|
||||
14
lms/static/js/groups/models/content_group.js
Normal file
14
lms/static/js/groups/models/content_group.js
Normal file
@@ -0,0 +1,14 @@
|
||||
var edx = edx || {};
|
||||
|
||||
(function(Backbone) {
|
||||
'use strict';
|
||||
|
||||
edx.groups = edx.groups || {};
|
||||
|
||||
edx.groups.ContentGroupModel = Backbone.Model.extend({
|
||||
idAttribute: 'id',
|
||||
defaults: {
|
||||
name: ''
|
||||
}
|
||||
});
|
||||
}).call(this, Backbone);
|
||||
@@ -1,18 +1,22 @@
|
||||
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);
|
||||
|
||||
128
lms/static/js/groups/views/cohort_form.js
Normal file
128
lms/static/js/groups/views/cohort_form.js
Normal file
@@ -0,0 +1,128 @@
|
||||
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);
|
||||
@@ -1,6 +1,6 @@
|
||||
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);
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpers/template_helpers',
|
||||
'js/groups/views/cohorts', 'js/groups/collections/cohort', 'string_utils'],
|
||||
function (Backbone, $, AjaxHelpers, TemplateHelpers, CohortsView, CohortCollection) {
|
||||
'js/groups/views/cohorts', 'js/groups/collections/cohort', 'js/groups/models/content_group'],
|
||||
function (Backbone, $, AjaxHelpers, TemplateHelpers, CohortsView, CohortCollection, ContentGroupModel) {
|
||||
'use strict';
|
||||
|
||||
describe("Cohorts View", function () {
|
||||
var catLoversInitialCount = 123, dogLoversInitialCount = 456, unknownUserMessage,
|
||||
createMockCohort, createMockCohorts, createCohortsView, cohortsView, requests, respondToRefresh,
|
||||
verifyMessage, verifyNoMessage, verifyDetailedMessage, verifyHeader;
|
||||
createMockCohort, createMockCohorts, createMockContentGroups, createCohortsView, cohortsView,
|
||||
requests, respondToRefresh, verifyMessage, verifyNoMessage, verifyDetailedMessage, verifyHeader,
|
||||
expectCohortAddRequest, getAddModal, selectContentGroup, clearContentGroup;
|
||||
|
||||
createMockCohort = function (name, id, user_count) {
|
||||
createMockCohort = function (name, id, userCount, groupId, userPartitionId) {
|
||||
return {
|
||||
id: id || 1,
|
||||
name: name,
|
||||
user_count: user_count || 0
|
||||
user_count: userCount || 0,
|
||||
group_id: groupId,
|
||||
user_partition_id: userPartitionId
|
||||
};
|
||||
};
|
||||
|
||||
@@ -23,17 +28,29 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
};
|
||||
};
|
||||
|
||||
createCohortsView = function (test, initialCohortID, initialCohorts) {
|
||||
var cohorts = new CohortCollection(initialCohorts || createMockCohorts(), {parse: true});
|
||||
cohorts.url = '/mock_service';
|
||||
createMockContentGroups = function () {
|
||||
return [
|
||||
new ContentGroupModel({id: 0, name: 'Dog Content'}),
|
||||
new ContentGroupModel({id: 1, name: 'Cat Content'})
|
||||
];
|
||||
};
|
||||
|
||||
createCohortsView = function (test, options) {
|
||||
var cohortsJson, cohorts, contentGroups;
|
||||
options = options || {};
|
||||
cohortsJson = options.cohorts ? {cohorts: options.cohorts} : createMockCohorts();
|
||||
cohorts = new CohortCollection(cohortsJson, {parse: true});
|
||||
contentGroups = options.contentGroups || createMockContentGroups();
|
||||
cohorts.url = '/mock_service/cohorts';
|
||||
requests = AjaxHelpers.requests(test);
|
||||
cohortsView = new CohortsView({
|
||||
model: cohorts,
|
||||
contentGroups: contentGroups,
|
||||
upload_cohorts_csv_url: "http://upload-csv-file-url/"
|
||||
});
|
||||
cohortsView.render();
|
||||
if (initialCohortID) {
|
||||
cohortsView.$('.cohort-select').val(initialCohortID.toString()).change();
|
||||
if (options && options.selectCohort) {
|
||||
cohortsView.$('.cohort-select').val(options.selectCohort.toString()).change();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -41,6 +58,33 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
AjaxHelpers.respondWithJson(requests, createMockCohorts(catCount, dogCount));
|
||||
};
|
||||
|
||||
expectCohortAddRequest = function(name, group_id) {
|
||||
AjaxHelpers.expectJsonRequest(
|
||||
requests, 'POST', '/mock_service/cohorts',
|
||||
{
|
||||
name: name,
|
||||
user_count: 0,
|
||||
assignment_type: '',
|
||||
group_id: group_id
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
getAddModal = function() {
|
||||
return cohortsView.$('.cohort-management-add-modal');
|
||||
};
|
||||
|
||||
selectContentGroup = function(values) {
|
||||
cohortsView.$('.radio-yes').prop('checked', true).change();
|
||||
cohortsView.$('.input-cohort-group-association').val(values).change();
|
||||
};
|
||||
|
||||
clearContentGroup = function() {
|
||||
cohortsView.$('.radio-no').prop('checked', true).change();
|
||||
expect(cohortsView.$('.radio-yes').prop('checked')).toBeFalsy();
|
||||
expect(cohortsView.$('.input-cohort-group-association').val()).toBe('None');
|
||||
};
|
||||
|
||||
verifyMessage = function(expectedTitle, expectedMessageType, expectedAction, hasDetails) {
|
||||
expect(cohortsView.$('.message-title').text().trim()).toBe(expectedTitle);
|
||||
expect(cohortsView.$('div.message')).toHaveClass('message-' + expectedMessageType);
|
||||
@@ -94,7 +138,7 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
beforeEach(function () {
|
||||
setFixtures('<ul class="instructor-nav"><li class="nav-item"><<a href data-section="membership" class="active-section">Membership</a></li></ul><div></div>');
|
||||
TemplateHelpers.installTemplate('templates/instructor/instructor_dashboard_2/cohorts');
|
||||
TemplateHelpers.installTemplate('templates/instructor/instructor_dashboard_2/add-cohort-form');
|
||||
TemplateHelpers.installTemplate('templates/instructor/instructor_dashboard_2/cohort-form');
|
||||
TemplateHelpers.installTemplate('templates/instructor/instructor_dashboard_2/cohort-selector');
|
||||
TemplateHelpers.installTemplate('templates/instructor/instructor_dashboard_2/cohort-editor');
|
||||
TemplateHelpers.installTemplate('templates/instructor/instructor_dashboard_2/notification');
|
||||
@@ -102,7 +146,7 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
});
|
||||
|
||||
it("Show an error if no cohorts are defined", function() {
|
||||
createCohortsView(this, null, { cohorts: [] });
|
||||
createCohortsView(this, {cohorts: []});
|
||||
verifyMessage(
|
||||
'You currently have no cohort groups configured',
|
||||
'warning',
|
||||
@@ -114,14 +158,42 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
});
|
||||
|
||||
it("Syncs data when membership tab is clicked", function() {
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
verifyHeader(1, 'Cat Lovers', catLoversInitialCount);
|
||||
$(cohortsView.getSectionCss("membership")).click();
|
||||
AjaxHelpers.expectRequest(requests, 'GET', '/mock_service');
|
||||
AjaxHelpers.expectRequest(requests, 'GET', '/mock_service/cohorts');
|
||||
respondToRefresh(1001, 2);
|
||||
verifyHeader(1, 'Cat Lovers', 1001);
|
||||
});
|
||||
|
||||
it('can upload a CSV of cohort assignments if a cohort exists', function () {
|
||||
var uploadCsvToggle, fileUploadForm, fileUploadFormCss='#file-upload-form';
|
||||
|
||||
createCohortsView(this);
|
||||
|
||||
// Should see the control to toggle CSV file upload.
|
||||
expect(cohortsView.$('.wrapper-cohort-supplemental')).not.toHaveClass('is-hidden');
|
||||
// But upload form should not be visible until toggle is clicked.
|
||||
expect(cohortsView.$(fileUploadFormCss).length).toBe(0);
|
||||
uploadCsvToggle = cohortsView.$('.toggle-cohort-management-secondary');
|
||||
expect(uploadCsvToggle.text()).
|
||||
toContain('Assign students to cohort groups by uploading a CSV file');
|
||||
uploadCsvToggle.click();
|
||||
// After toggle is clicked, it should be hidden.
|
||||
expect(uploadCsvToggle).toHaveClass('is-hidden');
|
||||
|
||||
fileUploadForm = cohortsView.$(fileUploadFormCss);
|
||||
expect(fileUploadForm.length).toBe(1);
|
||||
cohortsView.$(fileUploadForm).fileupload('add', {files: [{name: 'upload_file.txt'}]});
|
||||
cohortsView.$('.submit-file-button').click();
|
||||
|
||||
// No file will actually be uploaded because "uploaded_file.txt" doesn't actually exist.
|
||||
AjaxHelpers.expectRequest(requests, 'POST', "http://upload-csv-file-url/", new FormData());
|
||||
AjaxHelpers.respondWithJson(requests, {});
|
||||
expect(cohortsView.$('.file-upload-form-result .message-confirmation .message-title').text().trim())
|
||||
.toBe("Your file 'upload_file.txt' has been uploaded. Please allow a few minutes for processing.");
|
||||
});
|
||||
|
||||
describe("Cohort Selector", function () {
|
||||
it('has no initial selection', function () {
|
||||
createCohortsView(this);
|
||||
@@ -129,63 +201,57 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
expect(cohortsView.$('.cohort-management-group-header .title-value').text()).toBe('');
|
||||
});
|
||||
|
||||
it('can upload a CSV of cohort assignments if a cohort exists', function () {
|
||||
var uploadCsvToggle, fileUploadForm, fileUploadFormCss='#file-upload-form';
|
||||
|
||||
createCohortsView(this);
|
||||
|
||||
// Should see the control to toggle CSV file upload.
|
||||
expect(cohortsView.$('.wrapper-cohort-supplemental')).not.toHaveClass('is-hidden');
|
||||
// But upload form should not be visible until toggle is clicked.
|
||||
expect(cohortsView.$(fileUploadFormCss).length).toBe(0);
|
||||
uploadCsvToggle = cohortsView.$('.toggle-cohort-management-secondary');
|
||||
expect(uploadCsvToggle.text()).
|
||||
toContain('Assign students to cohort groups by uploading a CSV file');
|
||||
uploadCsvToggle.click();
|
||||
// After toggle is clicked, it should be hidden.
|
||||
expect(uploadCsvToggle).toHaveClass('is-hidden');
|
||||
|
||||
fileUploadForm = cohortsView.$(fileUploadFormCss);
|
||||
expect(fileUploadForm.length).toBe(1);
|
||||
cohortsView.$(fileUploadForm).fileupload('add', {files: [{name: 'upload_file.txt'}]});
|
||||
cohortsView.$('.submit-file-button').click();
|
||||
|
||||
// No file will actually be uploaded because "uploaded_file.txt" doesn't actually exist.
|
||||
AjaxHelpers.expectRequest(requests, 'POST', "http://upload-csv-file-url/", new FormData());
|
||||
AjaxHelpers.respondWithJson(requests, {});
|
||||
expect(cohortsView.$('.file-upload-form-result .message-confirmation .message-title').text().trim())
|
||||
.toBe("Your file 'upload_file.txt' has been uploaded. Please allow a few minutes for processing.");
|
||||
});
|
||||
|
||||
it('can select a cohort', function () {
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
verifyHeader(1, 'Cat Lovers', catLoversInitialCount);
|
||||
});
|
||||
|
||||
it('can switch cohort', function () {
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
cohortsView.$('.cohort-select').val("2").change();
|
||||
verifyHeader(2, 'Dog Lovers', dogLoversInitialCount);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Cohort Editor Tab Panel", function () {
|
||||
it("initially selects the Manage Students tab", function () {
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
expect(cohortsView.$('.tab-manage_students')).toHaveClass('is-selected');
|
||||
expect(cohortsView.$('.tab-settings')).not.toHaveClass('is-selected');
|
||||
expect(cohortsView.$('.tab-content-manage_students')).not.toHaveClass('is-hidden');
|
||||
expect(cohortsView.$('.tab-content-settings')).toHaveClass('is-hidden');
|
||||
});
|
||||
|
||||
it("can select the Settings tab", function () {
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
cohortsView.$('.tab-settings a').click();
|
||||
expect(cohortsView.$('.tab-manage_students')).not.toHaveClass('is-selected');
|
||||
expect(cohortsView.$('.tab-settings')).toHaveClass('is-selected');
|
||||
expect(cohortsView.$('.tab-content-manage_students')).toHaveClass('is-hidden');
|
||||
expect(cohortsView.$('.tab-content-settings')).not.toHaveClass('is-hidden');
|
||||
});
|
||||
});
|
||||
|
||||
describe("Add Cohorts Form", function () {
|
||||
var defaultCohortName = 'New Cohort';
|
||||
|
||||
it("can add a cohort", function() {
|
||||
createCohortsView(this, null, { cohorts: [] });
|
||||
var contentGroupId = 0;
|
||||
createCohortsView(this, {cohorts: []});
|
||||
cohortsView.$('.action-create').click();
|
||||
expect(cohortsView.$('.cohort-management-create-form').length).toBe(1);
|
||||
expect(cohortsView.$('.cohort-management-settings-form').length).toBe(1);
|
||||
expect(cohortsView.$('.cohort-management-nav')).toHaveClass('is-disabled');
|
||||
expect(cohortsView.$('.cohort-management-group')).toHaveClass('is-hidden');
|
||||
cohortsView.$('.cohort-create-name').val(defaultCohortName);
|
||||
cohortsView.$('.cohort-name').val(defaultCohortName);
|
||||
selectContentGroup(contentGroupId);
|
||||
cohortsView.$('.action-save').click();
|
||||
AjaxHelpers.expectRequest(requests, 'POST', '/mock_service/add', 'name=New+Cohort');
|
||||
expectCohortAddRequest(defaultCohortName, contentGroupId);
|
||||
AjaxHelpers.respondWithJson(
|
||||
requests,
|
||||
{
|
||||
success: true,
|
||||
cohort: { id: 1, name: defaultCohortName }
|
||||
id: 1,
|
||||
name: defaultCohortName,
|
||||
group_id: contentGroupId
|
||||
}
|
||||
);
|
||||
AjaxHelpers.respondWithJson(
|
||||
@@ -200,75 +266,60 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
verifyHeader(1, defaultCohortName, 0);
|
||||
expect(cohortsView.$('.cohort-management-nav')).not.toHaveClass('is-disabled');
|
||||
expect(cohortsView.$('.cohort-management-group')).not.toHaveClass('is-hidden');
|
||||
expect(cohortsView.$('.cohort-management-create-form').length).toBe(0);
|
||||
expect(getAddModal().find('.cohort-management-settings-form').length).toBe(0);
|
||||
});
|
||||
|
||||
it("trims off whitespace before adding a cohort", function() {
|
||||
createCohortsView(this);
|
||||
cohortsView.$('.action-create').click();
|
||||
cohortsView.$('.cohort-create-name').val(' New Cohort ');
|
||||
cohortsView.$('.cohort-name').val(' New Cohort ');
|
||||
cohortsView.$('.action-save').click();
|
||||
AjaxHelpers.expectRequest(requests, 'POST', '/mock_service/add', 'name=New+Cohort');
|
||||
expectCohortAddRequest('New Cohort', null);
|
||||
});
|
||||
|
||||
it("does not allow a blank cohort name to be submitted", function() {
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
cohortsView.$('.action-create').click();
|
||||
expect(cohortsView.$('.cohort-management-create-form').length).toBe(1);
|
||||
cohortsView.$('.cohort-create-name').val('');
|
||||
expect(getAddModal().find('.cohort-management-settings-form').length).toBe(1);
|
||||
cohortsView.$('.cohort-name').val('');
|
||||
expect(cohortsView.$('.cohort-management-nav')).toHaveClass('is-disabled');
|
||||
cohortsView.$('.action-save').click();
|
||||
getAddModal().find('.action-save').click();
|
||||
expect(requests.length).toBe(0);
|
||||
verifyMessage('Please enter a name for your new cohort group.', 'error');
|
||||
});
|
||||
|
||||
it("shows a message when adding a cohort throws a server error", function() {
|
||||
createCohortsView(this, 1);
|
||||
it("shows a message when adding a cohort returns a server error", function() {
|
||||
var addModal;
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
cohortsView.$('.action-create').click();
|
||||
expect(cohortsView.$('.cohort-management-create-form').length).toBe(1);
|
||||
cohortsView.$('.cohort-create-name').val(defaultCohortName);
|
||||
cohortsView.$('.action-save').click();
|
||||
AjaxHelpers.expectRequest(requests, 'POST', '/mock_service/add', 'name=New+Cohort');
|
||||
AjaxHelpers.respondWithError(requests);
|
||||
addModal = getAddModal();
|
||||
expect(addModal.find('.cohort-management-settings-form').length).toBe(1);
|
||||
addModal.find('.cohort-name').val(defaultCohortName);
|
||||
addModal.find('.action-save').click();
|
||||
AjaxHelpers.respondWithError(requests, 400, {
|
||||
error: 'You cannot add two cohorts with the same name'
|
||||
});
|
||||
verifyHeader(1, 'Cat Lovers', catLoversInitialCount);
|
||||
verifyMessage(
|
||||
"We've encountered an error. Please refresh your browser and then try again.",
|
||||
'You cannot add two cohorts with the same name',
|
||||
'error'
|
||||
);
|
||||
});
|
||||
|
||||
it("shows a server message if adding a cohort fails", function() {
|
||||
createCohortsView(this, 1);
|
||||
cohortsView.$('.action-create').click();
|
||||
expect(cohortsView.$('.cohort-management-create-form').length).toBe(1);
|
||||
cohortsView.$('.cohort-create-name').val('Cat Lovers');
|
||||
cohortsView.$('.action-save').click();
|
||||
AjaxHelpers.expectRequest(requests, 'POST', '/mock_service/add', 'name=Cat+Lovers');
|
||||
AjaxHelpers.respondWithJson(
|
||||
requests,
|
||||
{
|
||||
success: false,
|
||||
msg: 'You cannot create two cohorts with the same name'
|
||||
}
|
||||
);
|
||||
verifyHeader(1, 'Cat Lovers', catLoversInitialCount);
|
||||
verifyMessage('You cannot create two cohorts with the same name', 'error');
|
||||
});
|
||||
|
||||
it("is removed when 'Cancel' is clicked", function() {
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
cohortsView.$('.action-create').click();
|
||||
expect(cohortsView.$('.cohort-management-create-form').length).toBe(1);
|
||||
expect(getAddModal().find('.cohort-management-settings-form').length).toBe(1);
|
||||
expect(cohortsView.$('.cohort-management-nav')).toHaveClass('is-disabled');
|
||||
cohortsView.$('.action-cancel').click();
|
||||
expect(cohortsView.$('.cohort-management-create-form').length).toBe(0);
|
||||
expect(getAddModal().find('.cohort-management-settings-form').length).toBe(0);
|
||||
expect(cohortsView.$('.cohort-management-nav')).not.toHaveClass('is-disabled');
|
||||
});
|
||||
|
||||
it("shows an error if canceled when no cohorts are defined", function() {
|
||||
createCohortsView(this, null, { cohorts: [] });
|
||||
createCohortsView(this, {cohorts: []});
|
||||
cohortsView.$('.action-create').click();
|
||||
expect(cohortsView.$('.cohort-management-create-form').length).toBe(1);
|
||||
expect(getAddModal().find('.cohort-management-settings-form').length).toBe(1);
|
||||
expect(cohortsView.$('.cohort-management-nav')).toHaveClass('is-disabled');
|
||||
cohortsView.$('.action-cancel').click();
|
||||
verifyMessage(
|
||||
@@ -279,11 +330,11 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
});
|
||||
|
||||
it("hides any error message when switching to show a cohort", function() {
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
|
||||
// First try to save a blank name to create a message
|
||||
cohortsView.$('.action-create').click();
|
||||
cohortsView.$('.cohort-create-name').val('');
|
||||
cohortsView.$('.cohort-name').val('');
|
||||
cohortsView.$('.action-save').click();
|
||||
verifyMessage('Please enter a name for your new cohort group.', 'error');
|
||||
|
||||
@@ -294,11 +345,11 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
});
|
||||
|
||||
it("hides any error message when canceling the form", function() {
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
|
||||
// First try to save a blank name to create a message
|
||||
cohortsView.$('.action-create').click();
|
||||
cohortsView.$('.cohort-create-name').val('');
|
||||
cohortsView.$('.cohort-name').val('');
|
||||
cohortsView.$('.action-save').click();
|
||||
verifyMessage('Please enter a name for your new cohort group.', 'error');
|
||||
|
||||
@@ -328,7 +379,7 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
};
|
||||
|
||||
it('shows an error when adding with no students specified', function() {
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
addStudents(' ');
|
||||
expect(requests.length).toBe(0);
|
||||
verifyMessage('Please enter a username or email.', 'error');
|
||||
@@ -337,9 +388,8 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
|
||||
it('can add a single student', function() {
|
||||
var catLoversUpdatedCount = catLoversInitialCount + 1;
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
addStudents('student@sample.com');
|
||||
AjaxHelpers.expectRequest(requests, 'POST', '/mock_service/1/add', 'users=student%40sample.com');
|
||||
respondToAdd({ added: ['student@sample.com'] });
|
||||
respondToRefresh(catLoversUpdatedCount, dogLoversInitialCount);
|
||||
verifyHeader(1, 'Cat Lovers', catLoversUpdatedCount);
|
||||
@@ -348,9 +398,11 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
});
|
||||
|
||||
it('shows an error when adding a student that does not exist', function() {
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
addStudents('unknown@sample.com');
|
||||
AjaxHelpers.expectRequest(requests, 'POST', '/mock_service/1/add', 'users=unknown%40sample.com');
|
||||
AjaxHelpers.expectRequest(
|
||||
requests, 'POST', '/mock_service/cohorts/1/add', 'users=unknown%40sample.com'
|
||||
);
|
||||
respondToAdd({ unknown: ['unknown@sample.com'] });
|
||||
respondToRefresh(catLoversInitialCount, dogLoversInitialCount);
|
||||
verifyHeader(1, 'Cat Lovers', catLoversInitialCount);
|
||||
@@ -362,11 +414,12 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
|
||||
it('shows a "view all" button when more than 5 students do not exist', function() {
|
||||
var sixUsers = 'unknown1@sample.com, unknown2@sample.com, unknown3@sample.com, unknown4@sample.com, unknown5@sample.com, unknown6@sample.com';
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
|
||||
addStudents(sixUsers);
|
||||
AjaxHelpers.expectRequest(requests, 'POST', '/mock_service/1/add',
|
||||
'users=' + sixUsers.replace(/@/g, "%40").replace(/, /g, "%2C+")
|
||||
AjaxHelpers.expectRequest(
|
||||
requests, 'POST', '/mock_service/cohorts/1/add',
|
||||
'users=' + sixUsers.replace(/@/g, "%40").replace(/, /g, "%2C+")
|
||||
);
|
||||
respondToAdd({ unknown: [
|
||||
'unknown1@sample.com',
|
||||
@@ -399,10 +452,10 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
|
||||
it('shows students moved from one cohort to another', function() {
|
||||
var sixUsers = 'moved1@sample.com, moved2@sample.com, moved3@sample.com, alreadypresent@sample.com';
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
|
||||
addStudents(sixUsers);
|
||||
AjaxHelpers.expectRequest(requests, 'POST', '/mock_service/1/add',
|
||||
AjaxHelpers.expectRequest(requests, 'POST', '/mock_service/cohorts/1/add',
|
||||
'users=' + sixUsers.replace(/@/g, "%40").replace(/, /g, "%2C+")
|
||||
);
|
||||
respondToAdd({
|
||||
@@ -426,7 +479,7 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
});
|
||||
|
||||
it('shows a message when the add fails', function() {
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
addStudents('student@sample.com');
|
||||
AjaxHelpers.respondWithError(requests);
|
||||
verifyMessage('Error adding students.', 'error');
|
||||
@@ -434,7 +487,7 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
});
|
||||
|
||||
it('clears an error message on subsequent add', function() {
|
||||
createCohortsView(this, 1);
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
|
||||
// First verify that an error is shown
|
||||
addStudents('student@sample.com');
|
||||
@@ -448,5 +501,105 @@ define(['backbone', 'jquery', 'js/common_helpers/ajax_helpers', 'js/common_helpe
|
||||
verifyMessage('1 student has been added to this cohort group', 'confirmation');
|
||||
});
|
||||
});
|
||||
|
||||
describe("Cohort Settings", function() {
|
||||
describe("Content Group Setting", function() {
|
||||
it("shows a select element with an option for each content group", function () {
|
||||
var options;
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
cohortsView.$('.tab-settings a').click();
|
||||
options = cohortsView.$('.input-cohort-group-association option');
|
||||
expect(options.length).toBe(3);
|
||||
expect($(options[0]).text().trim()).toBe('Choose a content group to associate');
|
||||
expect($(options[1]).text().trim()).toBe('Cat Content');
|
||||
expect($(options[2]).text().trim()).toBe('Dog Content');
|
||||
});
|
||||
|
||||
it("can select a single content group", function () {
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
cohortsView.$('.tab-settings a').click();
|
||||
|
||||
// Select the content group with id 1 and verify the radio button was switched to 'Yes'
|
||||
selectContentGroup(0);
|
||||
expect(cohortsView.$('.radio-yes').prop('checked')).toBeTruthy();
|
||||
|
||||
// Click the save button and verify that the correct request is sent
|
||||
cohortsView.$('.action-save').click();
|
||||
AjaxHelpers.expectJsonRequest(
|
||||
requests, 'PATCH', '/mock_service/cohorts/1',
|
||||
{
|
||||
name: 'Cat Lovers',
|
||||
group_id: 0
|
||||
}
|
||||
);
|
||||
AjaxHelpers.respondWithJson(
|
||||
requests,
|
||||
createMockCohort('Cat Lovers', 1, catLoversInitialCount, 0, 0)
|
||||
);
|
||||
verifyMessage('Saved cohort group.', 'confirmation');
|
||||
});
|
||||
|
||||
it("can clear selected content group", function () {
|
||||
createCohortsView(this, {
|
||||
cohorts: [
|
||||
{id: 1, name: 'Cat Lovers', group_id: 0}
|
||||
],
|
||||
selectCohort: 1
|
||||
});
|
||||
cohortsView.$('.tab-settings a').click();
|
||||
expect(cohortsView.$('.radio-yes').prop('checked')).toBeTruthy();
|
||||
clearContentGroup();
|
||||
|
||||
// Click the save button and verify that the correct request is sent
|
||||
cohortsView.$('.action-save').click();
|
||||
AjaxHelpers.expectJsonRequest(
|
||||
requests, 'PATCH', '/mock_service/cohorts/1',
|
||||
{
|
||||
name: 'Cat Lovers',
|
||||
group_id: null
|
||||
}
|
||||
);
|
||||
AjaxHelpers.respondWithJson(
|
||||
requests,
|
||||
createMockCohort('Cat Lovers', 1, catLoversInitialCount, 0, 0)
|
||||
);
|
||||
verifyMessage('Saved cohort group.', 'confirmation');
|
||||
});
|
||||
|
||||
it("shows a message when the selected content group does not exist", function () {
|
||||
createCohortsView(this, {
|
||||
cohorts: [
|
||||
{id: 1, name: 'Cat Lovers', group_id: 999}
|
||||
],
|
||||
selectCohort: 1
|
||||
});
|
||||
cohortsView.$('.tab-settings a').click();
|
||||
expect(cohortsView.$('.copy-error').text().trim()).toBe(
|
||||
'The selected content group has been deleted, you may wish to reassign this cohort group.'
|
||||
);
|
||||
});
|
||||
|
||||
it("shows an error when the save fails", function () {
|
||||
createCohortsView(this, {selectCohort: 1});
|
||||
cohortsView.$('.tab-settings a').click();
|
||||
cohortsView.$('.action-save').click();
|
||||
AjaxHelpers.respondWithError(requests);
|
||||
verifyMessage(
|
||||
'We\'ve encountered an error. Please refresh your browser and then try again.',
|
||||
'error'
|
||||
);
|
||||
});
|
||||
|
||||
it("shows an error message when no content groups are specified", function () {
|
||||
createCohortsView(this, {selectCohort: 1, contentGroups: []});
|
||||
cohortsView.$('.tab-settings a').click();
|
||||
expect(
|
||||
cohortsView.$('.msg-inline').text().trim(),
|
||||
'You haven\'t configured any content groups yet. You need to create a content group ' +
|
||||
'before you can create assignments.'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
.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-manage-group-header {
|
||||
padding: 0;
|
||||
border-bottom: 0;
|
||||
|
||||
.cohort-management-group-setup {
|
||||
padding: $baseline;
|
||||
|
||||
.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 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
@@ -1,26 +0,0 @@
|
||||
<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>
|
||||
@@ -1,63 +1,72 @@
|
||||
<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>
|
||||
</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">
|
||||
|
||||
<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="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>
|
||||
<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>
|
||||
</header>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<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">
|
||||
|
||||
<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="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>
|
||||
</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="cohort-management-details tab-content tab-content-settings is-hidden">
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<% 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>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<%! 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>
|
||||
|
||||
Reference in New Issue
Block a user