Merge pull request #37462 from openedx/feanil/drop_course_outline

feat!: Drop the legacy course_outline page.
This commit is contained in:
Feanil Patel
2025-10-20 11:49:21 -04:00
committed by GitHub
10 changed files with 18 additions and 537 deletions

View File

@@ -116,9 +116,12 @@ class CourseWaffleFlagsSerializer(serializers.Serializer):
def get_use_new_course_outline_page(self, obj):
"""
Method to get the use_new_course_outline_page switch
Always true, because the switch is being removed and the new experience
should always be on. This function will be removed in
https://github.com/openedx/edx-platform/issues/37497
"""
course_key = self.get_course_key()
return toggles.use_new_course_outline_page(course_key)
return True
def get_use_new_unit_page(self, obj):
"""

View File

@@ -1399,33 +1399,6 @@ class ContentStoreTest(ContentStoreTestCase):
item = BlockFactory.create(parent_location=course.location)
self.assertIsInstance(item, SequenceBlock)
@override_waffle_flag(toggles.LEGACY_STUDIO_COURSE_OUTLINE, True)
def test_course_overview_view_with_course(self):
"""Test viewing the course overview page with an existing course"""
course = CourseFactory.create()
resp = self._show_course_overview(course.id)
# course_handler raise 404 for old mongo course
if course.id.deprecated:
self.assertEqual(resp.status_code, 404)
return
assets_url = reverse_course_url(
'assets_handler',
course.location.course_key
)
self.assertContains(
resp,
'<article class="outline outline-complex outline-course" data-locator="{locator}" data-course-key="{course_key}" data-course-assets="{assets_url}" >'.format( # lint-amnesty, pylint: disable=line-too-long
locator=str(course.location),
course_key=str(course.id),
assets_url=assets_url,
),
status_code=200,
html=True
)
def test_create_block(self):
"""Test creating a new xblock instance."""
course = CourseFactory.create()
@@ -1499,8 +1472,7 @@ class ContentStoreTest(ContentStoreTestCase):
)
course_key = course_items[0].id
with override_waffle_flag(toggles.LEGACY_STUDIO_COURSE_OUTLINE, True):
resp = self._show_course_overview(course_key)
resp = self._show_course_overview(course_key)
# course_handler raise 404 for old mongo course
if course_key.deprecated:
@@ -1744,7 +1716,8 @@ class ContentStoreTest(ContentStoreTestCase):
"""
Show the course overview page.
"""
resp = self.client.get_html(get_url('course_handler', course_key, 'course_key_string'))
resp = self.client.get(get_url('course_handler', course_key, 'course_key_string'),
content_type='application/json')
return resp
def test_wiki_slug(self):

View File

@@ -364,13 +364,6 @@ def use_new_video_uploads_page(course_key):
LEGACY_STUDIO_COURSE_OUTLINE = CourseWaffleFlag('legacy_studio.course_outline', __name__)
def use_new_course_outline_page(course_key):
"""
Returns a boolean if new studio course outline mfe is enabled
"""
return not LEGACY_STUDIO_COURSE_OUTLINE.is_enabled(course_key)
# .. toggle_name: legacy_studio.unit_editor
# .. toggle_implementation: WaffleFlag
# .. toggle_default: False

View File

@@ -43,7 +43,6 @@ from cms.djangoapps.contentstore.toggles import (
split_library_view_on_dashboard,
use_new_advanced_settings_page,
use_new_certificates_page,
use_new_course_outline_page,
use_new_course_team_page,
use_new_custom_pages,
use_new_export_page,
@@ -443,13 +442,12 @@ def get_course_outline_url(course_locator, block_to_show=None) -> str:
Gets course authoring microfrontend URL for course oultine page view.
"""
course_outline_url = None
if use_new_course_outline_page(course_locator):
mfe_base_url = get_course_authoring_url(course_locator)
course_mfe_url = f'{mfe_base_url}/course/{course_locator}'
if block_to_show:
course_mfe_url += f'?show={quote_plus(block_to_show)}'
if mfe_base_url:
course_outline_url = course_mfe_url
mfe_base_url = get_course_authoring_url(course_locator)
course_mfe_url = f'{mfe_base_url}/course/{course_locator}'
if block_to_show:
course_mfe_url += f'?show={quote_plus(block_to_show)}'
if mfe_base_url:
course_outline_url = course_mfe_url
return course_outline_url

View File

@@ -90,7 +90,6 @@ from ..courseware_index import CoursewareSearchIndexer, SearchIndexingError
from ..tasks import rerun_course as rerun_course_task
from ..toggles import (
default_enable_flexible_peer_openassessments,
use_new_course_outline_page,
use_new_updates_page,
use_new_advanced_settings_page,
use_new_grading_page,
@@ -102,7 +101,6 @@ from ..utils import (
add_instructor,
get_advanced_settings_url,
get_course_grading,
get_course_index_context,
get_course_outline_url,
get_course_rerun_context,
get_course_settings,
@@ -740,18 +738,8 @@ def course_index(request, course_key):
org, course, name: Attributes of the Location for the item to edit
"""
if use_new_course_outline_page(course_key):
block_to_show = request.GET.get("show")
return redirect(get_course_outline_url(course_key, block_to_show))
with modulestore().bulk_operations(course_key):
# A depth of None implies the whole course. The course outline needs this in order to compute has_changes.
# A unit may not have a draft version, but one of its components could, and hence the unit itself has changes.
course_block = get_course_and_check_access(course_key, request.user, depth=None)
if not course_block:
raise Http404
# should be under bulk_operations if course_block is passed
course_index_context = get_course_index_context(request, course_key, course_block)
return render_to_response('course_outline.html', course_index_context)
block_to_show = request.GET.get("show")
return redirect(get_course_outline_url(course_key, block_to_show))
@function_trace('get_courses_accessible_to_user')

View File

@@ -10,16 +10,12 @@ from unittest import mock, skip
import ddt
import pytz
from django.core.exceptions import PermissionDenied
from django.test.utils import override_settings
from django.utils.translation import gettext as _
from edx_toggles.toggles.testutils import override_waffle_flag
from search.api import perform_search
from cms.djangoapps.contentstore import toggles
from cms.djangoapps.contentstore.courseware_index import CoursewareSearchIndexer, SearchIndexingError
from cms.djangoapps.contentstore.tests.utils import CourseTestCase
from cms.djangoapps.contentstore.utils import (
get_proctored_exam_settings_url,
reverse_course_url,
reverse_usage_url
)
@@ -34,7 +30,6 @@ from ..course import _deprecated_blocks_info, course_outline_initial_state, rein
from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import VisibilityState, create_xblock_info
@override_waffle_flag(toggles.LEGACY_STUDIO_COURSE_OUTLINE, True)
@ddt.ddt
class TestCourseOutline(CourseTestCase):
"""
@@ -226,38 +221,15 @@ class TestCourseOutline(CourseTestCase):
expected_block_types
)
@override_settings(FEATURES={'ENABLE_EXAM_SETTINGS_HTML_VIEW': True})
@mock.patch('cms.djangoapps.models.settings.course_metadata.CourseMetadata.validate_proctoring_settings')
def test_proctoring_link_is_visible(self, mock_validate_proctoring_settings):
"""
Test to check proctored exam settings mfe url is rendering properly
"""
mock_validate_proctoring_settings.return_value = [
{
'key': 'proctoring_provider',
'message': 'error message',
'model': {'display_name': 'proctoring_provider'}
},
{
'key': 'proctoring_provider',
'message': 'error message',
'model': {'display_name': 'proctoring_provider'}
}
]
response = self.client.get_html(reverse_course_url('course_handler', self.course.id))
proctored_exam_settings_url = get_proctored_exam_settings_url(self.course.id)
self.assertContains(response, proctored_exam_settings_url, 2)
def test_number_of_calls_to_db(self):
"""
Test to check number of queries made to mysql and mongo
"""
with self.assertNumQueries(39, table_ignorelist=WAFFLE_TABLES):
with self.assertNumQueries(21, table_ignorelist=WAFFLE_TABLES):
with check_mongo_calls(3):
self.client.get_html(reverse_course_url('course_handler', self.course.id))
self.client.get(reverse_course_url('course_handler', self.course.id), content_type="application/json")
@override_waffle_flag(toggles.LEGACY_STUDIO_COURSE_OUTLINE, True)
class TestCourseReIndex(CourseTestCase):
"""
Unit tests for the course outline.

View File

@@ -24,7 +24,6 @@ from common.djangoapps.util.testing import UrlResetMixin
"ENABLE_PROCTORED_EXAMS": True,
},
)
@override_waffle_flag(toggles.LEGACY_STUDIO_COURSE_OUTLINE, True)
@override_waffle_flag(toggles.LEGACY_STUDIO_CERTIFICATES, True)
@override_waffle_flag(toggles.LEGACY_STUDIO_SCHEDULE_DETAILS, True)
@override_waffle_flag(toggles.LEGACY_STUDIO_CONFIGURATIONS, True)
@@ -93,7 +92,6 @@ class TestExamSettingsView(CourseTestCase, UrlResetMixin):
)
@ddt.data(
"advanced_settings_handler",
"course_handler",
)
def test_exam_settings_alert_with_exam_settings_enabled(self, page_handler):
"""
@@ -130,7 +128,6 @@ class TestExamSettingsView(CourseTestCase, UrlResetMixin):
)
@ddt.data(
"advanced_settings_handler",
"course_handler",
)
@override_waffle_flag(toggles.LEGACY_STUDIO_EXAM_SETTINGS, True)
def test_exam_settings_alert_with_exam_settings_disabled(self, page_handler):
@@ -173,7 +170,6 @@ class TestExamSettingsView(CourseTestCase, UrlResetMixin):
)
@ddt.data(
"advanced_settings_handler",
"course_handler",
)
def test_invalid_provider_alert(self, page_handler):
"""
@@ -198,7 +194,6 @@ class TestExamSettingsView(CourseTestCase, UrlResetMixin):
@ddt.data(
"advanced_settings_handler",
"course_handler",
)
def test_exam_settings_alert_not_shown(self, page_handler):
"""

View File

@@ -1,93 +0,0 @@
"""
Course Header Menu Tests.
"""
from unittest import SkipTest
from django.conf import settings
from django.test.utils import override_settings
from edx_toggles.toggles.testutils import override_waffle_flag
from cms.djangoapps.contentstore import toggles
from cms.djangoapps.contentstore.tests.utils import CourseTestCase
from cms.djangoapps.contentstore.utils import reverse_course_url
from common.djangoapps.util.testing import UrlResetMixin
FEATURES_WITH_CERTS_ENABLED = settings.FEATURES.copy()
FEATURES_WITH_CERTS_ENABLED['CERTIFICATES_HTML_VIEW'] = True
FEATURES_WITH_EXAM_SETTINGS_ENABLED = settings.FEATURES.copy()
FEATURES_WITH_EXAM_SETTINGS_ENABLED['ENABLE_EXAM_SETTINGS_HTML_VIEW'] = True
FEATURES_WITH_EXAM_SETTINGS_DISABLED = settings.FEATURES.copy()
FEATURES_WITH_EXAM_SETTINGS_DISABLED['ENABLE_EXAM_SETTINGS_HTML_VIEW'] = False
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
@override_waffle_flag(toggles.LEGACY_STUDIO_COURSE_OUTLINE, True)
class TestHeaderMenu(CourseTestCase, UrlResetMixin):
"""
Unit tests for the course header menu.
"""
def setUp(self):
"""
Set up the for the course header menu tests.
"""
super().setUp()
self.reset_urls()
def test_header_menu_without_web_certs_enabled(self):
"""
Tests course header menu should not have `Certificates` menu item
if course has not web/HTML certificates enabled.
"""
# course_handler raise 404 for old mongo course
if self.course.id.deprecated:
raise SkipTest("course_handler raise 404 for old mongo course")
self.course.cert_html_view_enabled = False
self.save_course()
outline_url = reverse_course_url('course_handler', self.course.id)
resp = self.client.get(outline_url, HTTP_ACCEPT='text/html')
self.assertEqual(resp.status_code, 200)
self.assertNotContains(resp, '<li class="nav-item nav-course-settings-certificates">')
def test_header_menu_with_web_certs_enabled(self):
"""
Tests course header menu should have `Certificates` menu item
if course has web/HTML certificates enabled.
"""
# course_handler raise 404 for old mongo course
if self.course.id.deprecated:
raise SkipTest("course_handler raise 404 for old mongo course")
outline_url = reverse_course_url('course_handler', self.course.id)
resp = self.client.get(outline_url, HTTP_ACCEPT='text/html')
self.assertEqual(resp.status_code, 200)
self.assertContains(resp, '<li class="nav-item nav-course-settings-certificates">')
@override_settings(FEATURES=FEATURES_WITH_EXAM_SETTINGS_DISABLED)
@override_waffle_flag(toggles.LEGACY_STUDIO_EXAM_SETTINGS, True)
def test_header_menu_without_exam_settings_enabled(self):
"""
Tests course header menu should not have `Exam Settings` menu item
if course does not have the Exam Settings view enabled.
"""
# course_handler raise 404 for old mongo course
if self.course.id.deprecated:
raise SkipTest("course_handler raise 404 for old mongo course")
outline_url = reverse_course_url('course_handler', self.course.id)
resp = self.client.get(outline_url, HTTP_ACCEPT='text/html')
self.assertEqual(resp.status_code, 200)
self.assertNotContains(resp, '<li class="nav-item nav-course-settings-exams">')
@override_settings(FEATURES=FEATURES_WITH_EXAM_SETTINGS_ENABLED)
def test_header_menu_with_exam_settings_enabled(self):
"""
Tests course header menu should have `Exam Settings` menu item
if course does have Exam Settings view enabled.
"""
# course_handler raise 404 for old mongo course
if self.course.id.deprecated:
raise SkipTest("course_handler raise 404 for old mongo course")
outline_url = reverse_course_url('course_handler', self.course.id)
resp = self.client.get(outline_url, HTTP_ACCEPT='text/html')
self.assertEqual(resp.status_code, 200)
self.assertContains(resp, '<li class="nav-item nav-course-settings-exams">')

View File

@@ -1,332 +0,0 @@
<%page expression_filter="h"/>
<%inherit file="base.html" />
<%def name="online_help_token()"><% return "develop_course" %></%def>
<%!
import logging
from six.moves.urllib.parse import quote
from cms.djangoapps.contentstore.config.waffle_utils import should_show_checklists_quality
from common.djangoapps.util.date_utils import get_default_time_display
from django.utils.translation import gettext as _
from openedx.core.djangolib.js_utils import js_escaped_string, dump_js_escaped_json
from openedx.core.djangolib.markup import HTML, Text
from django.urls import reverse
%>
<%block name="title">${_("Course Outline")}</%block>
<%block name="bodyclass">is-signedin course view-outline</%block>
<%namespace name='static' file='static_content.html'/>
<%block name="requirejs">
require(["js/factories/outline"], function (OutlineFactory) {
OutlineFactory(
${course_structure | n, dump_js_escaped_json},
${initial_state | n, dump_js_escaped_json},
${initial_user_clipboard | n, dump_js_escaped_json}
);
});
</%block>
<%block name="header_extras">
<link rel="stylesheet" type="text/css" href="${static.url('js/vendor/timepicker/jquery.timepicker.css')}" />
% for template_name in ['course-outline', 'xblock-string-field-editor', 'basic-modal', 'modal-button', 'course-outline-modal', 'due-date-editor', 'self-paced-due-date-editor', 'release-date-editor', 'grading-editor', 'publish-editor', 'staff-lock-editor', 'unit-access-editor', 'discussion-editor', 'content-visibility-editor', 'verification-access-editor', 'timed-examination-preference-editor', 'access-editor', 'settings-modal-tabs', 'show-correctness-editor', 'highlights-editor', 'highlights-enable-editor', 'course-highlights-enable', 'course-manage-tags', 'course-video-sharing-enable', 'summary-configuration-editor', 'tag-count', 'subsection-share-link-modal-tabs', 'full-page-share-link-editor', 'embed-link-share-link-editor']:
<script type="text/template" id="${template_name}-tpl">
<%static:include path="js/${template_name}.underscore" />
</script>
% endfor
<%static:optional_include_mako file="course_outline_header_extras_post.html" />
% if not settings.STUDIO_FRONTEND_CONTAINER_URL:
<link rel="stylesheet" type="text/css" href="${static.url('common/css/vendor/common.min.css')}" />
<link rel="stylesheet" type="text/css" href="${static.url('common/css/vendor/courseOutlineHealthCheck.min.css')}" />
% endif
</%block>
<%block name="page_alert">
%if notification_dismiss_url is not None:
<div class="wrapper wrapper-alert wrapper-alert-announcement is-shown">
<div class="alert announcement has-actions">
<span class="feedback-symbol fa fa-bullhorn" aria-hidden="true"></span>
<div class="copy">
<h2 class="title title-3">${_("This course was created as a re-run. Some manual configuration is needed.")}</h2>
<p>${_("No course content is currently visible, and no learners are enrolled. Be sure to review and reset all dates, including the Course Start Date; set up the course team; review course updates and other assets for dated material; and seed the discussions and wiki.")}</p>
</div>
<ul class="nav-actions">
<li class="action action-dismiss">
<a href="#" class="button dismiss-button" data-dismiss-link='${notification_dismiss_url}'>
<span class="icon fa fa-times-circle" aria-hidden="true"></span>
<span class="button-copy">${_("Dismiss")}</span>
</a>
</li>
</ul>
</div>
</div>
%endif
%if context_course.discussions_settings.get('provider_type') == "openedx":
<div class="wrapper wrapper-alert wrapper-alert-announcement is-shown" style="background-color:#F0CC00">
<div class="alert announcement has-actions">
<span class="feedback-symbol fa fa-bullhorn" style="color:black" aria-hidden="true"></span>
<div class="copy">
<div style="color:black; display:inline-block">
<div>
${_("This course run is using an upgraded version of edx discussion forum. In order to display the discussions sidebar, discussions xBlocks will no longer be visible to learners.")}
</div>
<div style="margin-left:auto; width:fit-content;">
%if settings.DISCUSSIONS_INCONTEXT_LEARNMORE_URL:
<span>
<a href="${settings.DISCUSSIONS_INCONTEXT_LEARNMORE_URL}" target="_blank" rel="noreferrer noopener">${_(" Learn more")}</a>
<i class="fa fa-share-square-o" aria-hidden="true"></i>
</span>
%endif
%if settings.DISCUSSIONS_INCONTEXT_FEEDBACK_URL:
<span style="margin-left: 1rem">
<a href="${settings.DISCUSSIONS_INCONTEXT_FEEDBACK_URL}" target="_blank" rel="noreferrer noopener">${_("Share feedback")}</a>
<i class="fa fa-share-square-o" aria-hidden="true"></i>
</span>
%endif
</div>
</div>
</div>
<ul class="nav-actions">
<li class="action action-dismiss">
<a href="#" class="button dismiss-button-announcement" style="color:black; border-color:black">
<span class="icon fa fa-times-circle" aria-hidden="true"></span>
<span class="button-copy">${_("Dismiss")}</span>
</a>
</li>
</ul>
</div>
</div>
%endif
%if deprecated_blocks_info.get('blocks') or deprecated_blocks_info.get('deprecated_enabled_block_types'):
<div class="wrapper wrapper-alert wrapper-alert-error is-shown">
<div class="alert announcement">
<span class="feedback-symbol fa fa-warning" aria-hidden="true"></span><span class="sr">${_("Warning")}</span>
<div class="copy">
<h2 class="title title-3 warning-heading-text">${_("This course uses features that are no longer supported.")}</h2>
%if deprecated_blocks_info.get('blocks'):
<div class="components-list">
<p class="components-list-heading-text">${_("You must delete or replace the following components.")}</p>
<nav class="nav-related" aria-label="${_('Unsupported Components')}">
<ul>
% for component_parent_url, component_display_name in deprecated_blocks_info['blocks']:
<li class="nav-item">
% if component_display_name:
<a href="${component_parent_url}">${component_display_name}</a>
% else:
<a href="${component_parent_url}">${_("Deprecated Component")}</a>
% endif
</li>
% endfor
</ul>
</nav>
</div>
%endif
% if deprecated_blocks_info.get('deprecated_enabled_block_types'):
<div class="advance-modules-list">
<p class="advance-modules-remove-text">
${Text(_("To avoid errors, {platform_name} strongly recommends that you remove unsupported features from the course advanced settings. To do this, go to the {link_start}Advanced Settings page{link_end}, locate the \"Advanced Module List\" setting, and then delete the following modules from the list.")).format(
platform_name=static.get_platform_name(),
link_start=HTML('<a href="{advance_settings_url}">').format(advance_settings_url=deprecated_blocks_info['advance_settings_url']),
link_end=HTML("</a>")
)}
</p>
<nav class="nav-related" aria-label="${_('Unsupported Advance Modules')}">
<ul>
% for block_type in deprecated_blocks_info['deprecated_enabled_block_types']:
<li class="nav-item">${block_type}</li>
% endfor
</ul>
</nav>
</div>
% endif
</div>
</div>
</div>
%endif
%if proctoring_errors:
<div class="wrapper wrapper-alert wrapper-alert-error is-shown">
<div class="alert announcement has-actions">
<span class="feedback-symbol fa fa-warning" aria-hidden="true"></span>
<div class="exam-settings-alert copy">
<h2 class="title title-3">${_("This course has proctored exam settings that are incomplete or invalid.")}</h2>
<p>
% if mfe_proctored_exam_settings_url:
<% url_encoded_course_id = quote(str(context_course.id).encode('utf-8'), safe='') %>
${Text(_("To update these settings go to the {link_start}Proctored Exam Settings page{link_end}.")).format(
link_start=HTML('<a href="{mfe_proctored_exam_settings_url}">').format(
mfe_proctored_exam_settings_url=mfe_proctored_exam_settings_url
),
link_end=HTML("</a>")
)}
% else:
${Text(_("To update these settings go to the {link_start}Advanced Settings page{link_end}.")).format(
link_start=HTML('<a href="{advance_settings_url}">').format(advance_settings_url=advance_settings_url),
link_end=HTML("</a>")
)}
% endif
</p>
<div class="errors-list">
<nav class="nav-related" aria-label="${_('Proctoring Settings Errors')}">
<ul>
% for error in proctoring_errors:
<li class="nav-item">
<h3 class="title title-4">${error.get('model', {}).get('display_name')}</h3>
<p>${error.get('message')}</p>
</li>
% endfor
</ul>
</nav>
</div>
</div>
</div>
</div>
%endif
</%block>
<%block name="content">
<div class="wrapper-mast wrapper">
<header class="mast has-actions has-subtitle">
<h1 class="page-header">
<small class="subtitle">${_("Content")}</small>
<span class="sr">&gt; </span>${_("Course Outline")}
</h1>
<nav class="nav-actions" aria-label="${_('Page Actions')}">
<h3 class="sr">${_("Page Actions")}</h3>
<ul>
<li class="nav-item">
<a href="#" class="button button-new" data-category="chapter" data-parent="${context_course.location}" data-default-name="${_('Section')}" title="${_('Click to add a new section')}">
<span class="icon fa fa-plus" aria-hidden="true"></span>${_('New Section')}
</a>
</li>
%if reindex_link:
<li class="nav-item">
<a href="${reindex_link}" class="button button-reindex" data-category="reindex" title="${_('Reindex current course')}">
<span class="icon-arrow-right" aria-hidden="true"></span>${_('Reindex')}
</a>
</li>
%endif
<li class="nav-item">
<a href="#" class="button button-toggle button-toggle-expand-collapse collapse-all is-hidden">
<span class="collapse-all"><span class="icon fa fa-arrow-up" aria-hidden="true"></span> <span class="label">${_("Collapse All Sections")}</span></span>
<span class="expand-all"><span class="icon fa fa-arrow-down" aria-hidden="true"></span> <span class="label">${_("Expand All Sections")}</span></span>
</a>
</li>
<li class="nav-item">
<a href="${lms_link}" rel="external" class="button view-button view-live-button"
title="${_('Click to open the courseware in the LMS in a new tab')}">${_("View Live")}</a>
</li>
</ul>
</nav>
</header>
</div>
<div class="wrapper-content wrapper">
<section class="content">
<article class="content-primary" role="main">
<div class="course-status">
## set width dynamically depending upon whether course has a start date to ensure spacing looks good
% if course_release_date == 'Set Date':
<div style="width: 40%" class="status-studio-frontend">
% else:
<div style="width: 50%" class="status-studio-frontend">
% endif
<%static:studiofrontend entry="courseOutlineHealthCheck">
<%
course_key = context_course.id
%>
{
"lang": "${language_code | n, js_escaped_string}",
"course": {
"id": "${context_course.id | n, js_escaped_string}",
"name": "${context_course.display_name_with_default | n, js_escaped_string}",
"course_release_date": "${course_release_date | n, js_escaped_string}",
"is_course_self_paced": ${context_course.self_paced | n, dump_js_escaped_json},
"url_name": "${context_course.location.block_id | n, js_escaped_string}",
"org": "${context_course.location.org | n, js_escaped_string}",
"num": "${context_course.location.course | n, js_escaped_string}",
"display_course_number": "${context_course.display_coursenumber | n, js_escaped_string}",
"revision": "${context_course.location.branch | n, js_escaped_string}"
},
"help_tokens": {
"files": "${get_online_help_info(online_help_token())['doc_url'] | n, js_escaped_string}"
},
"enable_quality": ${should_show_checklists_quality(context_course.id) | n, dump_js_escaped_json},
"links": {
"settings": ${reverse('settings_handler', kwargs={'course_key_string': str(course_key)})| n, dump_js_escaped_json}
}
}
</%static:studiofrontend>
</div>
<div class="status-highlights-enabled"></div>
<div class="status-manage-tags"></div>
<div class="status-video-sharing-enabled"></div>
</div>
<div class="wrapper-dnd"
% if getattr(context_course, 'language'):
lang="${context_course.language}"
% endif
>
<%
course_locator = context_course.location
assets_url = reverse('assets_handler', kwargs={'course_key_string': str(course_locator.course_key)})
%>
<h2 class="sr">${_("Course Outline")}</h2>
<article class="outline outline-complex outline-course" data-locator="${course_locator}" data-course-key="${course_locator.course_key}" data-course-assets="${assets_url}">
</article>
</div>
<div class="ui-loading">
<p><span class="spin"><span class="icon fa fa-refresh" aria-hidden="true"></span></span> <span class="copy">${_("Loading")}</span></p>
</div>
</article>
<aside class="content-supplementary" role="complementary">
<div class="bit">
<h3 class="title-3">${_("Creating your course organization")}</h3>
<p>${_("You add sections, subsections, and units directly in the outline.")}</p>
<p>${_("Create a section, then add subsections and units. Open a unit to add course components.")}</p>
</div>
<div class="bit">
<h3 class="title-3">${_("Reorganizing your course")}</h3>
<p>${_("Drag sections, subsections, and units to new locations in the outline.")}</p>
<div class="external-help">
<a href="${get_online_help_info('outline')['doc_url']}" rel="noopener" target="_blank" class="button external-help-button">${_("Learn more about the course outline")}</a>
</div>
</div>
<div class="bit">
<h3 class="title-3">${_("Setting release dates and grading policies")}</h3>
<p>${_("Select the Configure icon for a section or subsection to set its release date. When you configure a subsection, you can also set the grading policy and due date.")}</p>
<div class="external-help">
<a href="${get_online_help_info('grading')['doc_url']}" rel="noopener" target="_blank" class="button external-help-button">${_("Learn more about grading policy settings")}</a>
</div>
</div>
<div class="bit">
<h3 class="title-3">${_("Changing the content learners see")}</h3>
<p>${_("To publish draft content, select the Publish icon for a section, subsection, or unit.")}</p>
<p>${Text(_("To make a section, subsection, or unit unavailable to learners, select the Configure icon for that level, then select the appropriate {em_start}Hide{em_end} option. Grades for hidden sections, subsections, and units are not included in grade calculations.")).format(em_start=HTML("<strong>"), em_end=HTML("</strong>"))}</p>
<p>${Text(_("To hide the content of a subsection from learners after the subsection due date has passed, select the Configure icon for a subsection, then select {em_start}Hide content after due date{em_end}. Grades for the subsection remain included in grade calculations.")).format(em_start=HTML("<strong>"), em_end=HTML("</strong>"))}</p>
<div class="external-help">
<a href="${get_online_help_info('visibility')['doc_url']}" rel="noopener" target="_blank" class="button external-help-button">${_("Learn more about content visibility settings")}</a>
</div>
</div>
</aside>
</section>
</div>
<div id="manage-tags-drawer" class="drawer"></div>
<div class="drawer-cover gray-cover"></div>
</%block>

View File

@@ -46,7 +46,6 @@
certificates_url = reverse('certificates_list_handler', kwargs={'course_key_string': str(course_key)})
checklists_url = reverse('checklists_handler', kwargs={'course_key_string': str(course_key)})
pages_and_resources_mfe_enabled = ENABLE_PAGES_AND_RESOURCES_MICROFRONTEND.is_enabled(context_course.id)
course_outline_mfe_enabled = toggles.use_new_course_outline_page(context_course.id)
updates_mfe_enabled = toggles.use_new_updates_page(context_course.id)
files_uploads_mfe_enabled = toggles.use_new_files_uploads_page(context_course.id)
video_upload_mfe_enabled = toggles.use_new_video_uploads_page(context_course.id)
@@ -62,18 +61,10 @@
%>
<h2 class="info-course">
<span class="sr">${_("Current Course:")}</span>
% if not course_outline_mfe_enabled:
<a class="course-link" href="${index_url}">
<span class="course-org">${context_course.display_org_with_default}</span><span class="course-number">${context_course.display_number_with_default}</span>
<span class="course-title" title="${context_course.display_name_with_default}">${context_course.display_name_with_default}</span>
</a>
% endif
% if course_outline_mfe_enabled:
<a class="course-link" href="${get_course_outline_url(course_key)}">
<span class="course-org">${context_course.display_org_with_default}</span><span class="course-number">${context_course.display_number_with_default}</span>
<span class="course-title" title="${context_course.display_name_with_default}">${context_course.display_name_with_default}</span>
</a>
% endif
</h2>
<nav class="nav-course nav-dd ui-left" aria-label="${_('Course')}">
@@ -85,16 +76,9 @@
<div class="wrapper wrapper-nav-sub">
<div class="nav-sub">
<ul>
% if not course_outline_mfe_enabled:
<li class="nav-item nav-course-courseware-outline">
<a href="${index_url}">${_("Outline")}</a>
</li>
% endif
% if course_outline_mfe_enabled:
<li class="nav-item nav-course-courseware-outline">
<a href="${get_course_outline_url(course_key)}">${_("Outline")}</a>
</li>
% endif
% if libraries_v2_enabled:
<li class="nav-item nav-course-courseware-outline">
<a href="${get_course_libraries_url(course_key)}">${_("Libraries")}</a>