diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5266efaaed8..ae4bcaae5d1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,9 @@ Unreleased ~~~~~~~~~~ * Add simple history to proctored exam attempt, writing both old and new model for now. Includes admin view. +[3.22.1] - 2021-08-02 +* Add edit button to grouped allowances, which allows instructors to edit the value of a single allowance. + [3.22.0] - 2021-07-26 ~~~~~~~~~~~~~~~~~~~~~ * If verified name functionality is enabled through the "name_affirmation" runtime service, diff --git a/edx_proctoring/__init__.py b/edx_proctoring/__init__.py index cb14a356941..87fee2acddb 100644 --- a/edx_proctoring/__init__.py +++ b/edx_proctoring/__init__.py @@ -3,6 +3,6 @@ """ # Be sure to update the version number in edx_proctoring/package.json -__version__ = '3.22.0' +__version__ = '3.22.1' default_app_config = 'edx_proctoring.apps.EdxProctoringConfig' # pylint: disable=invalid-name diff --git a/edx_proctoring/settings/common.py b/edx_proctoring/settings/common.py index 80841654025..c7c41c1ede5 100644 --- a/edx_proctoring/settings/common.py +++ b/edx_proctoring/settings/common.py @@ -28,6 +28,7 @@ def plugin_settings(settings): 'proctoring/js/views/proctored_exam_add_bulk_allowance_view.js', 'proctoring/js/views/proctored_exam_allowance_view.js', 'proctoring/js/views/proctored_exam_attempt_view.js', + 'proctoring/js/views/proctored_exam_edit_allowance_view.js', 'proctoring/js/views/proctored_exam_onboarding_view.js', 'proctoring/js/views/proctored_exam_view.js', 'proctoring/js/views/proctored_exam_info.js', diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_bulk_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_bulk_allowance_view.js index cdd6daf52c8..110bb7a8fa6 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_bulk_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_bulk_allowance_view.js @@ -236,9 +236,9 @@ edx = edx || {}; }, updateAllowanceLabels: function(selectedAllowanceType) { if (selectedAllowanceType === 'additional_time_granted') { - $('#allowance_value_label').text(gettext('Input Additional Minutes as a Positive Number')); + $('#allowance_value_label').text(gettext('Add Time(Minutes)')); } else if (selectedAllowanceType === 'time_multiplier') { - $('#allowance_value_label').text(gettext('Input Multiplier as a Number Greater Than 1')); + $('#allowance_value_label').text(gettext('Add Multiplier as a Number Greater Than 1')); } else { $('#allowance_value_label').text(gettext('Add Policy Exception')); } diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js index 73be7d293c4..daa3e1da3f5 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js @@ -44,7 +44,8 @@ edx = edx || {}; events: { 'click #add-allowance': 'showAddModal', 'click .remove_allowance': 'removeAllowance', - 'click .accordion-trigger': 'toggleAllowanceAccordion' + 'click .accordion-trigger': 'toggleAllowanceAccordion', + 'click .edit_allowance': 'editAllowance' }, getCSRFToken: function() { var cookieValue = null; @@ -185,6 +186,29 @@ edx = edx || {}; event.stopPropagation(); event.preventDefault(); }, + editAllowance: function(event) { + var $element = $(event.currentTarget); + var userName = $element.data('user-name'); + var examID = $element.data('exam-id'); + var examName = $element.data('exam-name'); + var key = $element.data('key-name'); + var keyName = $element.data('key-value'); + var self = this; + self.proctoredExamCollection.fetch({ + success: function() { + // eslint-disable-next-line no-new + new edx.instructor_dashboard.proctoring.EditAllowanceView({ + course_id: self.course_id, + selected_exam_ID: examID, + selected_exam_name: examName, + proctored_exam_allowance_view: self, + selected_user: userName, + allowance_type: key, + allowance_type_name: keyName + }); + } + }); + }, toggleAllowanceAccordion: function(event) { // based on code from openedx/features/course_experience/static/course_experience/js/CourseOutline.js // but modified to better fit this feature's needs @@ -193,16 +217,16 @@ edx = edx || {}; if (accordionRow.classList.contains('accordion-trigger')) { isExpanded = accordionRow.getAttribute('aria-expanded') === 'true'; if (!isExpanded) { - $toggleChevron = $(accordionRow).find('.fa-chevron-right'); + $toggleChevron = $(accordionRow).find('.fa-chevron-down'); $contentPanel = $('#' + accordionRow.innerText.trim()); $contentPanel.show(); - $toggleChevron.addClass('fa-rotate-90'); + $toggleChevron.addClass('fa-rotate-180'); accordionRow.setAttribute('aria-expanded', 'true'); } else { - $toggleChevron = $(accordionRow).find('.fa-chevron-right'); + $toggleChevron = $(accordionRow).find('.fa-chevron-down'); $contentPanel = $('#' + accordionRow.innerText.trim()); $contentPanel.hide(); - $toggleChevron.removeClass('fa-rotate-90'); + $toggleChevron.removeClass('fa-rotate-180'); accordionRow.setAttribute('aria-expanded', 'false'); } } diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_edit_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_edit_allowance_view.js new file mode 100644 index 00000000000..ffa758e5f89 --- /dev/null +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_edit_allowance_view.js @@ -0,0 +1,164 @@ +edx = edx || {}; + +(function(Backbone, $, _, gettext) { + 'use strict'; + + edx.instructor_dashboard = edx.instructor_dashboard || {}; + edx.instructor_dashboard.proctoring = edx.instructor_dashboard.proctoring || {}; + + edx.instructor_dashboard.proctoring.EditAllowanceView = Backbone.ModalView.extend({ + name: 'EditAllowanceView', + template: null, + template_url: '/static/proctoring/templates/edit-allowance.underscore', + initialize: function(options) { + this.selected_exam_ID = options.selected_exam_ID; + this.selected_exam_name = options.selected_exam_name; + this.proctored_exam_allowance_view = options.proctored_exam_allowance_view; + this.course_id = options.course_id; + this.selected_user = options.selected_user; + this.allowance_type = options.allowance_type; + this.allowance_type_name = options.allowance_type_name; + this.model = new edx.instructor_dashboard.proctoring.ProctoredExamBulkAllowanceModel(); + _.bindAll(this, 'render'); + this.loadTemplateData(); + // Backbone.Validation.bind( this, {valid:this.hideError, invalid:this.showError}); + }, + events: { + 'submit form': 'editAllowance' + }, + loadTemplateData: function() { + var self = this; + $.ajax({url: self.template_url, dataType: 'html'}) + .done(function(templateData) { + self.template = _.template(templateData); + self.render(); + self.showModal(); + self.updateCss(); + }); + }, + updateCss: function() { + var $el = $(this.el); + $el.find('.modal-header').css({ + color: '#1580b0', + 'font-size': '20px', + 'font-weight': '600', + 'line-height': 'normal', + padding: '10px 15px', + 'border-bottom': '1px solid #ccc' + }); + $el.find('form').css({ + padding: '15px' + }); + $el.find('form table.compact td').css({ + 'vertical-align': 'middle', + padding: '4px 8px' + }); + $el.find('form label').css({ + display: 'block', + 'font-size': '14px', + margin: 0, + cursor: 'default' + }); + $el.find('form input[type="text"]').css({ + height: '26px', + padding: '1px 8px 2px', + 'font-size': '14px', + width: '100%' + }); + $el.find('form input[type="submit"]').css({ + 'margin-top': '10px', + float: 'right' + }); + $el.find('.error-message').css({ + color: '#ff0000', + 'line-height': 'normal', + 'font-size': '14px' + }); + $el.find('.error-response').css({ + color: '#ff0000', + 'line-height': 'normal', + 'font-size': '14px', + padding: '0px 10px 5px 7px' + }); + }, + getAllowanceValue: function() { + return $('#allowance_value').val(); + }, + hideError: function(view, attr) { + var $element = view.$form[attr]; + + $element.removeClass('error'); + $element.parent().find('.error-message').empty(); + }, + showError: function(view, attr, errorMessage) { + var $element = view.$form[attr]; + var $errorMessage; + + $element.addClass('error'); + $errorMessage = $element.parent().find('.error-message'); + if ($errorMessage.length === 0) { + $errorMessage = $("
"); + $element.parent().append($errorMessage); + } + + $errorMessage.empty().append(errorMessage); + this.updateCss(); + }, + editAllowance: function(event) { + var $errorResponse, formHasErrors, allowanceValue; + var self = this; + event.preventDefault(); + $errorResponse = $('.error-response'); + $errorResponse.html(); + allowanceValue = this.getAllowanceValue(); + formHasErrors = false; + + if (allowanceValue === '') { + formHasErrors = true; + self.showError(self, 'allowance_value', gettext('Required field')); + } else { + self.hideError(self, 'allowance_value'); + } + + if (!formHasErrors) { + self.model.fetch({ + headers: { + 'X-CSRFToken': self.proctored_exam_allowance_view.getCSRFToken() + }, + type: 'PUT', + data: { + exam_ids: this.selected_exam_ID, + user_ids: this.selected_user, + allowance_type: this.allowance_type, + value: allowanceValue + }, + success: function() { + // fetch the allowances again. + $errorResponse.html(); + self.proctored_exam_allowance_view.collection.url = + self.proctored_exam_allowance_view.initial_url + self.course_id + '/allowance'; + self.proctored_exam_allowance_view.hydrate(); + self.hideModal(); + }, + error: function(unused, response) { + var data = $.parseJSON(response.responseText); + $errorResponse.html(gettext(data.detail)); + } + }); + } + }, + render: function() { + $(this.el).html(this.template({ + selected_user: this.selected_user, + selected_exam_name: this.selected_exam_name, + allowance_type: this.allowance_type, + allowance_type_name: this.allowance_type_name + })); + + this.$form = { + allowance_value: this.$('#allowance_value') + }; + return this; + } + }); +}).call(this, Backbone, $, _, gettext); diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js index ab51a804140..1e3f500c77d 100644 --- a/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js +++ b/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js @@ -88,7 +88,7 @@ describe('ProctoredExamAAllowanceView', function() { // from http://www.howtocreate.co.uk/tutorials/jsexamples/syntax/prepareInline.html // eslint-disable-next-line max-len - html = '
<%- gettext("Add a New Allowance") %>
\n
\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n \n
\n \n
\n \n
\n \n
\n \n \n
\n
\n
\n \n
\n \n
\n \n
\n \n
\n \n
\n'; + html = '
<%- gettext("Add a New Allowance") %>
\n
\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n \n
\n \n
\n \n
\n \n
\n \n \n
\n
\n
\n \n
\n \n
\n \n
\n \n
\n \n
\n\n'; allowancesHtml = '' + '<%- gettext("Allowances") %>' + diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_bulk_allowance_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_bulk_allowance_spec.js index 4d2f217cdcb..f71117d669e 100644 --- a/edx_proctoring/static/proctoring/spec/proctored_exam_bulk_allowance_spec.js +++ b/edx_proctoring/static/proctoring/spec/proctored_exam_bulk_allowance_spec.js @@ -29,7 +29,7 @@ describe('ProctoredExamAllowanceView', function() { beforeEach(function() { // eslint-disable-next-line max-len - html = ' <%- gettext("Allowances") %>\n \n + <%- gettext("Add Allowance") %>\n \n\n<% var is_allowances = proctored_exam_allowances.length !== 0 %>\n<% if (is_allowances) { %>\n\n
\n
\n <% _.each(proctored_exam_allowances, function(student){ %>\n \n \n \n \n \n \n \n \n \n \n <% _.each(student, function(proctored_exam_allowance){ %>\n <% var key = proctored_exam_allowance.key; %>\n <% for (i = 0; i < allowance_types.length; i += 1) { %>\n <% if (key === allowance_types[i][0]) { %>\n <% proctored_exam_allowance.key_display_name = allowance_types[i][1]; %>\n <% break; %>\n <% }} %>\n <% if (!proctored_exam_allowance.key_display_name) { %>\n <% proctored_exam_allowance.key_display_name = key;} %>\n \n \n \n <% }else{ %>\n \n \n <% } %>\n \n \n \n \n <% }); %>\n \n \n <% }); %>\n
\n
\n<% } %>\n'; + html = ' <%- gettext("Allowances") %>\n \n + <%- gettext("Add Allowance") %>\n \n\n<% var is_allowances = proctored_exam_allowances.length !== 0 %>\n<% if (is_allowances) { %>\n\n
\n
\n <% _.each(proctored_exam_allowances, function(student){ %>\n \n \n \n \n \n \n \n \n \n \n <% _.each(student, function(proctored_exam_allowance){ %>\n <% var key = proctored_exam_allowance.key; %>\n <% for (i = 0; i < allowance_types.length; i += 1) { %>\n <% if (key === allowance_types[i][0]) { %>\n <% proctored_exam_allowance.key_display_name = allowance_types[i][1]; %>\n <% break; %>\n <% }} %>\n <% if (!proctored_exam_allowance.key_display_name) { %>\n <% proctored_exam_allowance.key_display_name = key;} %>\n \n \n \n <% }else{ %>\n \n \n <% } %>\n \n \n \n \n <% }); %>\n \n \n <% }); %>\n
\n
\n<% } %>\n'; this.server = sinon.fakeServer.create(); this.server.autoRespond = true; setFixtures('
- + diff --git a/edx_proctoring/static/proctoring/templates/course_grouped_allowances.underscore b/edx_proctoring/static/proctoring/templates/course_grouped_allowances.underscore index d0333ba9cb0..a58bfb84eac 100644 --- a/edx_proctoring/static/proctoring/templates/course_grouped_allowances.underscore +++ b/edx_proctoring/static/proctoring/templates/course_grouped_allowances.underscore @@ -10,7 +10,7 @@
<% _.each(proctored_exam_allowances, function(student){ %> @@ -49,10 +49,16 @@ <% }); %> diff --git a/edx_proctoring/static/proctoring/templates/edit-allowance.underscore b/edx_proctoring/static/proctoring/templates/edit-allowance.underscore new file mode 100644 index 00000000000..d1ad44e5443 --- /dev/null +++ b/edx_proctoring/static/proctoring/templates/edit-allowance.underscore @@ -0,0 +1,52 @@ + + +

+

+ + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ <% if (allowance_type == 'additional_time_granted') { %> + + <% }else{ %> + + <% } %> + + +
+ +
+ diff --git a/package.json b/package.json index e618cb6e599..1084458ef08 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@edx/edx-proctoring", "//": "Note that the version format is slightly different than that of the Python version when using prereleases.", - "version": "3.22.0", + "version": "3.22.1", "main": "edx_proctoring/static/index.js", "scripts": { "test": "gulp test"