'
# If this fails, it is likely because ENABLE_INSTRUCTOR_EMAIL is set to False
- self.assertTrue(email_link in response.content)
-
- # Select the Email view of the instructor dash
- session = self.client.session
- session[u'idash_mode:{0}'.format(self.course.location.course_id)] = 'Email'
- session.save()
- response = self.client.get(url)
- selected_email_link = '
'
- self.assertTrue(selected_email_link in response.content)
+ self.assertTrue(email_section in response.content)
@patch.dict(settings.FEATURES, {'ENABLE_INSTRUCTOR_EMAIL': True, 'REQUIRE_COURSE_EMAIL_AUTH': False})
def test_optout_course(self):
@@ -77,15 +77,14 @@ class TestOptoutCourseEmails(ModuleStoreTestCase):
self.client.login(username=self.instructor.username, password="test")
self.navigate_to_email_view()
- url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id})
test_email = {
'action': 'Send email',
- 'to_option': 'all',
+ 'send_to': 'all',
'subject': 'test subject for all',
'message': 'test message for all'
}
- response = self.client.post(url, test_email)
- self.assertContains(response, "Your email was successfully queued for sending.")
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
# Assert that self.student.email not in mail.to, outbox should be empty
self.assertEqual(len(mail.outbox), 0)
@@ -106,16 +105,14 @@ class TestOptoutCourseEmails(ModuleStoreTestCase):
self.client.login(username=self.instructor.username, password="test")
self.navigate_to_email_view()
- url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id})
test_email = {
'action': 'Send email',
- 'to_option': 'all',
+ 'send_to': 'all',
'subject': 'test subject for all',
'message': 'test message for all'
}
- response = self.client.post(url, test_email)
-
- self.assertContains(response, "Your email was successfully queued for sending.")
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
# Assert that self.student.email in mail.to
self.assertEqual(len(mail.outbox), 1)
diff --git a/lms/djangoapps/bulk_email/tests/test_email.py b/lms/djangoapps/bulk_email/tests/test_email.py
index d1b8e380e9..bcfcbba721 100644
--- a/lms/djangoapps/bulk_email/tests/test_email.py
+++ b/lms/djangoapps/bulk_email/tests/test_email.py
@@ -2,6 +2,8 @@
"""
Unit tests for sending course email
"""
+import json
+
from mock import patch
from django.conf import settings
@@ -70,18 +72,17 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
# Pull up email view on instructor dashboard
self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id})
+ # Response loads the whole instructor dashboard, so no need to explicitly
+ # navigate to a particular email section
response = self.client.get(self.url)
- email_link = '
'
# If this fails, it is likely because ENABLE_INSTRUCTOR_EMAIL is set to False
- self.assertTrue(email_link in response.content)
-
- # Select the Email view of the instructor dash
- session = self.client.session
- session[u'idash_mode:{0}'.format(self.course.location.course_id)] = 'Email'
- session.save()
- response = self.client.get(self.url)
- selected_email_link = '
Email'
- self.assertTrue(selected_email_link in response.content)
+ self.assertTrue(email_section in response.content)
+ self.send_mail_url = reverse('send_email', kwargs={'course_id': self.course.id})
+ self.success_content = {
+ 'course_id': self.course.id,
+ 'success': True,
+ }
def tearDown(self):
"""
@@ -96,12 +97,13 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
"""
test_email = {
'action': 'Send email',
- 'to_option': 'myself',
+ 'send_to': 'myself',
'subject': 'test subject for myself',
'message': 'test message for myself'
}
- response = self.client.post(self.url, test_email)
- self.assertContains(response, "Email is not enabled for this course.")
+ response = self.client.post(self.send_mail_url, test_email)
+ # We should get back a HttpResponseForbidden (status code 403)
+ self.assertContains(response, "Email is not enabled for this course.", status_code=403)
def test_send_to_self(self):
"""
@@ -110,15 +112,16 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
# Now we know we have pulled up the instructor dash's email view
# (in the setUp method), we can test sending an email.
test_email = {
- 'action': 'Send email',
- 'to_option': 'myself',
+ 'action': 'send',
+ 'send_to': 'myself',
'subject': 'test subject for myself',
'message': 'test message for myself'
}
- response = self.client.post(self.url, test_email)
-
- self.assertContains(response, "Your email was successfully queued for sending.")
+ # Post the email to the instructor dashboard API
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
+ # Check that outbox is as expected
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(len(mail.outbox[0].to), 1)
self.assertEquals(mail.outbox[0].to[0], self.instructor.email)
@@ -135,13 +138,13 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
# (in the setUp method), we can test sending an email.
test_email = {
'action': 'Send email',
- 'to_option': 'staff',
+ 'send_to': 'staff',
'subject': 'test subject for staff',
'message': 'test message for subject'
}
- response = self.client.post(self.url, test_email)
-
- self.assertContains(response, "Your email was successfully queued for sending.")
+ # Post the email to the instructor dashboard API
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
# the 1 is for the instructor in this test and others
self.assertEquals(len(mail.outbox), 1 + len(self.staff))
@@ -159,13 +162,13 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
test_email = {
'action': 'Send email',
- 'to_option': 'all',
+ 'send_to': 'all',
'subject': 'test subject for all',
'message': 'test message for all'
}
- response = self.client.post(self.url, test_email)
-
- self.assertContains(response, "Your email was successfully queued for sending.")
+ # Post the email to the instructor dashboard API
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
self.assertEquals(len(mail.outbox), 1 + len(self.staff) + len(self.students))
self.assertItemsEqual(
@@ -183,13 +186,13 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
uni_subject = u'téśt śúbjéćt főŕ áĺĺ'
test_email = {
'action': 'Send email',
- 'to_option': 'all',
+ 'send_to': 'all',
'subject': uni_subject,
'message': 'test message for all'
}
- response = self.client.post(self.url, test_email)
-
- self.assertContains(response, "Your email was successfully queued for sending.")
+ # Post the email to the instructor dashboard API
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
self.assertEquals(len(mail.outbox), 1 + len(self.staff) + len(self.students))
self.assertItemsEqual(
@@ -211,13 +214,13 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
uni_message = u'ẗëṡẗ ṁëṡṡäġë ḟöṛ äḷḷ イ乇丂イ ᄊ乇丂丂ムg乇 キo尺 ムレレ тэѕт мэѕѕаБэ fоѓ аll'
test_email = {
'action': 'Send email',
- 'to_option': 'all',
+ 'send_to': 'all',
'subject': 'test subject for all',
'message': uni_message
}
- response = self.client.post(self.url, test_email)
-
- self.assertContains(response, "Your email was successfully queued for sending.")
+ # Post the email to the instructor dashboard API
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
self.assertEquals(len(mail.outbox), 1 + len(self.staff) + len(self.students))
self.assertItemsEqual(
@@ -242,13 +245,13 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
test_email = {
'action': 'Send email',
- 'to_option': 'all',
+ 'send_to': 'all',
'subject': 'test subject for all',
'message': 'test message for all'
}
- response = self.client.post(self.url, test_email)
-
- self.assertContains(response, "Your email was successfully queued for sending.")
+ # Post the email to the instructor dashboard API
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
self.assertEquals(len(mail.outbox), 1 + len(self.staff) + len(self.students))
@@ -280,12 +283,14 @@ class TestEmailSendFromDashboard(ModuleStoreTestCase):
test_email = {
'action': 'Send email',
- 'to_option': 'all',
+ 'send_to': 'all',
'subject': 'test subject for all',
'message': 'test message for all'
}
- response = self.client.post(self.url, test_email)
- self.assertContains(response, "Your email was successfully queued for sending.")
+ # Post the email to the instructor dashboard API
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
+
self.assertEquals(mock_factory.emails_sent,
1 + len(self.staff) + len(self.students) + LARGE_NUM_EMAILS - len(optouts))
outbox_contents = [e.to[0] for e in mail.outbox]
diff --git a/lms/djangoapps/bulk_email/tests/test_err_handling.py b/lms/djangoapps/bulk_email/tests/test_err_handling.py
index f7b8b32d1f..c6b54391b2 100644
--- a/lms/djangoapps/bulk_email/tests/test_err_handling.py
+++ b/lms/djangoapps/bulk_email/tests/test_err_handling.py
@@ -2,6 +2,8 @@
"""
Unit tests for handling email sending errors
"""
+import json
+
from itertools import cycle
from mock import patch
from smtplib import SMTPDataError, SMTPServerDisconnected, SMTPConnectError
@@ -53,6 +55,11 @@ class TestEmailErrors(ModuleStoreTestCase):
# load initial content (since we don't run migrations as part of tests):
call_command("loaddata", "course_email_template.json")
self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id})
+ self.send_mail_url = reverse('send_email', kwargs={'course_id': self.course.id})
+ self.success_content = {
+ 'course_id': self.course.id,
+ 'success': True,
+ }
def tearDown(self):
patch.stopall()
@@ -66,15 +73,16 @@ class TestEmailErrors(ModuleStoreTestCase):
get_conn.return_value.send_messages.side_effect = SMTPDataError(455, "Throttling: Sending rate exceeded")
test_email = {
'action': 'Send email',
- 'to_option': 'myself',
+ 'send_to': 'myself',
'subject': 'test subject for myself',
'message': 'test message for myself'
}
- self.client.post(self.url, test_email)
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
# Test that we retry upon hitting a 4xx error
self.assertTrue(retry.called)
- (_, kwargs) = retry.call_args
+ (__, kwargs) = retry.call_args
exc = kwargs['exc']
self.assertIsInstance(exc, SMTPDataError)
@@ -94,11 +102,12 @@ class TestEmailErrors(ModuleStoreTestCase):
test_email = {
'action': 'Send email',
- 'to_option': 'all',
+ 'send_to': 'all',
'subject': 'test subject for all',
'message': 'test message for all'
}
- self.client.post(self.url, test_email)
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
# We shouldn't retry when hitting a 5xx error
self.assertFalse(retry.called)
@@ -118,14 +127,15 @@ class TestEmailErrors(ModuleStoreTestCase):
get_conn.return_value.open.side_effect = SMTPServerDisconnected(425, "Disconnecting")
test_email = {
'action': 'Send email',
- 'to_option': 'myself',
+ 'send_to': 'myself',
'subject': 'test subject for myself',
'message': 'test message for myself'
}
- self.client.post(self.url, test_email)
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
self.assertTrue(retry.called)
- (_, kwargs) = retry.call_args
+ (__, kwargs) = retry.call_args
exc = kwargs['exc']
self.assertIsInstance(exc, SMTPServerDisconnected)
@@ -139,14 +149,15 @@ class TestEmailErrors(ModuleStoreTestCase):
test_email = {
'action': 'Send email',
- 'to_option': 'myself',
+ 'send_to': 'myself',
'subject': 'test subject for myself',
'message': 'test message for myself'
}
- self.client.post(self.url, test_email)
+ response = self.client.post(self.send_mail_url, test_email)
+ self.assertEquals(json.loads(response.content), self.success_content)
self.assertTrue(retry.called)
- (_, kwargs) = retry.call_args
+ (__, kwargs) = retry.call_args
exc = kwargs['exc']
self.assertIsInstance(exc, SMTPConnectError)
@@ -162,7 +173,7 @@ class TestEmailErrors(ModuleStoreTestCase):
task_input = {"email_id": -1}
with self.assertRaises(CourseEmail.DoesNotExist):
perform_delegate_email_batches(entry.id, course_id, task_input, "action_name") # pylint: disable=E1101
- ((log_str, _, email_id), _) = mock_log.warning.call_args
+ ((log_str, __, email_id), __) = mock_log.warning.call_args
self.assertTrue(mock_log.warning.called)
self.assertIn('Failed to get CourseEmail with id', log_str)
self.assertEqual(email_id, -1)
diff --git a/lms/djangoapps/class_dashboard/test/test_dashboard_data.py b/lms/djangoapps/class_dashboard/tests/test_dashboard_data.py
similarity index 97%
rename from lms/djangoapps/class_dashboard/test/test_dashboard_data.py
rename to lms/djangoapps/class_dashboard/tests/test_dashboard_data.py
index e53d373b75..a011ee6dce 100644
--- a/lms/djangoapps/class_dashboard/test/test_dashboard_data.py
+++ b/lms/djangoapps/class_dashboard/tests/test_dashboard_data.py
@@ -253,17 +253,6 @@ class TestGetProblemGradeDistribution(ModuleStoreTestCase):
b_section_has_problem = get_array_section_has_problem(self.course.id)
self.assertEquals(b_section_has_problem[0], True)
- def test_dashboard(self):
-
- url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id})
- response = self.client.post(
- url,
- {
- 'idash_mode': 'Metrics'
- }
- )
- self.assertContains(response, '
Course Statistics At A Glance
')
-
def test_has_instructor_access_for_class(self):
"""
Test for instructor access
diff --git a/lms/djangoapps/class_dashboard/test/test_views.py b/lms/djangoapps/class_dashboard/tests/test_views.py
similarity index 100%
rename from lms/djangoapps/class_dashboard/test/test_views.py
rename to lms/djangoapps/class_dashboard/tests/test_views.py
diff --git a/lms/djangoapps/courseware/features/courseware_common.py b/lms/djangoapps/courseware/features/courseware_common.py
index 1c836f8674..fdc6dd2617 100644
--- a/lms/djangoapps/courseware/features/courseware_common.py
+++ b/lms/djangoapps/courseware/features/courseware_common.py
@@ -1,5 +1,6 @@
# pylint: disable=C0111
# pylint: disable=W0621
+# pylint: disable=unused-argument
from lettuce import world, step
@@ -14,6 +15,11 @@ def i_click_on_the_tab(step, tab_text):
world.click_link(tab_text)
+@step('I click on the "([^"]*)" link$')
+def i_click_on_the_link(step, link_text):
+ world.click_link(link_text)
+
+
@step('I visit the courseware URL$')
def i_visit_the_course_info_url(step):
world.visit('/courses/MITx/6.002x/2012_Fall/courseware')
diff --git a/lms/djangoapps/courseware/features/lti.feature b/lms/djangoapps/courseware/features/lti.feature
index eb888daede..e26647de32 100644
--- a/lms/djangoapps/courseware/features/lti.feature
+++ b/lms/djangoapps/courseware/features/lti.feature
@@ -51,7 +51,8 @@ Feature: LMS.LTI component
Then I see text "Problem Scores: 5/10"
And I see graph with total progress "5%"
Then I click on the "Instructor" tab
- And I click on the "Gradebook" tab
+ And I click on the "Student Admin" tab
+ And I click on the "View Gradebook" link
And I see in the gradebook table that "HW" is "50"
And I see in the gradebook table that "Total" is "5"
@@ -88,7 +89,8 @@ Feature: LMS.LTI component
Then I see text "Problem Scores: 8/10"
And I see graph with total progress "8%"
Then I click on the "Instructor" tab
- And I click on the "Gradebook" tab
+ And I click on the "Student Admin" tab
+ And I click on the "View Gradebook" link
And I see in the gradebook table that "HW" is "80"
And I see in the gradebook table that "Total" is "8"
And I visit the LTI component
@@ -113,7 +115,8 @@ Feature: LMS.LTI component
Then I see text "Problem Scores: 0/10"
And I see graph with total progress "0%"
Then I click on the "Instructor" tab
- And I click on the "Gradebook" tab
+ And I click on the "Student Admin" tab
+ And I click on the "View Gradebook" link
And I see in the gradebook table that "HW" is "0"
And I see in the gradebook table that "Total" is "0"
diff --git a/lms/djangoapps/instructor/features/bulk_email.py b/lms/djangoapps/instructor/features/bulk_email.py
index 821e6c9f73..a3981f0e61 100644
--- a/lms/djangoapps/instructor/features/bulk_email.py
+++ b/lms/djangoapps/instructor/features/bulk_email.py
@@ -117,7 +117,6 @@ def when_i_send_an_email(step, recipient): # pylint: disable=unused-argument
# Go to the email section of the instructor dash
world.visit('/courses/edx/888/Bulk_Email_Test_Course')
world.css_click('a[href="/courses/edx/888/Bulk_Email_Test_Course/instructor"]')
- world.css_click('div.beta-button-wrapper>a.beta-button')
world.css_click('a[data-section="send_email"]')
# Select the recipient
diff --git a/lms/djangoapps/instructor/features/common.py b/lms/djangoapps/instructor/features/common.py
index d6c23a1518..c2074ad493 100644
--- a/lms/djangoapps/instructor/features/common.py
+++ b/lms/djangoapps/instructor/features/common.py
@@ -77,7 +77,6 @@ def go_to_section(section_name):
# course_info, membership, student_admin, data_download, analytics, send_email
world.visit('/courses/edx/999/Test_Course')
world.css_click('a[href="/courses/edx/999/Test_Course/instructor"]')
- world.css_click('div.beta-button-wrapper>a.beta-button')
world.css_click('a[data-section="{0}"]'.format(section_name))
diff --git a/lms/djangoapps/instructor/tests/test_email.py b/lms/djangoapps/instructor/tests/test_email.py
index 6a2b71f2e8..8c9bc2542b 100644
--- a/lms/djangoapps/instructor/tests/test_email.py
+++ b/lms/djangoapps/instructor/tests/test_email.py
@@ -34,7 +34,7 @@ class TestNewInstructorDashboardEmailViewMongoBacked(ModuleStoreTestCase):
self.client.login(username=instructor.username, password="test")
# URL for instructor dash
- self.url = reverse('instructor_dashboard_2', kwargs={'course_id': self.course.id})
+ self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id})
# URL for email view
self.email_link = '
Email'
@@ -122,7 +122,7 @@ class TestNewInstructorDashboardEmailViewXMLBacked(ModuleStoreTestCase):
self.client.login(username=instructor.username, password="test")
# URL for instructor dash
- self.url = reverse('instructor_dashboard_2', kwargs={'course_id': self.course_name})
+ self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course_name})
# URL for email view
self.email_link = '
Email'
diff --git a/lms/djangoapps/instructor/tests/test_legacy_anon_csv.py b/lms/djangoapps/instructor/tests/test_legacy_anon_csv.py
index b3a329ee05..60b05440e3 100644
--- a/lms/djangoapps/instructor/tests/test_legacy_anon_csv.py
+++ b/lms/djangoapps/instructor/tests/test_legacy_anon_csv.py
@@ -52,7 +52,7 @@ class TestInstructorDashboardAnonCSV(ModuleStoreTestCase, LoginEnrollmentTestCas
def test_download_anon_csv(self):
course = self.toy
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
with patch('instructor.views.legacy.unique_id_for_user') as mock_unique:
mock_unique.return_value = 42
diff --git a/lms/djangoapps/instructor/tests/test_legacy_download_csv.py b/lms/djangoapps/instructor/tests/test_legacy_download_csv.py
index a03f029ff3..f5be4e8a67 100644
--- a/lms/djangoapps/instructor/tests/test_legacy_download_csv.py
+++ b/lms/djangoapps/instructor/tests/test_legacy_download_csv.py
@@ -49,7 +49,7 @@ class TestInstructorDashboardGradeDownloadCSV(ModuleStoreTestCase, LoginEnrollme
def test_download_grades_csv(self):
course = self.toy
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
msg = "url = {0}\n".format(url)
response = self.client.post(url, {'action': 'Download CSV of all student grades for this course'})
msg += "instructor dashboard download csv grades: response = '{0}'\n".format(response)
diff --git a/lms/djangoapps/instructor/tests/test_legacy_email.py b/lms/djangoapps/instructor/tests/test_legacy_email.py
index 823d112b3f..90ff66bb75 100644
--- a/lms/djangoapps/instructor/tests/test_legacy_email.py
+++ b/lms/djangoapps/instructor/tests/test_legacy_email.py
@@ -32,7 +32,7 @@ class TestInstructorDashboardEmailView(ModuleStoreTestCase):
self.client.login(username=instructor.username, password="test")
# URL for instructor dash
- self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id})
+ self.url = reverse('instructor_dashboard_legacy', kwargs={'course_id': self.course.id})
# URL for email view
self.email_link = '
Email'
diff --git a/lms/djangoapps/instructor/tests/test_legacy_enrollment.py b/lms/djangoapps/instructor/tests/test_legacy_enrollment.py
index 2a3b29c742..4efd6f88b2 100644
--- a/lms/djangoapps/instructor/tests/test_legacy_enrollment.py
+++ b/lms/djangoapps/instructor/tests/test_legacy_enrollment.py
@@ -52,7 +52,7 @@ class TestInstructorEnrollsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase)
course = self.course
# Run the Un-enroll students command
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
response = self.client.post(
url,
{
@@ -84,7 +84,7 @@ class TestInstructorEnrollsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase)
course = self.course
# Run the Enroll students command
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
response = self.client.post(url, {'action': 'Enroll multiple students', 'multiple_students': 'student1_1@test.com, student1_2@test.com', 'auto_enroll': 'on'})
# Check the page output
@@ -129,7 +129,7 @@ class TestInstructorEnrollsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase)
course = self.course
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
response = self.client.post(url, {'action': 'Enroll multiple students', 'multiple_students': 'student0@test.com', 'auto_enroll': 'on'})
self.assertContains(response, '
student0@test.com | ')
self.assertContains(response, '
already enrolled | ')
@@ -142,7 +142,7 @@ class TestInstructorEnrollsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase)
course = self.course
# Run the Enroll students command
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
response = self.client.post(url, {'action': 'Enroll multiple students', 'multiple_students': 'student2_1@test.com, student2_2@test.com'})
# Check the page output
@@ -199,7 +199,7 @@ class TestInstructorEnrollsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase)
# Create activated, but not enrolled, user
UserFactory.create(username="student3_0", email="student3_0@test.com", first_name='Autoenrolled')
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
response = self.client.post(url, {'action': 'Enroll multiple students', 'multiple_students': 'student3_0@test.com, student3_1@test.com, student3_2@test.com', 'auto_enroll': 'on', 'email_students': 'on'})
# Check the page output
@@ -254,7 +254,7 @@ class TestInstructorEnrollsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase)
cea = CourseEnrollmentAllowed(email='student4_0@test.com', course_id=course.id)
cea.save()
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
response = self.client.post(url, {'action': 'Unenroll multiple students', 'multiple_students': 'student4_0@test.com, student2@test.com, student3@test.com', 'email_students': 'on'})
# Check the page output
@@ -301,7 +301,7 @@ class TestInstructorEnrollsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase)
# Create activated, but not enrolled, user
UserFactory.create(username="student5_0", email="student5_0@test.com", first_name="ShibTest", last_name="Enrolled")
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
response = self.client.post(url, {'action': 'Enroll multiple students', 'multiple_students': 'student5_0@test.com, student5_1@test.com', 'auto_enroll': 'on', 'email_students': 'on'})
# Check the page output
diff --git a/lms/djangoapps/instructor/tests/test_legacy_forum_admin.py b/lms/djangoapps/instructor/tests/test_legacy_forum_admin.py
index 2da8d18d73..39003c0603 100644
--- a/lms/djangoapps/instructor/tests/test_legacy_forum_admin.py
+++ b/lms/djangoapps/instructor/tests/test_legacy_forum_admin.py
@@ -67,7 +67,7 @@ class TestInstructorDashboardForumAdmin(ModuleStoreTestCase, LoginEnrollmentTest
def test_add_forum_admin_users_for_unknown_user(self):
course = self.toy
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
username = 'unknown'
for action in ['Add', 'Remove']:
for rolename in FORUM_ROLES:
@@ -76,7 +76,7 @@ class TestInstructorDashboardForumAdmin(ModuleStoreTestCase, LoginEnrollmentTest
def test_add_forum_admin_users_for_missing_roles(self):
course = self.toy
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
username = 'u1'
for action in ['Add', 'Remove']:
for rolename in FORUM_ROLES:
@@ -86,7 +86,7 @@ class TestInstructorDashboardForumAdmin(ModuleStoreTestCase, LoginEnrollmentTest
def test_remove_forum_admin_users_for_missing_users(self):
course = self.toy
self.initialize_roles(course.id)
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
username = 'u1'
action = 'Remove'
for rolename in FORUM_ROLES:
@@ -96,7 +96,7 @@ class TestInstructorDashboardForumAdmin(ModuleStoreTestCase, LoginEnrollmentTest
def test_add_and_remove_forum_admin_users(self):
course = self.toy
self.initialize_roles(course.id)
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
username = 'u2'
for rolename in FORUM_ROLES:
response = self.client.post(url, {'action': action_name('Add', rolename), FORUM_ADMIN_USER[rolename]: username})
@@ -109,7 +109,7 @@ class TestInstructorDashboardForumAdmin(ModuleStoreTestCase, LoginEnrollmentTest
def test_add_and_read_forum_admin_users(self):
course = self.toy
self.initialize_roles(course.id)
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
username = 'u2'
for rolename in FORUM_ROLES:
# perform an add, and follow with a second identical add:
@@ -121,7 +121,7 @@ class TestInstructorDashboardForumAdmin(ModuleStoreTestCase, LoginEnrollmentTest
def test_add_nonstaff_forum_admin_users(self):
course = self.toy
self.initialize_roles(course.id)
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
username = 'u1'
rolename = FORUM_ROLE_ADMINISTRATOR
response = self.client.post(url, {'action': action_name('Add', rolename), FORUM_ADMIN_USER[rolename]: username})
@@ -130,7 +130,7 @@ class TestInstructorDashboardForumAdmin(ModuleStoreTestCase, LoginEnrollmentTest
def test_list_forum_admin_users(self):
course = self.toy
self.initialize_roles(course.id)
- url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id})
username = 'u2'
added_roles = [FORUM_ROLE_STUDENT] # u2 is already added as a student to the discussion forums
self.assertTrue(has_forum_access(username, course.id, 'Student'))
diff --git a/lms/djangoapps/instructor/tests/test_legacy_gradebook.py b/lms/djangoapps/instructor/tests/test_legacy_gradebook.py
index bca7528a96..75f5155d35 100644
--- a/lms/djangoapps/instructor/tests/test_legacy_gradebook.py
+++ b/lms/djangoapps/instructor/tests/test_legacy_gradebook.py
@@ -67,7 +67,7 @@ class TestGradebook(ModuleStoreTestCase):
module_state_key=Location(item.location).url()
)
- self.response = self.client.get(reverse('gradebook', args=(self.course.id,)))
+ self.response = self.client.get(reverse('gradebook_legacy', args=(self.course.id,)))
def test_response_code(self):
self.assertEquals(self.response.status_code, 200)
diff --git a/lms/djangoapps/instructor/tests/test_legacy_raw_download_csv.py b/lms/djangoapps/instructor/tests/test_legacy_raw_download_csv.py
index cb7aa803d0..01f452f105 100644
--- a/lms/djangoapps/instructor/tests/test_legacy_raw_download_csv.py
+++ b/lms/djangoapps/instructor/tests/test_legacy_raw_download_csv.py
@@ -45,7 +45,7 @@ class TestRawGradeCSV(TestSubmittingProblems):
resp = self.submit_question_answer('p2', {'2_1': 'Correct'})
self.assertEqual(resp.status_code, 200)
- url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': self.course.id})
msg = "url = {0}\n".format(url)
response = self.client.post(url, {'action': 'Download CSV of all RAW grades'})
msg += "instructor dashboard download raw csv grades: response = '{0}'\n".format(response)
diff --git a/lms/djangoapps/instructor/tests/test_legacy_reset.py b/lms/djangoapps/instructor/tests/test_legacy_reset.py
index ea259bc1fb..d3e9e1d351 100644
--- a/lms/djangoapps/instructor/tests/test_legacy_reset.py
+++ b/lms/djangoapps/instructor/tests/test_legacy_reset.py
@@ -53,7 +53,7 @@ class InstructorResetStudentStateTest(ModuleStoreTestCase, LoginEnrollmentTestCa
sub_api.set_score(submission['uuid'], 1, 2)
# Delete student state using the instructor dash
- url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id})
+ url = reverse('instructor_dashboard_legacy', kwargs={'course_id': self.course.id})
response = self.client.post(url, {
'action': 'Delete student state for module',
'unique_student_identifier': self.student.email,
diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py
index 479a246f02..f487e300f0 100644
--- a/lms/djangoapps/instructor/views/api.py
+++ b/lms/djangoapps/instructor/views/api.py
@@ -1053,7 +1053,10 @@ def send_email(request, course_id):
# Submit the task, so that the correct InstructorTask object gets created (for monitoring purposes)
instructor_task.api.submit_bulk_course_email(request, course_id, email.id) # pylint: disable=E1101
- response_payload = {'course_id': course_id}
+ response_payload = {
+ 'course_id': course_id,
+ 'success': True,
+ }
return JsonResponse(response_payload)
diff --git a/lms/djangoapps/instructor/views/instructor_dashboard.py b/lms/djangoapps/instructor/views/instructor_dashboard.py
index ed9520420b..a7c7bee453 100644
--- a/lms/djangoapps/instructor/views/instructor_dashboard.py
+++ b/lms/djangoapps/instructor/views/instructor_dashboard.py
@@ -6,6 +6,7 @@ from django.utils.translation import ugettext as _
from django_future.csrf import ensure_csrf_cookie
from django.views.decorators.cache import cache_control
from edxmako.shortcuts import render_to_response
+from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.utils.html import escape
from django.http import Http404
@@ -18,9 +19,10 @@ from xmodule.modulestore.django import modulestore
from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds
from courseware.access import has_access
-from courseware.courses import get_course_by_id, get_cms_course_link
+from courseware.courses import get_course_by_id, get_cms_course_link, get_course_with_access
from django_comment_client.utils import has_forum_access
from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR
+from instructor.offline_gradecalc import student_grades
from student.models import CourseEnrollment
from bulk_email.models import CourseAuthorization
from class_dashboard.dashboard_data import get_section_display_name, get_array_section_has_problem
@@ -79,7 +81,7 @@ def instructor_dashboard_2(request, course_id):
context = {
'course': course,
- 'old_dashboard_url': reverse('instructor_dashboard', kwargs={'course_id': course_id}),
+ 'old_dashboard_url': reverse('instructor_dashboard_legacy', kwargs={'course_id': course_id}),
'studio_url': studio_url,
'sections': sections,
'disable_buttons': disable_buttons,
@@ -156,15 +158,23 @@ def _section_membership(course_id, access):
def _section_student_admin(course_id, access):
""" Provide data for the corresponding dashboard section """
+ is_small_course = False
+ enrollment_count = CourseEnrollment.num_enrolled_in(course_id)
+ max_enrollment_for_buttons = settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS")
+ if max_enrollment_for_buttons is not None:
+ is_small_course = enrollment_count <= max_enrollment_for_buttons
+
section_data = {
'section_key': 'student_admin',
'section_display_name': _('Student Admin'),
'access': access,
+ 'is_small_course': is_small_course,
'get_student_progress_url_url': reverse('get_student_progress_url', kwargs={'course_id': course_id}),
'enrollment_url': reverse('students_update_enrollment', kwargs={'course_id': course_id}),
'reset_student_attempts_url': reverse('reset_student_attempts', kwargs={'course_id': course_id}),
'rescore_problem_url': reverse('rescore_problem', kwargs={'course_id': course_id}),
'list_instructor_tasks_url': reverse('list_instructor_tasks', kwargs={'course_id': course_id}),
+ 'spoc_gradebook_url': reverse('spoc_gradebook', kwargs={'course_id': course_id}),
}
return section_data
@@ -246,3 +256,43 @@ def _section_metrics(course_id, access):
'get_students_problem_grades_url': reverse('get_students_problem_grades'),
}
return section_data
+
+
+#---- Gradebook (shown to small courses only) ----
+@cache_control(no_cache=True, no_store=True, must_revalidate=True)
+def spoc_gradebook(request, course_id):
+ """
+ Show the gradebook for this course:
+ - Only shown for courses with enrollment < settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS")
+ - Only displayed to course staff
+ """
+ course = get_course_with_access(request.user, course_id, 'staff', depth=None)
+
+ enrolled_students = User.objects.filter(
+ courseenrollment__course_id=course_id,
+ courseenrollment__is_active=1
+ ).order_by('username').select_related("profile")
+
+ # TODO (vshnayder): implement pagination to show to large courses
+ max_num_students = settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS")
+ enrolled_students = enrolled_students[:max_num_students] # HACK!
+
+ student_info = [
+ {
+ 'username': student.username,
+ 'id': student.id,
+ 'email': student.email,
+ 'grade_summary': student_grades(student, request, course),
+ 'realname': student.profile.name,
+ }
+ for student in enrolled_students
+ ]
+
+ return render_to_response('courseware/gradebook.html', {
+ 'students': student_info,
+ 'course': course,
+ 'course_id': course_id,
+ # Checked above
+ 'staff_access': True,
+ 'ordered_grades': sorted(course.grade_cutoffs.items(), key=lambda i: i[1], reverse=True),
+ })
diff --git a/lms/djangoapps/instructor/views/legacy.py b/lms/djangoapps/instructor/views/legacy.py
index 7f62501a12..1e8bad1bc4 100644
--- a/lms/djangoapps/instructor/views/legacy.py
+++ b/lms/djangoapps/instructor/views/legacy.py
@@ -1,6 +1,9 @@
"""
Instructor Views
"""
+## NOTE: This is the code for the legacy instructor dashboard
+## We are no longer supporting this file or accepting changes into it.
+
from contextlib import contextmanager
import csv
import json
@@ -946,8 +949,7 @@ def instructor_dashboard(request, course_id):
'metrics_results': metrics_results,
}
- if settings.FEATURES.get('ENABLE_INSTRUCTOR_BETA_DASHBOARD'):
- context['beta_dashboard_url'] = reverse('instructor_dashboard_2', kwargs={'course_id': course_id})
+ context['standard_dashboard_url'] = reverse('instructor_dashboard', kwargs={'course_id': course_id})
return render_to_response('courseware/instructor_dashboard.html', context)
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 884e5d874b..c0dbab529f 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -169,8 +169,10 @@ FEATURES = {
# Enable instructor to assign individual due dates
'INDIVIDUAL_DUE_DATES': False,
- # Enable instructor dash beta version link
- 'ENABLE_INSTRUCTOR_BETA_DASHBOARD': True,
+ # Enable legacy instructor dashboard
+ 'ENABLE_INSTRUCTOR_LEGACY_DASHBOARD': True,
+ # Is this an edX-owned domain? (used on instructor dashboard)
+ 'IS_EDX_DOMAIN': False,
# Toggle to enable certificates of courses on dashboard
'ENABLE_VERIFIED_CERTIFICATES': False,
diff --git a/lms/envs/dev.py b/lms/envs/dev.py
index 4a2b9517e0..e1c68d92e4 100644
--- a/lms/envs/dev.py
+++ b/lms/envs/dev.py
@@ -31,11 +31,13 @@ FEATURES['ENABLE_SERVICE_STATUS'] = True
FEATURES['ENABLE_INSTRUCTOR_EMAIL'] = True # Enable email for all Studio courses
FEATURES['REQUIRE_COURSE_EMAIL_AUTH'] = False # Give all courses email (don't require django-admin perms)
FEATURES['ENABLE_HINTER_INSTRUCTOR_VIEW'] = True
-FEATURES['ENABLE_INSTRUCTOR_BETA_DASHBOARD'] = True
+FEATURES['ENABLE_INSTRUCTOR_LEGACY_DASHBOARD'] = True
FEATURES['MULTIPLE_ENROLLMENT_ROLES'] = True
FEATURES['ENABLE_SHOPPING_CART'] = True
FEATURES['AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING'] = True
FEATURES['ENABLE_S3_GRADE_DOWNLOADS'] = True
+FEATURES['IS_EDX_DOMAIN'] = True # Is this an edX-owned domain? (used on instructor dashboard)
+
FEEDBACK_SUBMISSION_EMAIL = "dummy@example.com"
diff --git a/lms/envs/test.py b/lms/envs/test.py
index edaa4c7c45..110e7a48f6 100644
--- a/lms/envs/test.py
+++ b/lms/envs/test.py
@@ -33,7 +33,7 @@ FEATURES['ENABLE_SERVICE_STATUS'] = True
FEATURES['ENABLE_HINTER_INSTRUCTOR_VIEW'] = True
-FEATURES['ENABLE_INSTRUCTOR_BETA_DASHBOARD'] = True
+FEATURES['ENABLE_INSTRUCTOR_LEGACY_DASHBOARD'] = True
FEATURES['ENABLE_SHOPPING_CART'] = True
diff --git a/lms/static/coffee/src/instructor_dashboard/instructor_dashboard.coffee b/lms/static/coffee/src/instructor_dashboard/instructor_dashboard.coffee
index 4459e407df..1235feaceb 100644
--- a/lms/static/coffee/src/instructor_dashboard/instructor_dashboard.coffee
+++ b/lms/static/coffee/src/instructor_dashboard/instructor_dashboard.coffee
@@ -99,7 +99,7 @@ setup_instructor_dashboard = (idash_content) =>
e.preventDefault()
# deactivate all link & section styles
- idash_content.find(".#{CSS_INSTRUCTOR_NAV}").children().removeClass CSS_ACTIVE_SECTION
+ idash_content.find(".#{CSS_INSTRUCTOR_NAV} li").children().removeClass CSS_ACTIVE_SECTION
idash_content.find(".#{CSS_IDASH_SECTION}").removeClass CSS_ACTIVE_SECTION
# discover section paired to link
diff --git a/lms/static/coffee/src/instructor_dashboard_tracking.coffee b/lms/static/coffee/src/instructor_dashboard_tracking.coffee
index a4eab610c8..eaeb3a4862 100644
--- a/lms/static/coffee/src/instructor_dashboard_tracking.coffee
+++ b/lms/static/coffee/src/instructor_dashboard_tracking.coffee
@@ -1,4 +1,4 @@
if $('.instructor-dashboard-wrapper').length == 1
- analytics.track "Loaded an Instructor Dashboard Page",
+ analytics.track "Loaded a Legacy Instructor Dashboard Page",
location: window.location.pathname
dashboard_page: $('.navbar .selectedmode').text()
diff --git a/lms/static/js/spec/staff_debug_actions_spec.js b/lms/static/js/spec/staff_debug_actions_spec.js
index 347dd6d584..1a6a6a9691 100644
--- a/lms/static/js/spec/staff_debug_actions_spec.js
+++ b/lms/static/js/spec/staff_debug_actions_spec.js
@@ -6,7 +6,7 @@ describe('StaffDebugActions', function() {
describe('get_url ', function() {
it('defines url to courseware ajax entry point', function() {
spyOn(StaffDebug, "get_current_url").andReturn("/courses/edX/Open_DemoX/edx_demo_course/courseware/stuff");
- expect(StaffDebug.get_url('rescore_problem')).toBe('/courses/edX/Open_DemoX/edx_demo_course/instructor_dashboard/api/rescore_problem');
+ expect(StaffDebug.get_url('rescore_problem')).toBe('/courses/edX/Open_DemoX/edx_demo_course/instructor/api/rescore_problem');
});
});
@@ -40,7 +40,7 @@ describe('StaffDebugActions', function() {
'delete_module': false
});
expect($.ajax.mostRecentCall.args[0]['url']).toEqual(
- '/instructor_dashboard/api/reset_student_attempts'
+ '/instructor/api/reset_student_attempts'
);
$('#' + fixture_id).remove();
});
@@ -59,7 +59,7 @@ describe('StaffDebugActions', function() {
'delete_module': true
});
expect($.ajax.mostRecentCall.args[0]['url']).toEqual(
- '/instructor_dashboard/api/reset_student_attempts'
+ '/instructor/api/reset_student_attempts'
);
$('#' + fixture_id).remove();
@@ -79,7 +79,7 @@ describe('StaffDebugActions', function() {
'delete_module': false
});
expect($.ajax.mostRecentCall.args[0]['url']).toEqual(
- '/instructor_dashboard/api/rescore_problem'
+ '/instructor/api/rescore_problem'
);
$('#' + fixture_id).remove();
});
diff --git a/lms/static/js/staff_debug_actions.js b/lms/static/js/staff_debug_actions.js
index cf5bc85495..fb602a2388 100644
--- a/lms/static/js/staff_debug_actions.js
+++ b/lms/static/js/staff_debug_actions.js
@@ -7,7 +7,7 @@ var StaffDebug = (function(){
get_url = function(action){
var pathname = this.get_current_url();
- var url = pathname.substr(0,pathname.indexOf('/courseware')) + '/instructor_dashboard/api/' + action;
+ var url = pathname.substr(0,pathname.indexOf('/courseware')) + '/instructor/api/' + action;
return url;
}
diff --git a/lms/static/sass/course/instructor/_instructor.scss b/lms/static/sass/course/instructor/_instructor.scss
index 059db7a3ee..03211f7b45 100644
--- a/lms/static/sass/course/instructor/_instructor.scss
+++ b/lms/static/sass/course/instructor/_instructor.scss
@@ -121,9 +121,9 @@
}
}
}
-
+
//Metrics tab
-
+
.metrics-container {
position: relative;
width: 100%;
@@ -170,6 +170,18 @@
border-radius: 5px;
margin-top: 25px;
}
-
+
+ .wrapper-msg {
+ margin-bottom: ($baseline*1.5);
+
+ .msg {
+ margin-bottom: 0;
+ }
+
+ .note {
+ margin: 0;
+ }
+ }
+
}
diff --git a/lms/static/sass/course/instructor/_instructor_2.scss b/lms/static/sass/course/instructor/_instructor_2.scss
index 924de892c9..35a984c6e8 100644
--- a/lms/static/sass/course/instructor/_instructor_2.scss
+++ b/lms/static/sass/course/instructor/_instructor_2.scss
@@ -34,6 +34,11 @@
}
// system feedback - messages
+
+ .wrapper-msg {
+ margin-bottom: ($baseline*1.5);
+ }
+
.msg {
border-radius: 1px;
padding: $baseline/2 $baseline*0.75;
@@ -43,6 +48,10 @@
.copy {
font-weight: 600;
}
+
+ &.is-shown {
+ display: block;
+ }
}
// TYPE: warning
@@ -51,6 +60,10 @@
background: tint($warning-color,95%);
display: none;
color: $warning-color;
+
+ &.is-shown {
+ display: block;
+ }
}
// TYPE: confirm
@@ -59,6 +72,10 @@
background: tint($confirm-color,95%);
display: none;
color: $confirm-color;
+
+ &.is-shown {
+ display: block;
+ }
}
// TYPE: confirm
@@ -69,6 +86,10 @@
.copy {
color: $error-color;
}
+
+ &.is-shown {
+ display: block;
+ }
}
// inline copy
@@ -110,6 +131,11 @@ section.instructor-dashboard-content-2 {
// border: 1px solid blue;
// }
+ .wrap-instructor-info {
+ display: inline;
+ top: 0;
+ }
+
.request-response-error {
margin: 0;
padding-bottom: ($baseline);
@@ -141,8 +167,10 @@ section.instructor-dashboard-content-2 {
h1 {
@extend .top-header;
+ display: inline-block;
padding-bottom: 0;
border-bottom: 0;
+ margin-bottom: ($baseline*.75);
}
input[type="button"] {
@@ -163,20 +191,29 @@ section.instructor-dashboard-content-2 {
}
.instructor-nav {
- padding-bottom: 1em;
+ @extend %ui-no-list;
+ border-top: 1px solid $gray-l3;
+ border-bottom: 1px solid $gray-l3;
- border-bottom: 1px solid #C8C8C8;
- a {
- margin-right: 1.2em;
- }
+ .nav-item {
+ @extend %t-copy-base;
+ display: inline-block;
+ margin: ($baseline/2) $baseline;
- .active-section {
- color: #551A8B;
+ a {
+ display: block;
+ text-transform: uppercase;
+
+ &.active-section {
+ color: $black;
+ }
+ }
}
}
section.idash-section {
display: none;
+ margin-top: ($baseline*1.5);
// background-color: #0f0;
&.active-section {
@@ -560,14 +597,14 @@ section.instructor-dashboard-content-2 {
float: left;
clear: both;
margin-top: 25px;
-
+
.metrics-left {
position: relative;
width: 30%;
height: 640px;
float: left;
margin-right: 2.5%;
-
+
svg {
width: 100%;
}
@@ -579,33 +616,33 @@ section.instructor-dashboard-content-2 {
float: left;
margin-left: 2.5%;
margin-bottom: 25px;
-
+
svg {
width: 100%;
}
}
-
+
svg {
.stacked-bar {
cursor: pointer;
}
}
-
+
.metrics-tooltip {
width: 250px;
background-color: lightgray;
padding: 3px;
}
-
+
.metrics-overlay {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: rgba(255,255,255, .75);
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ background-color: rgba(255,255,255, .75);
display: none;
-
+
.metrics-overlay-content-wrapper {
position: relative;
display: block;
@@ -616,23 +653,23 @@ section.instructor-dashboard-content-2 {
border: 1px solid #000;
border-radius: 25px;
padding: 2.5%;
-
+
.metrics-overlay-title {
display: block;
height: 50px;
margin-bottom: 10px;
font-weight: bold;
}
-
+
.metrics-overlay-content {
width: 100%;
height: 370px;
overflow: auto;
border: 1px solid #000;
-
+
table {
width: 100%;
-
+
.header {
background-color: #ddd;
}
@@ -641,18 +678,18 @@ section.instructor-dashboard-content-2 {
}
}
}
-
+
.overflow-message {
padding-top: 20px;
}
-
+
.download-csv {
position: absolute;
display: none;
right: 2%;
bottom: 2%;
}
-
+
.close-button {
position: absolute;
right: 1.5%;
@@ -661,27 +698,27 @@ section.instructor-dashboard-content-2 {
}
}
}
-
+
.stacked-bar-graph-legend {
fill: white;
}
-
+
p.loading {
padding-top: 100px;
text-align: center;
}
-
+
p.nothing {
padding-top: 25px;
}
-
+
h3.attention {
padding: 10px;
border: 1px solid #999;
border-radius: 5px;
margin-top: 25px;
}
-
+
input#graph_reload {
display: none;
}
diff --git a/lms/templates/courseware/instructor_dashboard.html b/lms/templates/courseware/instructor_dashboard.html
index f80a94644a..6ed4f90e02 100644
--- a/lms/templates/courseware/instructor_dashboard.html
+++ b/lms/templates/courseware/instructor_dashboard.html
@@ -1,10 +1,14 @@
+## NOTE: This is the template for the LEGACY instructor dashboard ##
+## We are no longer supporting this file or accepting changes into it. ##
+## Please see lms/templates/instructor for instructor dashboard templates ##
+
<%! from django.utils.translation import ugettext as _ %>
<%! from django.core.urlresolvers import reverse %>
<%inherit file="../main.html" />
<%namespace name='static' file='/static_content.html'/>
-<%block name="pagetitle">${_("Instructor Dashboard")}%block>
+<%block name="pagetitle">${_("Legacy Instructor Dashboard")}%block>
<%block name="nav_skip">#instructor-dashboard-content%block>
<%block name="headextra">
@@ -122,13 +126,19 @@ function goto( mode)
%if studio_url:
${_("View Course in Studio")}
%endif
- %if settings.FEATURES.get('ENABLE_INSTRUCTOR_BETA_DASHBOARD'):
-
${_("Try New Beta Dashboard")}
- %endif
+
${_("Back To Instructor Dashboard")}
+ %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)
+
${_("User requires forum administrator privileges to perform administration tasks. See instructor.")}
${_("Forum Moderators: can edit or delete any post, remove misuse flags, close and re-open threads, endorse "
@@ -686,7 +696,7 @@ function goto( mode)
%for i in range(0,len(metrics_results['section_display_name'])):
diff --git a/lms/templates/instructor/instructor_dashboard_2/instructor_dashboard_2.html b/lms/templates/instructor/instructor_dashboard_2/instructor_dashboard_2.html
index 680db26673..7d4cee28bc 100644
--- a/lms/templates/instructor/instructor_dashboard_2/instructor_dashboard_2.html
+++ b/lms/templates/instructor/instructor_dashboard_2/instructor_dashboard_2.html
@@ -53,35 +53,39 @@
diff --git a/lms/templates/instructor/instructor_dashboard_2/student_admin.html b/lms/templates/instructor/instructor_dashboard_2/student_admin.html
index 1ff3e2727c..93856d6695 100644
--- a/lms/templates/instructor/instructor_dashboard_2/student_admin.html
+++ b/lms/templates/instructor/instructor_dashboard_2/student_admin.html
@@ -1,6 +1,21 @@
<%! from django.utils.translation import ugettext as _ %>
<%page args="section_data"/>
+