From e007a9ab7788913b7815a4da5ad2077b92861147 Mon Sep 17 00:00:00 2001 From: alenkadev Date: Fri, 24 Jul 2026 09:34:04 +0000 Subject: [PATCH] feat: Update Xpert Summary frontend widget and location --- lms/djangoapps/courseware/block_render.py | 8 +++++- lms/djangoapps/lms_xblock/runtime.py | 33 +++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/courseware/block_render.py b/lms/djangoapps/courseware/block_render.py index de92692ce4fc..4317af8d8c5d 100644 --- a/lms/djangoapps/courseware/block_render.py +++ b/lms/djangoapps/courseware/block_render.py @@ -66,7 +66,12 @@ from lms.djangoapps.courseware.services import UserStateService from lms.djangoapps.grades.api import GradesUtilService from lms.djangoapps.lms_xblock.field_data import LmsFieldData -from lms.djangoapps.lms_xblock.runtime import UserTagsService, lms_wrappers_aside, lms_applicable_aside_types +from lms.djangoapps.lms_xblock.runtime import ( + UserTagsService, + lms_applicable_aside_types, + lms_layout_asides, + lms_wrappers_aside, +) from lms.djangoapps.verify_student.services import XBlockVerificationService from openedx.core.djangoapps.bookmarks.api import BookmarksService from openedx.core.djangoapps.crawlers.models import CrawlersConfig @@ -644,6 +649,7 @@ def inner_get_block(block: XBlock) -> XBlock | None: runtime.request_token = request_token runtime.wrap_asides_override = lms_wrappers_aside runtime.applicable_aside_types_override = lms_applicable_aside_types + runtime.layout_asides_override = partial(lms_layout_asides, wrap_aside=runtime.wrap_aside) def load_single_xblock(request, user_id, course_id, usage_key_string, course=None, will_recheck_access=False): diff --git a/lms/djangoapps/lms_xblock/runtime.py b/lms/djangoapps/lms_xblock/runtime.py index c902bf8c35fe..0e54fd4d368c 100644 --- a/lms/djangoapps/lms_xblock/runtime.py +++ b/lms/djangoapps/lms_xblock/runtime.py @@ -4,6 +4,7 @@ from django.conf import settings from django.urls import reverse +from web_fragments.fragment import Fragment from lms.djangoapps.lms_xblock.models import XBlockAsidesConfig from openedx.core.djangoapps.user_api.course_tag import api as user_course_tag_api @@ -129,6 +130,38 @@ def lms_applicable_aside_types(block, applicable_aside_types=None): ] +def lms_layout_asides(block, context, frag, view_name, aside_frag_fns, wrap_aside=None): + """ + Custom aside layout for the LMS. + + XBlock's default `layout_asides` (xblock.runtime.Runtime.layout_asides) renders + aside content after the block's own content. summaryhook_aside (the Xpert Unit + Summary button) renders before instead; every other aside keeps the default + after-block placement. + """ + before_content = [] + after_content = [] + + result = Fragment() + + for aside, aside_fn in aside_frag_fns: + aside_frag = wrap_aside(block, aside, view_name, aside_fn(block, context), context) + aside.save() + result.add_fragment_resources(aside_frag) + + if aside.scope_ids.block_type == 'summaryhook_aside': + before_content.append(aside_frag.content) + else: + after_content.append(aside_frag.content) + + result.add_content(''.join(before_content)) + result.add_content(frag.content) + result.add_fragment_resources(frag) + result.add_content(''.join(after_content)) + + return result + + class UserTagsService: """ A runtime class that provides an interface to the user service. It handles filling in