Commit faf796b5 by Adam

Merge pull request #1125 from edx/adam/remove-instr-dash-buttons

disable buttons for legacy and beta instr dash
parents a617988c e3758461
...@@ -5,6 +5,7 @@ These are notable changes in edx-platform. This is a rolling list of changes, ...@@ -5,6 +5,7 @@ These are notable changes in edx-platform. This is a rolling list of changes,
in roughly chronological order, most recent first. Add your entries at or near in roughly chronological order, most recent first. Add your entries at or near
the top. Include a label indicating the component affected. the top. Include a label indicating the component affected.
LMS: Disable data download buttons on the instructor dashboard for large courses
LMS: Refactor and clean student dashboard templates. LMS: Refactor and clean student dashboard templates.
......
...@@ -9,6 +9,7 @@ from mitxmako.shortcuts import render_to_response ...@@ -9,6 +9,7 @@ from mitxmako.shortcuts import render_to_response
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils.html import escape from django.utils.html import escape
from django.http import Http404 from django.http import Http404
from django.conf import settings
from courseware.access import has_access from courseware.access import has_access
from courseware.courses import get_course_by_id from courseware.courses import get_course_by_id
...@@ -45,10 +46,19 @@ def instructor_dashboard_2(request, course_id): ...@@ -45,10 +46,19 @@ def instructor_dashboard_2(request, course_id):
_section_analytics(course_id), _section_analytics(course_id),
] ]
enrollment_count = sections[0]['enrollment_count']
disable_buttons = False
max_enrollment_for_buttons = settings.MITX_FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS")
if max_enrollment_for_buttons is not None:
disable_buttons = enrollment_count > max_enrollment_for_buttons
context = { context = {
'course': course, 'course': course,
'old_dashboard_url': reverse('instructor_dashboard', kwargs={'course_id': course_id}), 'old_dashboard_url': reverse('instructor_dashboard', kwargs={'course_id': course_id}),
'sections': sections, 'sections': sections,
'disable_buttons': disable_buttons,
} }
return render_to_response('instructor/instructor_dashboard_2/instructor_dashboard_2.html', context) return render_to_response('instructor/instructor_dashboard_2/instructor_dashboard_2.html', context)
......
...@@ -105,12 +105,15 @@ def instructor_dashboard(request, course_id): ...@@ -105,12 +105,15 @@ def instructor_dashboard(request, course_id):
else: else:
idash_mode = request.session.get('idash_mode', 'Grades') idash_mode = request.session.get('idash_mode', 'Grades')
enrollment_number = CourseEnrollment.objects.filter(course_id=course_id, is_active=1).count()
# assemble some course statistics for output to instructor # assemble some course statistics for output to instructor
def get_course_stats_table(): def get_course_stats_table():
datatable = {'header': ['Statistic', 'Value'], datatable = {
'title': _u('Course Statistics At A Glance'), 'header': ['Statistic', 'Value'],
} 'title': _u('Course Statistics At A Glance'),
data = [['# Enrolled', CourseEnrollment.objects.filter(course_id=course_id, is_active=1).count()]] }
data = [['# Enrolled', enrollment_number]]
data += [['Date', timezone.now().isoformat()]] data += [['Date', timezone.now().isoformat()]]
data += compute_course_stats(course).items() data += compute_course_stats(course).items()
if request.user.is_staff: if request.user.is_staff:
...@@ -832,35 +835,43 @@ def instructor_dashboard(request, course_id): ...@@ -832,35 +835,43 @@ def instructor_dashboard(request, course_id):
if not datatable: if not datatable:
course_stats = get_course_stats_table() course_stats = get_course_stats_table()
# disable buttons for large courses
disable_buttons = False
max_enrollment_for_buttons = settings.MITX_FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS")
if max_enrollment_for_buttons is not None:
disable_buttons = enrollment_number > max_enrollment_for_buttons
#---------------------------------------- #----------------------------------------
# context for rendering # context for rendering
context = {'course': course, context = {
'staff_access': True, 'course': course,
'admin_access': request.user.is_staff, 'staff_access': True,
'instructor_access': instructor_access, 'admin_access': request.user.is_staff,
'forum_admin_access': forum_admin_access, 'instructor_access': instructor_access,
'datatable': datatable, 'forum_admin_access': forum_admin_access,
'course_stats': course_stats, 'datatable': datatable,
'msg': msg, 'course_stats': course_stats,
'modeflag': {idash_mode: 'selectedmode'}, 'msg': msg,
'studio_url': studio_url, 'modeflag': {idash_mode: 'selectedmode'},
'studio_url': studio_url,
'to_option': email_to_option, # email
'subject': email_subject, # email 'to_option': email_to_option, # email
'editor': email_editor, # email 'subject': email_subject, # email
'email_msg': email_msg, # email 'editor': email_editor, # email
'show_email_tab': show_email_tab, # email 'email_msg': email_msg, # email
'show_email_tab': show_email_tab, # email
'problems': problems, # psychometrics
'plots': plots, # psychometrics 'problems': problems, # psychometrics
'course_errors': modulestore().get_item_errors(course.location), 'plots': plots, # psychometrics
'instructor_tasks': instructor_tasks, 'course_errors': modulestore().get_item_errors(course.location),
'offline_grade_log': offline_grades_available(course_id), 'instructor_tasks': instructor_tasks,
'cohorts_ajax_url': reverse('cohorts', kwargs={'course_id': course_id}), 'offline_grade_log': offline_grades_available(course_id),
'cohorts_ajax_url': reverse('cohorts', kwargs={'course_id': course_id}),
'analytics_results': analytics_results,
} 'analytics_results': analytics_results,
'disable_buttons': disable_buttons
}
if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_BETA_DASHBOARD'): if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_BETA_DASHBOARD'):
context['beta_dashboard_url'] = reverse('instructor_dashboard_2', kwargs={'course_id': course_id}) context['beta_dashboard_url'] = reverse('instructor_dashboard_2', kwargs={'course_id': course_id})
......
...@@ -182,6 +182,10 @@ MITX_FEATURES = { ...@@ -182,6 +182,10 @@ MITX_FEATURES = {
# Automatically approve student identity verification attempts # Automatically approve student identity verification attempts
'AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING': False, 'AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING': False,
# Disable instructor dash buttons for downloading course data
# when enrollment exceeds this number
'MAX_ENROLLMENT_INSTR_BUTTONS': 200,
} }
# Used for A/B testing # Used for A/B testing
......
...@@ -219,6 +219,11 @@ $action-secondary-disabled-fg: $white; ...@@ -219,6 +219,11 @@ $action-secondary-disabled-fg: $white;
$header-graphic-super-color: $m-blue-d1; $header-graphic-super-color: $m-blue-d1;
$header-graphic-sub-color: $m-gray-d2; $header-graphic-sub-color: $m-gray-d2;
// State-based colors
$error-color: $error-red;
$warning-color: $m-pink;
$confirm-color: $m-green;
// ==================== // ====================
// MISC: visual horizontal rules // MISC: visual horizontal rules
......
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
} }
} }
// ====================
// system feedback - messages // system feedback - messages
.msg { .msg {
border-radius: 1px; border-radius: 1px;
...@@ -51,15 +53,51 @@ ...@@ -51,15 +53,51 @@
} }
} }
// TYPE: warning
.msg-warning {
border-top: 2px solid $warning-color;
background: tint($warning-color,95%);
.copy {
color: $warning-color;
}
}
// TYPE: confirm
.msg-confirm { .msg-confirm {
border-top: 2px solid green; border-top: 2px solid $confirm-color;
background: tint(green,90%); background: tint($confirm-color,95%);
.copy {
color: $confirm-color;
}
}
// TYPE: confirm
.msg-error {
border-top: 2px solid $error-color;
background: tint($error-color,95%);
.copy { .copy {
color: green; color: $error-color;
} }
} }
// ====================
// inline copy
.copy-confirm {
color: $confirm-color;
}
.copy-warning {
color: $warning-color;
}
.copy-error {
color: $error-color;
}
.list-advice { .list-advice {
list-style: none; list-style: none;
padding: 0; padding: 0;
......
...@@ -18,6 +18,77 @@ ...@@ -18,6 +18,77 @@
right: 15px; right: 15px;
font-size: 11pt; font-size: 11pt;
} }
// system feedback - messages
.msg {
border-radius: 1px;
padding: 10px 15px;
margin-bottom: 20px;
.copy {
font-weight: 600;
}
}
// TYPE: warning
.msg-warning {
border-top: 2px solid $warning-color;
background: tint($warning-color,95%);
.copy {
color: $warning-color;
}
}
// TYPE: confirm
.msg-confirm {
border-top: 2px solid $confirm-color;
background: tint($confirm-color,95%);
.copy {
color: $confirm-color;
}
}
// TYPE: confirm
.msg-error {
border-top: 2px solid $error-color;
background: tint($error-color,95%);
.copy {
color: $error-color;
}
}
// ====================
// inline copy
.copy-confirm {
color: $confirm-color;
}
.copy-warning {
color: $warning-color;
}
.copy-error {
color: $error-color;
}
.list-advice {
list-style: none;
padding: 0;
margin: 20px 0;
.item {
font-weight: 600;
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
}
}
} }
section.instructor-dashboard-content-2 { section.instructor-dashboard-content-2 {
......
...@@ -146,35 +146,59 @@ function goto( mode) ...@@ -146,35 +146,59 @@ function goto( mode)
%if modeflag.get('Grades'): %if modeflag.get('Grades'):
%if offline_grade_log: %if offline_grade_log:
<p><font color='orange'>Pre-computed grades ${offline_grade_log} available: Use? <p>
<input type='checkbox' name='use_offline_grades' value='${_("yes")}'></font> </p> <span class="copy-warning">Pre-computed grades ${offline_grade_log} available: Use?
<input type='checkbox' name='use_offline_grades' value='${_("yes")}'>
</span>
</p>
%endif %endif
<hr width="40%" style="align:left">
<h2>${_("Grade Downloads")}</h2>
% if disable_buttons:
<div class="msg msg-warning">
<div class="copy">
<p>
${_("Note: some of these buttons are known to time out for larger "
"courses. We have temporarily disabled those features for courses "
"with more than {max_enrollment} students. We are urgently working on "
"fixing this issue. Thank you for your patience as we continue "
"working to improve the platform!").format(
max_enrollment=settings.MITX_FEATURES['MAX_ENROLLMENT_INSTR_BUTTONS']
)}
</p>
</div>
</div>
% endif
<p> <p>
<a href="${reverse('gradebook', kwargs=dict(course_id=course.id))}">${_("Gradebook")}</a> <a href="${reverse('gradebook', kwargs=dict(course_id=course.id))}" class="${'is-disabled' if disable_buttons else ''}">${_("Gradebook")}</a>
</p> </p>
<p> <p>
<a href="${reverse('grade_summary', kwargs=dict(course_id=course.id))}">${_("Grade summary")}</a> <a href="${reverse('grade_summary', kwargs=dict(course_id=course.id))}" class="${'is-disabled' if disable_buttons else ''}">${_("Grade summary")}</a>
</p> </p>
<p> <p>
<input type="submit" name="action" value="Dump list of enrolled students"> <input type="submit" name="action" value="Dump list of enrolled students" class="${'is-disabled' if disable_buttons else ''}">
</p> </p>
<p> <p>
<input type="submit" name="action" value="Dump Grades for all students in this course"> <input type="submit" name="action" value="Dump Grades for all students in this course" class="${'is-disabled' if disable_buttons else ''}">
<input type="submit" name="action" value="Download CSV of all student grades for this course"> <input type="submit" name="action" value="Download CSV of all student grades for this course" class="${'is-disabled' if disable_buttons else ''}">
</p> </p>
<p> <p>
<input type="submit" name="action" value="Dump all RAW grades for all students in this course"> <input type="submit" name="action" value="Dump all RAW grades for all students in this course" class="${'is-disabled' if disable_buttons else ''}">
<input type="submit" name="action" value="Download CSV of all RAW grades"> <input type="submit" name="action" value="Download CSV of all RAW grades" class="${'is-disabled' if disable_buttons else ''}">
</p> </p>
<p> <p>
<input type="submit" name="action" value="Download CSV of answer distributions"> <input type="submit" name="action" value="Download CSV of answer distributions" class="${'is-disabled' if disable_buttons else ''}">
<input type="submit" name="action" value="Dump description of graded assignments configuration"> <input type="submit" name="action" value="Dump description of graded assignments configuration" class="${'is-disabled' if disable_buttons else ''}">
</p> </p>
<hr width="40%" style="align:left"> <hr width="40%" style="align:left">
...@@ -188,7 +212,7 @@ function goto( mode) ...@@ -188,7 +212,7 @@ function goto( mode)
<p>${_("The assignments defined for this course should match the ones stored in the gradebook, for this to work properly!")}</p> <p>${_("The assignments defined for this course should match the ones stored in the gradebook, for this to work properly!")}</p>
<ul> <ul>
<li>${_("Gradebook name:")} <font color="green">${rg.get('name','None defined!')}</font> <li>${_("Gradebook name:")} <span class="copy-confirm">${rg.get('name','None defined!')}</span>
<br/> <br/>
<br/> <br/>
<input type="submit" name="action" value="List assignments available in remote gradebook"> <input type="submit" name="action" value="List assignments available in remote gradebook">
...@@ -369,9 +393,26 @@ function goto( mode) ...@@ -369,9 +393,26 @@ function goto( mode)
%if modeflag.get('Enrollment'): %if modeflag.get('Enrollment'):
<hr width="40%" style="align:left"> <hr width="40%" style="align:left">
<p> <h2>${_("Enrollment Data")}</h2>
<input type="submit" name="action" value="List enrolled students"> % if disable_buttons:
<input type="submit" name="action" value="List students who may enroll but may not have yet signed up">
<div class="msg msg-warning">
<div class="copy">
<p>
${_("Note: some of these buttons are known to time out for larger "
"courses. We have temporarily disabled those features for courses "
"with more than {max_enrollment} students. We are urgently working on "
"fixing this issue. Thank you for your patience as we continue "
"working to improve the platform!").format(
max_enrollment=settings.MITX_FEATURES['MAX_ENROLLMENT_INSTR_BUTTONS']
)}
</p>
</div>
</div>
% endif
<input type="submit" name="action" value="List enrolled students" class="${'is-disabled' if disable_buttons else ''}">
<input type="submit" name="action" value="List students who may enroll but may not have yet signed up" class="${'is-disabled' if disable_buttons else ''}">
<hr width="40%" style="align:left"> <hr width="40%" style="align:left">
%if settings.MITX_FEATURES.get('REMOTE_GRADEBOOK_URL','') and instructor_access: %if settings.MITX_FEATURES.get('REMOTE_GRADEBOOK_URL','') and instructor_access:
...@@ -382,7 +423,7 @@ function goto( mode) ...@@ -382,7 +423,7 @@ function goto( mode)
<p>${_("Pull enrollment from remote gradebook")}</p> <p>${_("Pull enrollment from remote gradebook")}</p>
<ul> <ul>
<li>${_("Gradebook name:")} <font color="green">${rg.get('name','None defined!')}</font> <li>${_("Gradebook name:")} <span class="copy-confirm">${rg.get('name','None defined!')}</span>
<li>${_("Section:")} <input type="text" name="gradebook_section" size=40 value="${rg.get('section','')}"></li> <li>${_("Section:")} <input type="text" name="gradebook_section" size=40 value="${rg.get('section','')}"></li>
</ul> </ul>
<input type="submit" name="action" value="List sections available in remote gradebook"> <input type="submit" name="action" value="List sections available in remote gradebook">
...@@ -392,7 +433,7 @@ function goto( mode) ...@@ -392,7 +433,7 @@ function goto( mode)
<hr width="40%" style="align:left"> <hr width="40%" style="align:left">
%endif %endif
<h2>${_("Batch Enrollment")}</h2>
<p>${_("Enroll or un-enroll one or many students: enter emails, separated by new lines or commas;")}</p> <p>${_("Enroll or un-enroll one or many students: enter emails, separated by new lines or commas;")}</p>
<textarea rows="6" cols="70" name="multiple_students"></textarea> <textarea rows="6" cols="70" name="multiple_students"></textarea>
<p> <p>
......
<%! from django.utils.translation import ugettext as _ %> <%! from django.utils.translation import ugettext as _ %>
<%page args="section_data"/> <%page args="section_data"/>
<input type="button" name="list-profiles" value="${_("List enrolled students with profile information")}" data-endpoint="${ section_data['get_students_features_url'] }" >
<input type="button" name="list-profiles" value="CSV" data-csv="true" class="csv" data-endpoint="${ section_data['get_students_features_url'] }" > <h2>${_("Data Download")}</h2>
% if disable_buttons:
<div class="msg msg-warning">
<div class="copy">
<p>
${_("Note: some of these buttons are known to time out for larger "
"courses. We have temporarily disabled those features for courses "
"with more than {max_enrollment} students. We are urgently working on "
"fixing this issue. Thank you for your patience as we continue "
"working to improve the platform!").format(
max_enrollment=settings.MITX_FEATURES['MAX_ENROLLMENT_INSTR_BUTTONS']
)}
</p>
</div>
</div>
<br>
% endif
<input type="button" name="list-profiles" value="${_("List enrolled students with profile information")}" data-endpoint="${ section_data['get_students_features_url'] }" class="${'is-disabled' if disable_buttons else ''}">
<input type="button" name="list-profiles" value="CSV" data-csv="true" class="csv ${'is-disabled' if disable_buttons else ''}" data-endpoint="${ section_data['get_students_features_url'] }" >
<br> <br>
## <input type="button" name="list-grades" value="Student grades"> ## <input type="button" name="list-grades" value="Student grades">
## <input type="button" name="list-profiles" value="CSV" data-csv="true" class="csv"> ## <input type="button" name="list-profiles" value="CSV" data-csv="true" class="csv">
...@@ -10,8 +29,7 @@ ...@@ -10,8 +29,7 @@
## <input type="button" name="list-answer-distributions" value="Answer distributions (x students got y points)"> ## <input type="button" name="list-answer-distributions" value="Answer distributions (x students got y points)">
## <br> ## <br>
<input type="button" name="dump-gradeconf" value="${_("Grading Configuration")}" data-endpoint="${ section_data['get_grading_config_url'] }"> <input type="button" name="dump-gradeconf" value="${_("Grading Configuration")}" data-endpoint="${ section_data['get_grading_config_url'] }">
<input type="button" name="list-anon-ids" value="${_("Get Student Anonymized IDs CSV")}" data-csv="true" class="csv" data-endpoint="${ section_data['get_anon_ids_url'] }"> <input type="button" name="list-anon-ids" value="${_("Get Student Anonymized IDs CSV")}" data-csv="true" class="csv" data-endpoint="${ section_data['get_anon_ids_url'] }" class="${'is-disabled' if disable_buttons else ''}">
<div class="data-display"> <div class="data-display">
<div class="data-display-text"></div> <div class="data-display-text"></div>
......
...@@ -79,7 +79,7 @@ ...@@ -79,7 +79,7 @@
%if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS') and section_data['access']['instructor']: %if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS') and section_data['access']['instructor']:
<div class="course-specific-container action-type-container"> <div class="course-specific-container action-type-container">
<H2>${_('Course-specific grade adjustment')}</h2> <h2>${_('Course-specific grade adjustment')}</h2>
<div class="request-response-error"></div> <div class="request-response-error"></div>
<p> <p>
......
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