From 90879d167f26bc6af47d1c5bec9c7d9dadc7b00e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Ch=C3=A1vez?= Date: Fri, 12 Jan 2024 12:35:23 -0500 Subject: [PATCH] feat: Tag count in components on Studio Unit page(#33928) --- cms/djangoapps/contentstore/views/block.py | 13 ++++++-- cms/djangoapps/contentstore/views/preview.py | 7 +++- .../contentstore/views/tests/test_block.py | 33 +++++++++++++++++++ .../xblock_storage_handlers/view_handlers.py | 4 +-- .../xblock_storage_handlers/xblock_helpers.py | 11 +++++++ cms/static/js/views/pages/container.js | 2 +- cms/templates/studio_xblock_wrapper.html | 11 ++++++- .../core/djangoapps/content_tagging/api.py | 1 + 8 files changed, 75 insertions(+), 7 deletions(-) diff --git a/cms/djangoapps/contentstore/views/block.py b/cms/djangoapps/contentstore/views/block.py index 91078ccd11c6..8d157c66c45b 100644 --- a/cms/djangoapps/contentstore/views/block.py +++ b/cms/djangoapps/contentstore/views/block.py @@ -28,7 +28,7 @@ from xmodule.modulestore.django import ( modulestore, ) # lint-amnesty, pylint: disable=wrong-import-order - +from cms.djangoapps.contentstore.toggles import use_tagging_taxonomy_list_page from xmodule.x_module import ( AUTHOR_VIEW, @@ -51,7 +51,10 @@ get_xblock, delete_orphans, ) -from cms.djangoapps.contentstore.xblock_storage_handlers.xblock_helpers import usage_key_with_run +from cms.djangoapps.contentstore.xblock_storage_handlers.xblock_helpers import ( + usage_key_with_run, + get_children_tags_count, +) __all__ = [ @@ -230,6 +233,11 @@ def xblock_view_handler(request, usage_key_string, view_name): force_render = request.GET.get("force_render", None) + # Fetch tags of children components + tags_count_map = {} + if use_tagging_taxonomy_list_page(): + tags_count_map = get_children_tags_count(xblock) + # Set up the context to be passed to each XBlock's render method. context = request.GET.dict() context.update( @@ -245,6 +253,7 @@ def xblock_view_handler(request, usage_key_string, view_name): "paging": paging, "force_render": force_render, "item_url": "/container/{usage_key}", + "tags_count_map": tags_count_map, } ) fragment = get_preview_fragment(request, xblock, context) diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py index acab35471813..a897a38ad21a 100644 --- a/cms/djangoapps/contentstore/views/preview.py +++ b/cms/djangoapps/contentstore/views/preview.py @@ -302,6 +302,10 @@ def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False): can_edit = context.get('can_edit', True) # Is this a course or a library? is_course = xblock.scope_ids.usage_id.context_key.is_course + tags_count_map = context.get('tags_count_map') + tags_count = 0 + if tags_count_map: + tags_count = tags_count_map.get(str(xblock.location), 0) template_context = { 'xblock_context': context, 'xblock': xblock, @@ -318,7 +322,8 @@ def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False): 'can_add': context.get('can_add', True), 'can_move': context.get('can_move', is_course), 'language': getattr(course, 'language', None), - 'is_course': is_course + 'is_course': is_course, + 'tags_count': tags_count, } add_webpack_js_to_fragment(frag, "js/factories/xblock_validation") diff --git a/cms/djangoapps/contentstore/views/tests/test_block.py b/cms/djangoapps/contentstore/views/tests/test_block.py index a90187ef605d..ac86961b2293 100644 --- a/cms/djangoapps/contentstore/views/tests/test_block.py +++ b/cms/djangoapps/contentstore/views/tests/test_block.py @@ -17,6 +17,7 @@ from openedx_events.content_authoring.signals import XBLOCK_DUPLICATED from openedx_events.tests.utils import OpenEdxEventsTestMixin from edx_proctoring.exceptions import ProctoredExamNotFoundException +from edx_toggles.toggles.testutils import override_waffle_flag from opaque_keys import InvalidKeyError from opaque_keys.edx.asides import AsideUsageKeyV2 from opaque_keys.edx.keys import CourseKey, UsageKey @@ -83,6 +84,7 @@ add_container_page_publishing_info, create_xblock_info, ) +from cms.djangoapps.contentstore.toggles import ENABLE_TAGGING_TAXONOMY_LIST_PAGE class AsideTest(XBlockAside): @@ -269,6 +271,37 @@ def test_get_container_nested_container_fragment(self): ), ) + @override_waffle_flag(ENABLE_TAGGING_TAXONOMY_LIST_PAGE, True) + @patch("cms.djangoapps.contentstore.xblock_storage_handlers.xblock_helpers.get_object_tag_counts") + def test_tag_count_in_container_fragment(self, mock_get_object_tag_counts): + root_usage_key = self._create_vertical() + + # Add a problem beneath a child vertical + child_vertical_usage_key = self._create_vertical( + parent_usage_key=root_usage_key + ) + resp = self.create_xblock( + parent_usage_key=child_vertical_usage_key, + category="problem", + boilerplate="multiplechoice.yaml", + ) + self.assertEqual(resp.status_code, 200) + usage_key = self.response_usage_key(resp) + + # Get the preview HTML without tags + mock_get_object_tag_counts.return_value = {} + html, __ = self._get_container_preview(root_usage_key) + self.assertIn("wrapper-xblock", html) + self.assertNotIn('data-testid="tag-count-button"', html) + + # Get the preview HTML with tags + mock_get_object_tag_counts.return_value = { + str(usage_key): 13 + } + html, __ = self._get_container_preview(root_usage_key) + self.assertIn("wrapper-xblock", html) + self.assertIn('data-testid="tag-count-button"', html) + def test_split_test(self): """ Test that a split_test block renders all of its children in Studio. diff --git a/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py b/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py index f94b43d3e758..eb79181c4659 100644 --- a/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py +++ b/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py @@ -19,7 +19,7 @@ from django.http import HttpResponse, HttpResponseBadRequest from django.utils.translation import gettext as _ from edx_django_utils.plugins import pluggable_override -from openedx_tagging.core.tagging import api as tagging_api +from openedx.core.djangoapps.content_tagging.api import get_object_tag_counts from edx_proctoring.api import ( does_backend_support_onboarding, get_exam_by_content_id, @@ -1249,7 +1249,7 @@ def _get_course_unit_tags(course_key) -> dict: # Create a pattern to match the IDs of the units, e.g. "block-v1:org+course+run+type@vertical+block@*" vertical_key = course_key.make_usage_key('vertical', 'x') unit_key_pattern = str(vertical_key).rsplit("@", 1)[0] + "@*" - return tagging_api.get_object_tag_counts(unit_key_pattern) + return get_object_tag_counts(unit_key_pattern, count_implicit=True) def _was_xblock_ever_exam_linked_with_external(course, xblock): diff --git a/cms/djangoapps/contentstore/xblock_storage_handlers/xblock_helpers.py b/cms/djangoapps/contentstore/xblock_storage_handlers/xblock_helpers.py index 3205b79a8887..7e589405a1c2 100644 --- a/cms/djangoapps/contentstore/xblock_storage_handlers/xblock_helpers.py +++ b/cms/djangoapps/contentstore/xblock_storage_handlers/xblock_helpers.py @@ -4,6 +4,7 @@ from opaque_keys.edx.keys import UsageKey from xmodule.modulestore.django import modulestore +from openedx.core.djangoapps.content_tagging.api import get_object_tag_counts def usage_key_with_run(usage_key_string): @@ -13,3 +14,13 @@ def usage_key_with_run(usage_key_string): usage_key = UsageKey.from_string(usage_key_string) usage_key = usage_key.replace(course_key=modulestore().fill_in_run(usage_key.course_key)) return usage_key + + +def get_children_tags_count(xblock): + """ + Returns a map with tag count of each child + """ + children = xblock.get_children() + child_usage_keys = [str(child.location) for child in children] + tags_count_query = ','.join(child_usage_keys) + return get_object_tag_counts(tags_count_query, count_implicit=True) diff --git a/cms/static/js/views/pages/container.js b/cms/static/js/views/pages/container.js index cea6eb856bd3..783133af21be 100644 --- a/cms/static/js/views/pages/container.js +++ b/cms/static/js/views/pages/container.js @@ -32,7 +32,7 @@ function($, _, Backbone, gettext, BasePage, 'click .new-component-button': 'scrollToNewComponentButtons', 'click .save-button': 'saveSelectedLibraryComponents', 'click .paste-component-button': 'pasteComponent', - 'click .tags-button': 'openManageTags', + 'click .manage-tags-button': 'openManageTags', 'change .header-library-checkbox': 'toggleLibraryComponent', 'click .collapse-button': 'collapseXBlock', }, diff --git a/cms/templates/studio_xblock_wrapper.html b/cms/templates/studio_xblock_wrapper.html index 63ff93d41a1b..328a0a37e90d 100644 --- a/cms/templates/studio_xblock_wrapper.html +++ b/cms/templates/studio_xblock_wrapper.html @@ -99,6 +99,15 @@