Merge pull request #37462 from openedx/feanil/drop_course_outline
feat!: Drop the legacy course_outline page.
This commit is contained in:
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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">')
|
||||
@@ -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">> </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>
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user