From bc87ff310ef1953a88b1c580b16be7dcd66b9544 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 | 20 +++++++++-- cms/djangoapps/contentstore/views/preview.py | 7 +++- .../contentstore/views/tests/test_block.py | 33 +++++++++++++++++++ cms/static/js/views/pages/container.js | 2 +- .../partials/cms/theme/_variables-v1.scss | 2 +- cms/templates/studio_xblock_wrapper.html | 18 +++++----- 6 files changed, 68 insertions(+), 14 deletions(-) diff --git a/cms/djangoapps/contentstore/views/block.py b/cms/djangoapps/contentstore/views/block.py index d018f475d086..896e740fab0b 100644 --- a/cms/djangoapps/contentstore/views/block.py +++ b/cms/djangoapps/contentstore/views/block.py @@ -17,7 +17,7 @@ from edx_django_utils.plugins import pluggable_override from openedx_events.content_authoring.data import DuplicatedXBlockData from openedx_events.content_authoring.signals import XBLOCK_DUPLICATED -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, @@ -417,6 +417,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({ @@ -429,6 +434,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) @@ -1644,4 +1650,14 @@ 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 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/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py index c65e00a0f36a..acd530631d66 100644 --- a/cms/djangoapps/contentstore/views/preview.py +++ b/cms/djangoapps/contentstore/views/preview.py @@ -301,6 +301,10 @@ def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False): can_edit = context.get('can_edit', True) # Copy-paste is a new feature; while we are beta-testing it, only beta users with the Waffle flag enabled see it enable_copy_paste = can_edit and ENABLE_COPY_PASTE_FEATURE.is_enabled() + 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, @@ -314,7 +318,8 @@ def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False): 'selected_groups_label': selected_groups_label, 'can_add': context.get('can_add', True), 'can_move': context.get('can_move', xblock.scope_ids.usage_id.context_key.is_course), - 'language': getattr(course, 'language', None) + 'language': getattr(course, 'language', None), + 'tags_count': tags_count, } add_webpack_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 7f5cbfe2be85..88ffdf0029d4 100644 --- a/cms/djangoapps/contentstore/views/tests/test_block.py +++ b/cms/djangoapps/contentstore/views/tests/test_block.py @@ -16,6 +16,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 @@ -69,6 +70,7 @@ add_container_page_publishing_info, create_xblock_info, ) +from cms.djangoapps.contentstore.toggles import ENABLE_TAGGING_TAXONOMY_LIST_PAGE class AsideTest(XBlockAside): @@ -239,6 +241,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/static/js/views/pages/container.js b/cms/static/js/views/pages/container.js index 5a69482c34c8..fbea10e00349 100644 --- a/cms/static/js/views/pages/container.js +++ b/cms/static/js/views/pages/container.js @@ -24,7 +24,7 @@ function($, _, Backbone, gettext, BasePage, ViewUtils, ContainerView, XBlockView 'click .delete-button': 'deleteXBlock', 'click .show-actions-menu-button': 'showXBlockActionsMenu', 'click .new-component-button': 'scrollToNewComponentButtons', - 'click .tags-button': 'openManageTags', + 'click .manage-tags-button': 'openManageTags', }, options: { diff --git a/cms/static/sass/partials/cms/theme/_variables-v1.scss b/cms/static/sass/partials/cms/theme/_variables-v1.scss index 9dd001d455cc..c35321618537 100644 --- a/cms/static/sass/partials/cms/theme/_variables-v1.scss +++ b/cms/static/sass/partials/cms/theme/_variables-v1.scss @@ -28,7 +28,7 @@ $fg-column: $gw-column; $fg-gutter: $gw-gutter; $fg-max-columns: 12; $fg-max-width: 1280px; -$fg-min-width: 995px; +$fg-min-width: 1005px; // +Fonts // ==================== diff --git a/cms/templates/studio_xblock_wrapper.html b/cms/templates/studio_xblock_wrapper.html index b85ad79fbe4c..fea24c17be4f 100644 --- a/cms/templates/studio_xblock_wrapper.html +++ b/cms/templates/studio_xblock_wrapper.html @@ -86,6 +86,15 @@