From ea92073e0839ec64402a0d1fddbdcf9e1be72102 Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Thu, 30 Jan 2020 11:14:36 -0500 Subject: [PATCH] Limit course outline to a depth of two Previously, we'd show three layers deep (section, subsection, and unit). But now we cut out unit and stop at subsection. AA-17 --- .../sass/features/_course-experience.scss | 100 +++++------------- .../course-outline-fragment.html | 94 +++++----------- .../tests/views/test_course_outline.py | 30 +++--- openedx/features/course_experience/utils.py | 10 -- scripts/thresholds.sh | 2 +- 5 files changed, 71 insertions(+), 165 deletions(-) diff --git a/lms/static/sass/features/_course-experience.scss b/lms/static/sass/features/_course-experience.scss index 391829d899..3f91244b4f 100644 --- a/lms/static/sass/features/_course-experience.scss +++ b/lms/static/sass/features/_course-experience.scss @@ -308,6 +308,35 @@ padding: 0; list-style-type: none; + // Course outline accordion / link + .outline-button { + display: block; + padding: 10px 0 10px 2px; + border: none; + width: 100%; + text-align: left; + margin: 0; + background: none; + cursor: pointer; + + .fa { + color: $blue; + } + + .prerequisites-icon { + margin-right: 0.25rem; + } + + .complete-checkmark { + border: 1px solid $green; + margin-right: $baseline / 2; + border-radius: 100px; + color: white; + background-color: $green; + float: right; + } + } + .section { @include media-breakpoint-up(md) { margin: 0; @@ -346,7 +375,6 @@ display: inline-block; margin: 0; font-weight: $font-regular; - margin-left: $baseline - 2; display: inline; } @@ -354,7 +382,6 @@ .details { font-size: $body-font-size; color: theme-color("secondary"); - margin-left: 34px; } .prerequisite { @@ -362,72 +389,12 @@ font-weight: $font-bold; } } - - .vertical { - @include margin-left(16px); - - list-style-type: none; - - a.outline-item { - display: flex; - justify-content: space-between; - align-items: center; - padding: ($baseline / 2) 0 ($baseline / 2) 0; - margin: 0 0 0 ($baseline); - 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); - border-radius: $btn-border-radius; - text-decoration: none; - } - - .vertical-actions { - .resume-right { - position: relative; - top: calc(50% - (#{$baseline} / 2)); - } - } - } } } } } } -// Course outline accordion -button.accordion-trigger, button.prerequisite-button { - padding: 10px 0 10px 2px; - border: none; - width: 100%; - text-align: left; - margin: 0; - background: none; - cursor: pointer; - - .fa { - color: $blue; - } -} - #expand-collapse-outline-all-button { float: right; background-color: $white; @@ -444,15 +411,6 @@ 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; -} - // date summary .date-summary-container { .date-summary { diff --git a/openedx/features/course_experience/templates/course_experience/course-outline-fragment.html b/openedx/features/course_experience/templates/course_experience/course-outline-fragment.html index 2424162444..2d913abf96 100644 --- a/openedx/features/course_experience/templates/course_experience/course-outline-fragment.html +++ b/openedx/features/course_experience/templates/course_experience/course-outline-fragment.html @@ -35,7 +35,7 @@ self_paced = context.get('self_paced', False) scored = 'scored' if section.get('scored', False) else '' %>
  • - - % if gated_subsection and not completed_prereqs: - - % endif - % if not gated_subsection or (gated_subsection and completed_prereqs): -
      - % for vertical in subsection.get('children', []): - <% - vertical_is_access_denied = vertical.get('authorization_denial_reason') - if vertical_is_access_denied: - continue - scored = 'scored' if vertical.get('scored', False) else '' - access_restricted = list(vertical.get('all_denial_reasons', [])) - %> -
    1. - -
      -
      - ${ vertical['display_name'] } -
      -
      - % if vertical.get('complete'): - - ${_("Completed")} - - % endif -
      -
    2. - % endfor -
    - % 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 68ff1c47a2..88d413a250 100644 --- a/openedx/features/course_experience/tests/views/test_course_outline.py +++ b/openedx/features/course_experience/tests/views/test_course_outline.py @@ -131,8 +131,6 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase): self.assertContains(response, sequential.due.strftime(u'%Y-%m-%d %H:%M:%S')) self.assertContains(response, sequential.format) self.assertTrue(sequential.children) - for vertical in sequential.children: - self.assertContains(response, vertical.display_name) class TestCourseOutlinePageWithPrerequisites(SharedModuleStoreTestCase, MilestonesTestCaseMixin): @@ -318,14 +316,22 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT course = CourseFactory.create() with cls.store.bulk_operations(course.id): chapter = ItemFactory.create(category='chapter', parent_location=course.location) + chapter2 = ItemFactory.create(category='chapter', parent_location=course.location) sequential = ItemFactory.create(category='sequential', parent_location=chapter.location) sequential2 = ItemFactory.create(category='sequential', parent_location=chapter.location) + sequential3 = ItemFactory.create(category='sequential', parent_location=chapter2.location) + sequential4 = ItemFactory.create(category='sequential', parent_location=chapter2.location) vertical = ItemFactory.create(category='vertical', parent_location=sequential.location) vertical2 = ItemFactory.create(category='vertical', parent_location=sequential2.location) - course.children = [chapter] + vertical3 = ItemFactory.create(category='vertical', parent_location=sequential3.location) + vertical4 = ItemFactory.create(category='vertical', parent_location=sequential4.location) + course.children = [chapter, chapter2] chapter.children = [sequential, sequential2] + chapter2.children = [sequential3, sequential4] sequential.children = [vertical] sequential2.children = [vertical2] + sequential3.children = [vertical3] + sequential4.children = [vertical4] if hasattr(cls, 'user'): CourseEnrollment.enroll(cls.user, course.id) return course @@ -407,8 +413,8 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT response = self.client.get(course_home_url(course)) content = pq(response.content) - # vertical and its parent should be checked - self.assertEqual(len(content('.fa-check')), 2) + # Subsection should be checked + self.assertEqual(len(content('.fa-check')), 1) def test_start_course(self): """ @@ -434,7 +440,6 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT # Course tree course = self.course - course_key = CourseKey.from_string(str(course.id)) vertical1 = course.children[0].children[0].children[0] vertical2 = course.children[0].children[1].children[0] @@ -534,9 +539,9 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT ) def test_course_outline_auto_open(self): """ - Tests that the course outline auto-opens to the first unit + Tests that the course outline auto-opens to the first subsection in a course if a user has no completion data, and to the - last-accessed unit if a user does have completion data. + last-accessed subsection if a user does have completion data. """ def get_sequential_button(url, is_hidden): is_hidden_string = "is-hidden" if is_hidden else "" @@ -547,15 +552,14 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT ">" # Course tree course = self.course - chapter = course.children[0] - sequential1 = chapter.children[0] - sequential2 = chapter.children[1] + chapter1 = course.children[0] + chapter2 = course.children[1] response_content = self.client.get(course_home_url(course)).content stripped_response = text_type(re.sub(b"\\s+", b"", response_content), "utf-8") - self.assertTrue(get_sequential_button(text_type(sequential1.location), False) in stripped_response) - self.assertTrue(get_sequential_button(text_type(sequential2.location), True) in stripped_response) + self.assertIn(get_sequential_button(text_type(chapter1.location), False), stripped_response) + self.assertIn(get_sequential_button(text_type(chapter2.location), True), stripped_response) content = pq(response_content) button = content('#expand-collapse-outline-all-button') diff --git a/openedx/features/course_experience/utils.py b/openedx/features/course_experience/utils.py index 221416d6c5..30ecb3cf69 100644 --- a/openedx/features/course_experience/utils.py +++ b/openedx/features/course_experience/utils.py @@ -4,22 +4,12 @@ Common utilities for the course experience, including course outline. from completion.models import BlockCompletion -from django.utils.translation import ugettext as _ from opaque_keys.edx.keys import CourseKey from six.moves import range -from web_fragments.fragment import Fragment from lms.djangoapps.course_api.blocks.api import get_blocks from lms.djangoapps.course_blocks.utils import get_student_module_as_dict -from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link -from openedx.core.djangolib.markup import HTML from openedx.core.lib.cache_utils import request_cached -from openedx.features.discounts.applicability import ( - can_receive_discount, - get_discount_expiration_date, - discount_percentage -) -from openedx.features.discounts.utils import format_strikeout_price from xmodule.modulestore.django import modulestore diff --git a/scripts/thresholds.sh b/scripts/thresholds.sh index fde1c75365..6f8bfb89d4 100755 --- a/scripts/thresholds.sh +++ b/scripts/thresholds.sh @@ -2,6 +2,6 @@ set -e export LOWER_PYLINT_THRESHOLD=1000 -export UPPER_PYLINT_THRESHOLD=2100 +export UPPER_PYLINT_THRESHOLD=2005 export ESLINT_THRESHOLD=5530 export STYLELINT_THRESHOLD=880