diff --git a/lms/static/sass/features/_course-experience.scss b/lms/static/sass/features/_course-experience.scss
index e6442e5f57..1bec52b475 100644
--- a/lms/static/sass/features/_course-experience.scss
+++ b/lms/static/sass/features/_course-experience.scss
@@ -365,8 +365,6 @@
@include margin-left(16px);
list-style-type: none;
- border: 1px solid transparent;
- border-radius: 2px;
a.outline-item {
display: flex;
@@ -377,6 +375,22 @@
border-top: 1px solid $border-color;
}
+ a.outline-item:hover {
+ text-decoration: none;
+
+ .vertical-details {
+ text-decoration: underline;
+ }
+
+ .complete-checkmark {
+ text-decoration: none;
+ }
+ }
+
+ .vertical-details {
+ float:left;
+ }
+
&:hover,
&:focus {
background-color: palette(primary, x-back);
@@ -399,11 +413,11 @@
// Course outline accordion
button.accordion-trigger, button.prerequisite-button {
- margin: 2px;
padding: 10px 0 10px 0;
border: none;
width: 100%;
text-align: left;
+ margin: 0px;
.fa {
color: $blue;
@@ -414,6 +428,15 @@ button.accordion-trigger, button.prerequisite-button {
display: none;
}
+.fa-check.fa.complete-checkmark {
+ border: 1px solid $green;
+ margin-right: $baseline / 2;
+ border-radius: 100px;
+ color: white;
+ background-color: $green;
+ float: right;
+}
+
// Course outline
.course-outline {
.block-tree {
diff --git a/openedx/features/course_experience/templates/course_experience/course-outline-fragment-new.html b/openedx/features/course_experience/templates/course_experience/course-outline-fragment-new.html
index d981f1eac9..5fa0a0d8b2 100644
--- a/openedx/features/course_experience/templates/course_experience/course-outline-fragment-new.html
+++ b/openedx/features/course_experience/templates/course_experience/course-outline-fragment-new.html
@@ -27,6 +27,9 @@ from openedx.core.djangolib.markup import HTML, Text
id="${ section['id'] }">
${ subsection['display_name'] }
- % endif
+ % if subsection.get('complete') and show_visual_progress:
+
+ % endif
+ % endif
## There are behavior differences between rendering of subsections which have
@@ -150,6 +156,9 @@ from openedx.core.djangolib.markup import HTML, Text
${ vertical['display_name'] }
+ % if vertical.get('complete') and show_visual_progress:
+
+ % endif
% endfor
diff --git a/openedx/features/course_experience/tests/views/test_course_outline.py b/openedx/features/course_experience/tests/views/test_course_outline.py
index 34a6a6f700..698d557b60 100644
--- a/openedx/features/course_experience/tests/views/test_course_outline.py
+++ b/openedx/features/course_experience/tests/views/test_course_outline.py
@@ -379,12 +379,13 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT
# first navigate to a sequential to make it the last accessed
chapter = course.children[0]
sequential = chapter.children[0]
+ vertical = sequential.children[0]
self.visit_sequential(course, chapter, sequential)
# check resume course buttons
response = self.visit_course_home(course, resume_count=2)
content = pq(response.content)
- self.assertTrue(content('.action-resume-course').attr('href').endswith('/sequential/' + sequential.url_name))
+ self.assertTrue(content('.action-resume-course').attr('href').endswith('/vertical/' + vertical.url_name))
@override_switch(
'{}.{}'.format(
diff --git a/openedx/features/course_experience/utils.py b/openedx/features/course_experience/utils.py
index 518e91c4f6..2e938d5299 100644
--- a/openedx/features/course_experience/utils.py
+++ b/openedx/features/course_experience/utils.py
@@ -6,7 +6,7 @@ from completion.waffle import visual_progress_enabled
from lms.djangoapps.course_api.blocks.api import get_blocks
from lms.djangoapps.course_blocks.utils import get_student_module_as_dict
-from opaque_keys.edx.keys import CourseKey, UsageKey
+from opaque_keys.edx.keys import CourseKey
from openedx.core.djangoapps.request_cache.middleware import request_cached
from xmodule.modulestore.django import modulestore
@@ -118,26 +118,18 @@ def get_course_outline_block_tree(request, course_id):
course_key = CourseKey.from_string(course_id)
course_usage_key = modulestore().make_course_usage_key(course_key)
- if visual_progress_enabled(course_key=course_key):
- # Deeper query for course tree traversing/marking complete
- # and last completed block
- block_types_filter = [
- 'course',
- 'chapter',
- 'sequential',
- 'vertical',
- 'html',
- 'problem',
- 'video',
- 'discussion'
- ]
- else:
- # Shallower query is sufficient for last accessed block
- block_types_filter = [
- 'course',
- 'chapter',
- 'sequential'
- ]
+ # Deeper query for course tree traversing/marking complete
+ # and last completed block
+ block_types_filter = [
+ 'course',
+ 'chapter',
+ 'sequential',
+ 'vertical',
+ 'html',
+ 'problem',
+ 'video',
+ 'discussion'
+ ]
all_blocks = get_blocks(
request,
course_usage_key,
diff --git a/openedx/features/course_experience/views/course_outline.py b/openedx/features/course_experience/views/course_outline.py
index 7822f6cd11..b95522c709 100644
--- a/openedx/features/course_experience/views/course_outline.py
+++ b/openedx/features/course_experience/views/course_outline.py
@@ -2,7 +2,10 @@
Views to show a course outline.
"""
import re
+import datetime
+import pytz
+from django.contrib.auth.models import User
from django.template.context_processors import csrf
from django.template.loader import render_to_string
from opaque_keys.edx.keys import CourseKey
@@ -10,7 +13,9 @@ from web_fragments.fragment import Fragment
from courseware.courses import get_course_overview_with_access
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
-from openedx.features.course_experience import waffle as waffle
+from openedx.features.course_experience import waffle as course_experience_waffle
+from completion import waffle as completion_waffle
+from student.models import CourseEnrollment
from ..utils import get_course_outline_block_tree
from util.milestones_helpers import get_course_content_milestones
@@ -32,14 +37,19 @@ class CourseOutlineFragmentView(EdxFragmentView):
if not course_block_tree:
return None
+ # TODO: EDUCATOR-2283 Remove 'show_visual_progress' from context
+ # and remove the check for it in the HTML file
+ show_visual_progress = (completion_waffle.visual_progress_enabled(course_key) and
+ self.user_enrolled_after_completion_collection(request.user, course_key))
context = {
'csrf': csrf(request)['csrf_token'],
'course': course_overview,
- 'blocks': course_block_tree
+ 'blocks': course_block_tree,
+ 'show_visual_progress': show_visual_progress
}
# TODO: EDUCATOR-2283 Remove this check when the waffle flag is turned on in production
- if waffle.new_course_outline_enabled(course_key=course_key):
+ if course_experience_waffle.new_course_outline_enabled(course_key=course_key):
xblock_display_names = self.create_xblock_id_and_name_dict(course_block_tree)
gated_content = self.get_content_milestones(request, course_key)
@@ -120,3 +130,23 @@ class CourseOutlineFragmentView(EdxFragmentView):
}
return course_content_milestones
+
+ def user_enrolled_after_completion_collection(self, user, course_key):
+ """
+ Checks that the user has enrolled in the course after 01/24/2018, the date that
+ the completion API began data collection. If the user has enrolled in the course
+ before this date, they may see incomplete collection data. This is a temporary
+ check until all active enrollments are created after the date.
+ """
+ begin_collection_date = datetime.datetime(2018, 01, 24, tzinfo=pytz.utc)
+ user = User.objects.get(username=user)
+ user_enrollment = CourseEnrollment.objects.get(
+ user=user,
+ course_id=course_key,
+ is_active=True
+ )
+
+ if user_enrollment and user_enrollment.created > begin_collection_date:
+ return True
+
+ return False