Commit 8778608b by Dennis Jen Committed by GitHub

Merge pull request #685 from edx/dsjen/passing-learners

Add passing learners column and put behind feature flag.
parents 538e9add 7c3de64f
...@@ -33,6 +33,7 @@ services: ...@@ -33,6 +33,7 @@ services:
ENABLE_ERROR_PAGE_TESTS: "False" ENABLE_ERROR_PAGE_TESTS: "False"
DISPLAY_LEARNER_ANALYTICS: "True" DISPLAY_LEARNER_ANALYTICS: "True"
ENABLE_COURSE_LIST_FILTERS: "True" ENABLE_COURSE_LIST_FILTERS: "True"
ENABLE_COURSE_LIST_PASSING: "True"
depends_on: depends_on:
- "es" - "es"
- "analyticsapi" - "analyticsapi"
...@@ -47,6 +47,9 @@ endif ...@@ -47,6 +47,9 @@ endif
ifeq ("${ENABLE_COURSE_LIST_FILTERS}", "True") ifeq ("${ENABLE_COURSE_LIST_FILTERS}", "True")
./manage.py waffle_switch enable_course_filters on --create ./manage.py waffle_switch enable_course_filters on --create
endif endif
ifeq ("${ENABLE_COURSE_LIST_PASSING}", "True")
./manage.py waffle_switch enable_course_passing on --create
endif
./manage.py create_acceptance_test_soapbox_messages ./manage.py create_acceptance_test_soapbox_messages
nosetests -v acceptance_tests -e NUM_PROCESSES=1 --exclude-dir=acceptance_tests/course_validation nosetests -v acceptance_tests -e NUM_PROCESSES=1 --exclude-dir=acceptance_tests/course_validation
./manage.py delete_acceptance_test_soapbox_messages ./manage.py delete_acceptance_test_soapbox_messages
......
...@@ -244,6 +244,7 @@ when executing either of the commands above. ...@@ -244,6 +244,7 @@ when executing either of the commands above.
| ENABLE_OAUTH_TESTS | Test the OAUTH sign-in process | true | | ENABLE_OAUTH_TESTS | Test the OAUTH sign-in process | true |
| ENABLE_AUTO_AUTH | Sign-in using auto-auth. (no LMS involved) | false | | ENABLE_AUTO_AUTH | Sign-in using auto-auth. (no LMS involved) | false |
| ENABLE_COURSE_LIST_FILTERS | Tests on filtering the course list | false | | ENABLE_COURSE_LIST_FILTERS | Tests on filtering the course list | false |
| ENABLE_COURSE_LIST_PASSING | Tests on the passing learners column in the course list | false |
Override example: Override example:
......
...@@ -79,8 +79,9 @@ ENABLE_VIDEO_PREVIEW = str2bool(os.environ.get('ENABLE_VIDEO_PREVIEW', False)) ...@@ -79,8 +79,9 @@ ENABLE_VIDEO_PREVIEW = str2bool(os.environ.get('ENABLE_VIDEO_PREVIEW', False))
# Learner analytics # Learner analytics
DISPLAY_LEARNER_ANALYTICS = str2bool(os.environ.get('DISPLAY_LEARNER_ANALYTICS', False)) DISPLAY_LEARNER_ANALYTICS = str2bool(os.environ.get('DISPLAY_LEARNER_ANALYTICS', False))
# Learner analytics # Course listing
ENABLE_COURSE_LIST_FILTERS = str2bool(os.environ.get('ENABLE_COURSE_LIST_FILTERS', False)) ENABLE_COURSE_LIST_FILTERS = str2bool(os.environ.get('ENABLE_COURSE_LIST_FILTERS', False))
ENABLE_COURSE_LIST_PASSING = str2bool(os.environ.get('ENABLE_COURSE_LIST_PASSING', False))
# Soapbox Messages tests constants # Soapbox Messages tests constants
SOAPBOX_GLOBAL_MESSAGE = 'Test global message' SOAPBOX_GLOBAL_MESSAGE = 'Test global message'
......
...@@ -5,6 +5,7 @@ from selenium.webdriver.common.keys import Keys ...@@ -5,6 +5,7 @@ from selenium.webdriver.common.keys import Keys
from acceptance_tests import ( from acceptance_tests import (
ENABLE_COURSE_LIST_FILTERS, ENABLE_COURSE_LIST_FILTERS,
ENABLE_COURSE_LIST_PASSING,
TEST_COURSE_ID, TEST_COURSE_ID,
) )
from acceptance_tests.mixins import AnalyticsDashboardWebAppTestMixin, AnalyticsApiClientMixin from acceptance_tests.mixins import AnalyticsDashboardWebAppTestMixin, AnalyticsApiClientMixin
...@@ -47,8 +48,11 @@ class CourseIndexTests(AnalyticsApiClientMixin, AnalyticsDashboardWebAppTestMixi ...@@ -47,8 +48,11 @@ class CourseIndexTests(AnalyticsApiClientMixin, AnalyticsDashboardWebAppTestMixi
'Total Enrollment \nclick to sort', 'Total Enrollment \nclick to sort',
'Current Enrollment \nclick to sort', 'Current Enrollment \nclick to sort',
'Change Last Week \nclick to sort', 'Change Last Week \nclick to sort',
'Verified Enrollment \nclick to sort' 'Verified Enrollment \nclick to sort',
] ]
if ENABLE_COURSE_LIST_PASSING:
columns.append('Passing Learners \nclick to sort')
self.assertTable('.course-list-table', columns) self.assertTable('.course-list-table', columns)
# Validate that we have a list of courses # Validate that we have a list of courses
......
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-05 13:57+0000\n" "POT-Creation-Date: 2017-06-07 12:34-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
...@@ -54,8 +54,8 @@ msgid "" ...@@ -54,8 +54,8 @@ msgid ""
msgstr "" msgstr ""
#: core/templates/core/landing.html:49 #: core/templates/core/landing.html:49
#: courses/tests/test_views/test_engagement.py:44 courses/views/__init__.py:304 #: courses/tests/test_views/test_engagement.py:44
#: courses/views/__init__.py:554 #: courses/views/__init__.py:304 courses/views/__init__.py:554
msgid "Engagement" msgid "Engagement"
msgstr "" msgstr ""
...@@ -1006,13 +1006,13 @@ msgid "Gender" ...@@ -1006,13 +1006,13 @@ msgid "Gender"
msgstr "" msgstr ""
#. Translators: Content as in course content (e.g. things, not the feeling) #. Translators: Content as in course content (e.g. things, not the feeling)
#: courses/tests/test_views/test_engagement.py:62 courses/views/__init__.py:561 #: courses/tests/test_views/test_engagement.py:62
#: courses/views/engagement.py:27 #: courses/views/__init__.py:561 courses/views/engagement.py:27
msgid "Content" msgid "Content"
msgstr "" msgstr ""
#: courses/tests/test_views/test_engagement.py:73 courses/views/__init__.py:574 #: courses/tests/test_views/test_engagement.py:73
#: courses/views/engagement.py:36 #: courses/views/__init__.py:574 courses/views/engagement.py:36
msgid "Videos" msgid "Videos"
msgstr "" msgstr ""
......
...@@ -47,8 +47,6 @@ class CourseIndex(CourseAPIMixin, LoginRequiredMixin, TrackedViewMixin, LastUpda ...@@ -47,8 +47,6 @@ class CourseIndex(CourseAPIMixin, LoginRequiredMixin, TrackedViewMixin, LastUpda
# The user is probably not a course administrator and should not be using this application. # The user is probably not a course administrator and should not be using this application.
raise PermissionDenied raise PermissionDenied
enable_course_filters = switch_is_active('enable_course_filters')
summaries_presenter = CourseSummariesPresenter() summaries_presenter = CourseSummariesPresenter()
summaries, last_updated = summaries_presenter.get_course_summaries(courses) summaries, last_updated = summaries_presenter.get_course_summaries(courses)
...@@ -56,9 +54,11 @@ class CourseIndex(CourseAPIMixin, LoginRequiredMixin, TrackedViewMixin, LastUpda ...@@ -56,9 +54,11 @@ class CourseIndex(CourseAPIMixin, LoginRequiredMixin, TrackedViewMixin, LastUpda
'update_message': self.get_last_updated_message(last_updated) 'update_message': self.get_last_updated_message(last_updated)
}) })
enable_course_filters = switch_is_active('enable_course_filters')
data = { data = {
'course_list_json': summaries, 'course_list_json': summaries,
'enable_course_filters': enable_course_filters, 'enable_course_filters': enable_course_filters,
'enable_passing_users': switch_is_active('enable_course_passing'),
'course_list_download_url': reverse('courses:index_csv'), 'course_list_download_url': reverse('courses:index_csv'),
} }
......
...@@ -54,7 +54,8 @@ define(function(require) { ...@@ -54,7 +54,8 @@ define(function(require) {
// Will be filled in dynamically by the initialize() function from the programsCollection models: // Will be filled in dynamically by the initialize() function from the programsCollection models:
program_ids: {} program_ids: {}
}, },
programsCollection: programsCollection programsCollection: programsCollection,
passingUsersEnabled: this.options.passingUsersEnabled
}); });
rootView = new RootView({ rootView = new RootView({
......
...@@ -7,7 +7,8 @@ require(['vendor/domReady!', 'jquery', 'load/init-page', ...@@ -7,7 +7,8 @@ require(['vendor/domReady!', 'jquery', 'load/init-page',
courseListJson: modelData.get('course_list_json'), courseListJson: modelData.get('course_list_json'),
programsJson: modelData.get('programs_json'), programsJson: modelData.get('programs_json'),
courseListDownloadUrl: modelData.get('course_list_download_url'), courseListDownloadUrl: modelData.get('course_list_download_url'),
filteringEnabled: modelData.get('enable_course_filters') filteringEnabled: modelData.get('enable_course_filters'),
passingUsersEnabled: modelData.get('enable_passing_users')
}); });
app.start(); app.start();
......
...@@ -29,6 +29,7 @@ define(function(require) { ...@@ -29,6 +29,7 @@ define(function(require) {
pacing_type: Math.random() > 0.5 ? 'instructor_paced' : 'self_paced', pacing_type: Math.random() > 0.5 ? 'instructor_paced' : 'self_paced',
count: count, count: count,
cumulative_count: parseInt(count + (count / 2), 10), cumulative_count: parseInt(count + (count / 2), 10),
passing_users: 0,
enrollment_modes: { enrollment_modes: {
audit: { audit: {
count: 0, count: 0,
......
...@@ -82,6 +82,10 @@ define(function(require) { ...@@ -82,6 +82,10 @@ define(function(require) {
this.registerSortableField('count_change_7_days', gettext('Change Last Week')); this.registerSortableField('count_change_7_days', gettext('Change Last Week'));
this.registerSortableField('verified_enrollment', gettext('Verified Enrollment')); this.registerSortableField('verified_enrollment', gettext('Verified Enrollment'));
if (options.passingUsersEnabled) {
this.registerSortableField('passing_users', gettext('Passing Learners'));
}
this.registerFilterableField('availability', gettext('Availability')); this.registerFilterableField('availability', gettext('Availability'));
this.registerFilterableField('pacing_type', gettext('Pacing Type')); this.registerFilterableField('pacing_type', gettext('Pacing Type'));
this.registerFilterableArrayField('program_ids', gettext('Programs')); this.registerFilterableArrayField('program_ids', gettext('Programs'));
......
...@@ -21,6 +21,7 @@ define(function(require) { ...@@ -21,6 +21,7 @@ define(function(require) {
cumulative_count: 0, cumulative_count: 0,
count_change_7_days: 0, count_change_7_days: 0,
verified_enrollment: 0, verified_enrollment: 0,
passing_users: 0,
enrollment_modes: { enrollment_modes: {
audit: { audit: {
count: 0, count: 0,
......
...@@ -19,6 +19,7 @@ define(function(require) { ...@@ -19,6 +19,7 @@ define(function(require) {
cumulative_count: 0, cumulative_count: 0,
count_change_7_days: 0, count_change_7_days: 0,
verified_enrollment: 0, verified_enrollment: 0,
passing_users: 0,
enrollment_modes: { enrollment_modes: {
audit: { audit: {
count: 0, count: 0,
......
...@@ -15,7 +15,8 @@ define(function(require) { ...@@ -15,7 +15,8 @@ define(function(require) {
count: gettext('Learners currently enrolled in the course.'), count: gettext('Learners currently enrolled in the course.'),
count_change_7_days: gettext('Net difference in current enrollment in the last week.'), count_change_7_days: gettext('Net difference in current enrollment in the last week.'),
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
verified_enrollment: gettext('Number of currently enrolled learners pursuing a verified certificate of achievement.') verified_enrollment: gettext('Number of currently enrolled learners pursuing a verified certificate of achievement.'),
passing_users: gettext('Learners who have earned a passing grade.')
} }
}); });
......
...@@ -50,7 +50,9 @@ define(function(require) { ...@@ -50,7 +50,9 @@ define(function(require) {
defaultOptions.programCollectionOptions defaultOptions.programCollectionOptions
); );
if (defaultOptions.collectionOptions === undefined) { if (defaultOptions.collectionOptions === undefined) {
defaultOptions.collectionOptions = {}; defaultOptions.collectionOptions = {
passingUsersEnabled: true
};
} }
defaultOptions.collectionOptions.programsCollection = programsCollection; defaultOptions.collectionOptions.programsCollection = programsCollection;
...@@ -63,6 +65,7 @@ define(function(require) { ...@@ -63,6 +65,7 @@ define(function(require) {
cumulative_count: 20, cumulative_count: 20,
count_change_7_days: 30, count_change_7_days: 30,
verified_enrollment: 40, verified_enrollment: 40,
passing_users: 50,
start_date: '2015-02-17T050000', start_date: '2015-02-17T050000',
end_date: '2015-03-31T000000' end_date: '2015-03-31T000000'
}), }),
...@@ -73,6 +76,7 @@ define(function(require) { ...@@ -73,6 +76,7 @@ define(function(require) {
cumulative_count: 1000, cumulative_count: 1000,
count_change_7_days: -10, count_change_7_days: -10,
verified_enrollment: 1000, verified_enrollment: 1000,
passing_users: 2000,
start_date: '2016-11-17T050000', start_date: '2016-11-17T050000',
end_date: '2016-12-01T000000' end_date: '2016-12-01T000000'
})], })],
...@@ -127,6 +131,8 @@ define(function(require) { ...@@ -127,6 +131,8 @@ define(function(require) {
Utils.localizeNumber(course.get('count_change_7_days'))); Utils.localizeNumber(course.get('count_change_7_days')));
expect($(tr).find('td.verified_enrollment')).toContainText( expect($(tr).find('td.verified_enrollment')).toContainText(
Utils.localizeNumber(course.get('verified_enrollment'))); Utils.localizeNumber(course.get('verified_enrollment')));
expect($(tr).find('td.passing_users')).toContainText(
Utils.localizeNumber(course.get('passing_users')));
}); });
}); });
...@@ -202,6 +208,22 @@ define(function(require) { ...@@ -202,6 +208,22 @@ define(function(require) {
}); });
}); });
describe('passingUsersEnabled setting', function() {
it('shows column', function() {
var view = getCourseListView({
collectionOptions: {passingUsersEnabled: true}
});
expect(view.$('.passing_users')).toContainText('Passing Learners');
});
it('hides column', function() {
var view = getCourseListView({
collectionOptions: {passingUsersEnabled: false}
});
expect(view.$('.passing_users')).not.toBeInDOM();
});
});
describe('sorting', function() { describe('sorting', function() {
var clickSortingHeader, var clickSortingHeader,
executeSortTest, executeSortTest,
...@@ -264,7 +286,8 @@ define(function(require) { ...@@ -264,7 +286,8 @@ define(function(require) {
cumulative_count: ['cumulative_count'], cumulative_count: ['cumulative_count'],
count: ['count'], count: ['count'],
count_change_7_days: ['count_change_7_days'], count_change_7_days: ['count_change_7_days'],
verified_enrollment: ['verified_enrollment'] verified_enrollment: ['verified_enrollment'],
passing_users: ['passing_users']
}, function(column, isInitial) { }, function(column, isInitial) {
this.column = column; this.column = column;
this.isInitial = isInitial; this.isInitial = isInitial;
......
...@@ -15,7 +15,7 @@ define(function(require) { ...@@ -15,7 +15,7 @@ define(function(require) {
notAvailableTemplate = require('text!course-list/list/templates/table-data-not-available.underscore'), notAvailableTemplate = require('text!course-list/list/templates/table-data-not-available.underscore'),
Utils = require('utils/utils'), Utils = require('utils/utils'),
INTEGER_COLUMNS = ['count', 'cumulative_count', 'count_change_7_days', 'verified_enrollment'], INTEGER_COLUMNS = ['count', 'cumulative_count', 'count_change_7_days', 'verified_enrollment', 'passing_users'],
DATE_COLUMNS = ['start_date', 'end_date'], DATE_COLUMNS = ['start_date', 'end_date'],
CourseListTableView; CourseListTableView;
......
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