Style cleanups: legacy instructor dashboard
This commit is contained in:
@@ -3,7 +3,6 @@ Instructor Views
|
||||
"""
|
||||
## NOTE: This is the code for the legacy instructor dashboard
|
||||
## We are no longer supporting this file or accepting changes into it.
|
||||
# pylint: skip-file
|
||||
from contextlib import contextmanager
|
||||
import csv
|
||||
import json
|
||||
@@ -27,38 +26,22 @@ from django.core.urlresolvers import reverse
|
||||
from django.core.mail import send_mail
|
||||
from django.utils import timezone
|
||||
|
||||
from xmodule_modifiers import wrap_xblock, request_token
|
||||
import xmodule.graders as xmgraders
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
from xmodule.html_module import HtmlDescriptor
|
||||
from opaque_keys import InvalidKeyError
|
||||
from lms.lib.xblock.runtime import quote_slashes
|
||||
|
||||
from submissions import api as sub_api # installed from the edx-submissions repository
|
||||
|
||||
from bulk_email.models import CourseEmail, CourseAuthorization
|
||||
from courseware import grades
|
||||
from courseware.access import has_access
|
||||
from courseware.courses import get_course_with_access, get_cms_course_link
|
||||
from student.roles import (
|
||||
CourseStaffRole, CourseInstructorRole, CourseBetaTesterRole, GlobalStaff
|
||||
)
|
||||
from courseware.models import StudentModule
|
||||
from django_comment_common.models import (
|
||||
Role, FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_MODERATOR, FORUM_ROLE_COMMUNITY_TA
|
||||
)
|
||||
from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR
|
||||
from django_comment_client.utils import has_forum_access
|
||||
from instructor.offline_gradecalc import student_grades, offline_grades_available
|
||||
from instructor.views.tools import strip_if_string, bulk_email_is_enabled_for_course, add_block_ids
|
||||
from instructor_task.api import (
|
||||
get_running_instructor_tasks,
|
||||
get_instructor_task_history,
|
||||
submit_rescore_problem_for_all_students,
|
||||
submit_rescore_problem_for_student,
|
||||
submit_reset_problem_attempts_for_all_students
|
||||
)
|
||||
from instructor_task.views import get_task_completion_info
|
||||
from edxmako.shortcuts import render_to_response, render_to_string
|
||||
@@ -67,12 +50,8 @@ from psychometrics import psychoanalyze
|
||||
from student.models import (
|
||||
CourseEnrollment,
|
||||
CourseEnrollmentAllowed,
|
||||
unique_id_for_user,
|
||||
anonymous_id_for_user
|
||||
)
|
||||
import track.views
|
||||
from xblock.field_data import DictFieldData
|
||||
from xblock.fields import ScopeIds
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from microsite_configuration import microsite
|
||||
@@ -107,10 +86,6 @@ def instructor_dashboard(request, course_id):
|
||||
forum_admin_access = has_forum_access(request.user, course_key, FORUM_ROLE_ADMINISTRATOR)
|
||||
|
||||
msg = ''
|
||||
email_msg = ''
|
||||
email_to_option = None
|
||||
email_subject = None
|
||||
html_message = ''
|
||||
show_email_tab = False
|
||||
problems = []
|
||||
plots = []
|
||||
@@ -171,23 +146,6 @@ def instructor_dashboard(request, course_id):
|
||||
writer.writerow(encoded_row)
|
||||
return response
|
||||
|
||||
def get_student_from_identifier(unique_student_identifier):
|
||||
"""Gets a student object using either an email address or username"""
|
||||
unique_student_identifier = strip_if_string(unique_student_identifier)
|
||||
msg = ""
|
||||
try:
|
||||
if "@" in unique_student_identifier:
|
||||
student = User.objects.get(email=unique_student_identifier)
|
||||
else:
|
||||
student = User.objects.get(username=unique_student_identifier)
|
||||
msg += _("Found a single student. ")
|
||||
except User.DoesNotExist:
|
||||
student = None
|
||||
msg += "<font color='red'>{text}</font>".format(
|
||||
text=_("Couldn't find student with that email or username.")
|
||||
)
|
||||
return msg, student
|
||||
|
||||
# process actions from form POST
|
||||
action = request.POST.get('action', '')
|
||||
use_offline = request.POST.get('use_offline_grades', False)
|
||||
@@ -266,8 +224,9 @@ def instructor_dashboard(request, course_id):
|
||||
datatable = {'header': ['Student email', 'Match?']}
|
||||
rg_students = [x['email'] for x in rg_stud_data['retdata']]
|
||||
|
||||
def domatch(x):
|
||||
return 'yes' if x.email in rg_students else 'No'
|
||||
def domatch(student):
|
||||
"""Returns 'yes' if student is pressent in the remote gradebook student list, else returns 'No'"""
|
||||
return 'yes' if student.email in rg_students else 'No'
|
||||
datatable['data'] = [[x.email, domatch(x)] for x in stud_data['students']]
|
||||
datatable['title'] = action
|
||||
|
||||
@@ -429,7 +388,7 @@ def instructor_dashboard(request, course_id):
|
||||
analytics_results = {}
|
||||
|
||||
if idash_mode == 'Analytics':
|
||||
DASHBOARD_ANALYTICS = [
|
||||
dashboard_analytics = [
|
||||
# "StudentsAttemptedProblems", # num students who tried given problem
|
||||
"StudentsDailyActivity", # active students by day
|
||||
"StudentsDropoffPerDay", # active students dropoff by day
|
||||
@@ -438,7 +397,7 @@ def instructor_dashboard(request, course_id):
|
||||
"ProblemGradeDistribution", # foreach problem, grade distribution
|
||||
]
|
||||
|
||||
for analytic_name in DASHBOARD_ANALYTICS:
|
||||
for analytic_name in dashboard_analytics:
|
||||
analytics_results[analytic_name] = get_analytics_result(analytic_name)
|
||||
|
||||
#----------------------------------------
|
||||
@@ -522,31 +481,31 @@ def _do_remote_gradebook(user, course, action, args=None, files=None):
|
||||
'''
|
||||
Perform remote gradebook action. Returns msg, datatable.
|
||||
'''
|
||||
rg = course.remote_gradebook
|
||||
if not rg:
|
||||
rgb = course.remote_gradebook
|
||||
if not rgb:
|
||||
msg = _("No remote gradebook defined in course metadata")
|
||||
return msg, {}
|
||||
|
||||
rgurl = settings.FEATURES.get('REMOTE_GRADEBOOK_URL', '')
|
||||
if not rgurl:
|
||||
rgburl = settings.FEATURES.get('REMOTE_GRADEBOOK_URL', '')
|
||||
if not rgburl:
|
||||
msg = _("No remote gradebook url defined in settings.FEATURES")
|
||||
return msg, {}
|
||||
|
||||
rgname = rg.get('name', '')
|
||||
if not rgname:
|
||||
rgbname = rgb.get('name', '')
|
||||
if not rgbname:
|
||||
msg = _("No gradebook name defined in course remote_gradebook metadata")
|
||||
return msg, {}
|
||||
|
||||
if args is None:
|
||||
args = {}
|
||||
data = dict(submit=action, gradebook=rgname, user=user.email)
|
||||
data = dict(submit=action, gradebook=rgbname, user=user.email)
|
||||
data.update(args)
|
||||
|
||||
try:
|
||||
resp = requests.post(rgurl, data=data, verify=False, files=files)
|
||||
resp = requests.post(rgburl, data=data, verify=False, files=files)
|
||||
retdict = json.loads(resp.content)
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
msg = _("Failed to communicate with gradebook server at {url}").format(url=rgurl) + "<br/>"
|
||||
msg = _("Failed to communicate with gradebook server at {url}").format(url=rgburl) + "<br/>"
|
||||
msg += _("Error: {err}").format(err=err)
|
||||
msg += "<br/>resp={resp}".format(resp=resp.content)
|
||||
msg += "<br/>data={data}".format(data=data)
|
||||
@@ -565,6 +524,7 @@ def _do_remote_gradebook(user, course, action, args=None, files=None):
|
||||
|
||||
return msg, datatable
|
||||
|
||||
|
||||
def _role_members_table(role, title, course_key):
|
||||
"""
|
||||
Return a data table of usernames and names of users in group_name.
|
||||
@@ -784,7 +744,7 @@ def get_student_grade_summary_data(request, course, get_grades=True, get_raw_sco
|
||||
datarow = [student.id, student.username, student.profile.name, student.email]
|
||||
try:
|
||||
datarow.append(student.externalauthmap.external_email)
|
||||
except: # ExternalAuthMap.DoesNotExist
|
||||
except Exception: # pylint: disable=broad-except
|
||||
datarow.append('')
|
||||
|
||||
if get_grades:
|
||||
@@ -843,12 +803,12 @@ def _do_enroll_students(course, course_key, students, secure=False, overload=Fal
|
||||
|
||||
if overload: # delete all but staff
|
||||
todelete = CourseEnrollment.objects.filter(course_id=course_key)
|
||||
for ce in todelete:
|
||||
if not has_access(ce.user, 'staff', course) and ce.user.email.lower() not in new_students_lc:
|
||||
status[ce.user.email] = 'deleted'
|
||||
ce.deactivate()
|
||||
for enrollee in todelete:
|
||||
if not has_access(enrollee.user, 'staff', course) and enrollee.user.email.lower() not in new_students_lc:
|
||||
status[enrollee.user.email] = 'deleted'
|
||||
enrollee.deactivate()
|
||||
else:
|
||||
status[ce.user.email] = 'is staff'
|
||||
status[enrollee.user.email] = 'is staff'
|
||||
ceaset = CourseEnrollmentAllowed.objects.filter(course_id=course_key)
|
||||
for cea in ceaset:
|
||||
status[cea.email] = 'removed from pending enrollment list'
|
||||
@@ -882,7 +842,7 @@ def _do_enroll_students(course, course_key, students, secure=False, overload=Fal
|
||||
)
|
||||
|
||||
# Composition of email
|
||||
d = {
|
||||
email_data = {
|
||||
'site_name': stripped_site_name,
|
||||
'registration_url': registration_url,
|
||||
'course': course,
|
||||
@@ -897,11 +857,11 @@ def _do_enroll_students(course, course_key, students, secure=False, overload=Fal
|
||||
user = User.objects.get(email=student)
|
||||
except User.DoesNotExist:
|
||||
|
||||
#Student not signed up yet, put in pending enrollment allowed table
|
||||
# Student not signed up yet, put in pending enrollment allowed table
|
||||
cea = CourseEnrollmentAllowed.objects.filter(email=student, course_id=course_key)
|
||||
|
||||
#If enrollmentallowed already exists, update auto_enroll flag to however it was set in UI
|
||||
#Will be 0 or 1 records as there is a unique key on email + course_id
|
||||
# If enrollmentallowed already exists, update auto_enroll flag to however it was set in UI
|
||||
# Will be 0 or 1 records as there is a unique key on email + course_id
|
||||
if cea:
|
||||
cea[0].auto_enroll = auto_enroll
|
||||
cea[0].save()
|
||||
@@ -909,7 +869,7 @@ def _do_enroll_students(course, course_key, students, secure=False, overload=Fal
|
||||
+ ('on' if auto_enroll else 'off')
|
||||
continue
|
||||
|
||||
#EnrollmentAllowed doesn't exist so create it
|
||||
# EnrollmentAllowed doesn't exist so create it
|
||||
cea = CourseEnrollmentAllowed(email=student, course_id=course_key, auto_enroll=auto_enroll)
|
||||
cea.save()
|
||||
|
||||
@@ -918,9 +878,9 @@ def _do_enroll_students(course, course_key, students, secure=False, overload=Fal
|
||||
|
||||
if email_students:
|
||||
# User is allowed to enroll but has not signed up yet
|
||||
d['email_address'] = student
|
||||
d['message'] = 'allowed_enroll'
|
||||
send_mail_ret = send_mail_to_student(student, d)
|
||||
email_data['email_address'] = student
|
||||
email_data['message'] = 'allowed_enroll'
|
||||
send_mail_ret = send_mail_to_student(student, email_data)
|
||||
status[student] += (', email sent' if send_mail_ret else '')
|
||||
continue
|
||||
|
||||
@@ -936,13 +896,13 @@ def _do_enroll_students(course, course_key, students, secure=False, overload=Fal
|
||||
|
||||
if email_students:
|
||||
# User enrolled for first time, populate dict with user specific info
|
||||
d['email_address'] = student
|
||||
d['full_name'] = user.profile.name
|
||||
d['message'] = 'enrolled_enroll'
|
||||
send_mail_ret = send_mail_to_student(student, d)
|
||||
email_data['email_address'] = student
|
||||
email_data['full_name'] = user.profile.name
|
||||
email_data['message'] = 'enrolled_enroll'
|
||||
send_mail_ret = send_mail_to_student(student, email_data)
|
||||
status[student] += (', email sent' if send_mail_ret else '')
|
||||
|
||||
except:
|
||||
except Exception: # pylint: disable=broad-except
|
||||
status[student] = 'rejected'
|
||||
|
||||
datatable = {'header': ['StudentEmail', 'action']}
|
||||
@@ -977,15 +937,17 @@ def _do_unenroll_students(course_key, students, email_students=False):
|
||||
)
|
||||
if email_students:
|
||||
course = modulestore().get_course(course_key)
|
||||
#Composition of email
|
||||
d = {'site_name': stripped_site_name,
|
||||
'course': course}
|
||||
# Composition of email
|
||||
data = {
|
||||
'site_name': stripped_site_name,
|
||||
'course': course
|
||||
}
|
||||
|
||||
for student in old_students:
|
||||
|
||||
isok = False
|
||||
cea = CourseEnrollmentAllowed.objects.filter(course_id=course_key, email=student)
|
||||
#Will be 0 or 1 records as there is a unique key on email + course_id
|
||||
# Will be 0 or 1 records as there is a unique key on email + course_id
|
||||
if cea:
|
||||
cea[0].delete()
|
||||
status[student] = "un-enrolled"
|
||||
@@ -996,25 +958,25 @@ def _do_unenroll_students(course_key, students, email_students=False):
|
||||
except User.DoesNotExist:
|
||||
|
||||
if isok and email_students:
|
||||
#User was allowed to join but had not signed up yet
|
||||
d['email_address'] = student
|
||||
d['message'] = 'allowed_unenroll'
|
||||
send_mail_ret = send_mail_to_student(student, d)
|
||||
# User was allowed to join but had not signed up yet
|
||||
data['email_address'] = student
|
||||
data['message'] = 'allowed_unenroll'
|
||||
send_mail_ret = send_mail_to_student(student, data)
|
||||
status[student] += (', email sent' if send_mail_ret else '')
|
||||
|
||||
continue
|
||||
|
||||
#Will be 0 or 1 records as there is a unique key on user + course_id
|
||||
# Will be 0 or 1 records as there is a unique key on user + course_id
|
||||
if CourseEnrollment.is_enrolled(user, course_key):
|
||||
try:
|
||||
CourseEnrollment.unenroll(user, course_key)
|
||||
status[student] = "un-enrolled"
|
||||
if email_students:
|
||||
#User was enrolled
|
||||
d['email_address'] = student
|
||||
d['full_name'] = user.profile.name
|
||||
d['message'] = 'enrolled_unenroll'
|
||||
send_mail_ret = send_mail_to_student(student, d)
|
||||
# User was enrolled
|
||||
data['email_address'] = student
|
||||
data['full_name'] = user.profile.name
|
||||
data['message'] = 'enrolled_unenroll'
|
||||
send_mail_ret = send_mail_to_student(student, data)
|
||||
status[student] += (', email sent' if send_mail_ret else '')
|
||||
|
||||
except Exception: # pylint: disable=broad-except
|
||||
@@ -1025,8 +987,7 @@ def _do_unenroll_students(course_key, students, email_students=False):
|
||||
datatable['data'] = [[x, status[x]] for x in sorted(status)]
|
||||
datatable['title'] = _('Un-enrollment of students')
|
||||
|
||||
data = dict(datatable=datatable)
|
||||
return data
|
||||
return dict(datatable=datatable)
|
||||
|
||||
|
||||
def send_mail_to_student(student, param_dict):
|
||||
@@ -1123,15 +1084,15 @@ def get_answers_distribution(request, course_key):
|
||||
|
||||
dist = grades.answer_distributions(course.id)
|
||||
|
||||
d = {}
|
||||
d['header'] = ['url_name', 'display name', 'answer id', 'answer', 'count']
|
||||
dist = {}
|
||||
dist['header'] = ['url_name', 'display name', 'answer id', 'answer', 'count']
|
||||
|
||||
d['data'] = [
|
||||
dist['data'] = [
|
||||
[url_name, display_name, answer_id, a, answers[a]]
|
||||
for (url_name, display_name, answer_id), answers in sorted(dist.items())
|
||||
for a in answers
|
||||
]
|
||||
return d
|
||||
return dist
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -1153,8 +1114,8 @@ def compute_course_stats(course):
|
||||
children = module.get_children()
|
||||
category = module.__class__.__name__ # HtmlDescriptor, CapaDescriptor, ...
|
||||
counts[category] += 1
|
||||
for c in children:
|
||||
walk(c)
|
||||
for child in children:
|
||||
walk(child)
|
||||
|
||||
walk(course)
|
||||
stats = dict(counts) # number of each kind of module
|
||||
|
||||
@@ -136,7 +136,7 @@ function goto( mode)
|
||||
<a class="instructor-info-action beta-button" href="${ standard_dashboard_url }">${_("Back To Instructor Dashboard")}</a>
|
||||
</div>
|
||||
|
||||
<h1>${_("Instructor Dashboard")}</h1>
|
||||
<h1>${_("Legacy Instructor Dashboard")}</h1>
|
||||
|
||||
%if settings.FEATURES.get('IS_EDX_DOMAIN', False):
|
||||
## Only show this banner on the edx.org website (other sites may choose to show this if they wish)
|
||||
@@ -201,21 +201,10 @@ function goto( mode)
|
||||
</div>
|
||||
% endif
|
||||
|
||||
<p class="is-deprecated">
|
||||
${_("To view the Gradebook (small courses only), please visit the 'Student Admin' section of the instructor dashboard.")}
|
||||
</p>
|
||||
<p>
|
||||
<input type="submit" name="action" value="Dump list of enrolled students" class="${'is-disabled' if disable_buttons else ''}">
|
||||
</p>
|
||||
|
||||
<p class="deprecated">
|
||||
${_("To perform grade downloads, please visit the 'Data Download' section of the instructor dashboard.")}
|
||||
</p>
|
||||
|
||||
<p class="is-deprecated">
|
||||
${_("To download student grades, please visit the 'Data Download' section of the instructor dashboard.")}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<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" class="${'is-disabled' if disable_buttons else ''}">
|
||||
@@ -226,7 +215,10 @@ function goto( mode)
|
||||
<input type="submit" name="action" value="Download CSV of answer distributions" class="${'is-disabled' if disable_buttons else ''}">
|
||||
%endif
|
||||
<p class="is-deprecated">
|
||||
${_("To view the graded assignments configuration, please visit the 'Data Download' section of the instructor dashboard.")}
|
||||
${_("To download student grades and view the grading configuration for your course, visit the Data Download section of the Instructor Dashboard.")}
|
||||
</p>
|
||||
<p class="is-deprecated">
|
||||
${_("To view the Gradebook (only available for courses with a small number of enrolled students), visit the Student Admin section of the Instructor Dashboard.")}
|
||||
</p>
|
||||
</p>
|
||||
<hr width="40%" style="align:left">
|
||||
@@ -267,13 +259,13 @@ function goto( mode)
|
||||
%if settings.FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS'):
|
||||
<H2>${_("Course-specific grade adjustment")}</h2>
|
||||
|
||||
<p class="is-deprecated">${_("To perform these actions, please visit the 'Student Admin' section of the instructor dashboard.")}</p>
|
||||
<p class="is-deprecated">${_("To perform these actions, visit the Student Admin section of the Instructor Dashboard.")}</p>
|
||||
|
||||
%endif
|
||||
|
||||
<h2>${_("Student-specific grade inspection and adjustment")}</h2>
|
||||
|
||||
<p class="is-deprecated">${_("To perform these actions, please visit the 'Student Admin' section of the instructor dashboard.")}</p>
|
||||
<p class="is-deprecated">${_("To perform these actions, visit the Student Admin section of the Instructor Dashboard.")}</p>
|
||||
|
||||
%endif
|
||||
|
||||
@@ -301,12 +293,8 @@ function goto( mode)
|
||||
##-----------------------------------------------------------------------------
|
||||
%if modeflag.get('Admin'):
|
||||
|
||||
%if instructor_access:
|
||||
<p class="is-deprecated">${_("To add or remove course staff, please visit the 'Membership' section of the instructor dashboard.")}</p>
|
||||
%endif
|
||||
|
||||
%if admin_access:
|
||||
<p class="is-deprecated">${_("To add or remove course instructors, please visit the 'Membership' section of the instructor dashboard.")}</p>
|
||||
%if instructor_access or admin_access:
|
||||
<p class="is-deprecated">${_("To add or remove course staff or instructors, visit the Membership section of the Instructor Dashboard.")}</p>
|
||||
%endif
|
||||
|
||||
%if settings.FEATURES['ENABLE_MANUAL_GIT_RELOAD'] and admin_access:
|
||||
@@ -318,7 +306,7 @@ function goto( mode)
|
||||
|
||||
##-----------------------------------------------------------------------------
|
||||
%if modeflag.get('Forum Admin'):
|
||||
<p class="is-deprecated">${_("To manage forum roles, please visit the 'Membership' section of the instructor dashboard.")}</p>
|
||||
<p class="is-deprecated">${_("To manage forum roles, visit the Membership section of the Instructor Dashboard.")}</p>
|
||||
%endif
|
||||
|
||||
##-----------------------------------------------------------------------------
|
||||
@@ -369,17 +357,13 @@ function goto( mode)
|
||||
|
||||
%if modeflag.get('Data'):
|
||||
<hr width="40%" style="align:left">
|
||||
<p class="is-deprecated">
|
||||
${_("To download student profile data, please visit the 'Data Download' section of the instructor dashboard.")}
|
||||
</p>
|
||||
|
||||
<p> ${_("Problem urlname:")}
|
||||
<input type="text" name="problem_to_dump" size="40">
|
||||
<input type="submit" name="action" value="Download CSV of all responses to problem">
|
||||
</p>
|
||||
|
||||
<p class="is-deprecated">
|
||||
${_("To download student anonymized IDs, please visit the 'Data Download' section of the instructor dashboard.")}
|
||||
${_("To download student profile data and anonymized IDs, visit the Data Download section of the Instructor Dashboard.")}
|
||||
</p>
|
||||
<hr width="40%" style="align:left">
|
||||
%endif
|
||||
@@ -388,19 +372,18 @@ function goto( mode)
|
||||
|
||||
%if modeflag.get('Manage Groups'):
|
||||
%if instructor_access:
|
||||
<p class="is-deprecated">${_("To manage beta tester roles, please visit the 'Membership' section of the instructor dashboard.")}</p>
|
||||
|
||||
%if course.is_cohorted:
|
||||
<p class="is-deprecated">${_("To manage course cohorts, please visit the 'Membership' section of the instructor dashboard.")}</p>
|
||||
<p class="is-deprecated">${_("To manage beta tester roles and cohort groups, visit the Membership section of the Instructor Dashboard.")}</p>
|
||||
%else:
|
||||
<p class="is-deprecated">${_("To manage beta tester roles, visit the Membership section of the Instructor Dashboard.")}</p>
|
||||
%endif
|
||||
|
||||
%endif
|
||||
%endif
|
||||
|
||||
##-----------------------------------------------------------------------------
|
||||
|
||||
%if modeflag.get('Email'):
|
||||
<p class="is-deprecated">${_("To send email, please visit the 'Email' section of the instructor dashboard.")}</p>
|
||||
<p class="is-deprecated">${_("To send email, visit the Email section of the Instructor Dashboard.")}</p>
|
||||
%endif
|
||||
|
||||
</form>
|
||||
@@ -698,7 +681,7 @@ function goto( mode)
|
||||
<br/>
|
||||
<h2>${_("Course Statistics At A Glance")}</h2>
|
||||
<p class="is-deprecated">
|
||||
${_("These statistics can be viewed under the 'Admin' tab of the legacy instructor dashboard.")}
|
||||
${_("View course statistics in the Admin section of this legacy instructor dashboard.")}
|
||||
</p>
|
||||
%endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user