feat: Tag count in components on Studio Unit page(#33928)
This commit is contained in:
@@ -28,7 +28,7 @@ from openedx.core.lib.xblock_utils import (
|
||||
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 @@ from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import (
|
||||
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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -17,6 +17,7 @@ from openedx_events.content_authoring.data import DuplicatedXBlockData
|
||||
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 @@ from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import (
|
||||
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 @@ class GetItemTest(ItemTest):
|
||||
),
|
||||
)
|
||||
|
||||
@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.
|
||||
|
||||
@@ -19,7 +19,7 @@ from django.core.exceptions import PermissionDenied
|
||||
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):
|
||||
|
||||
@@ -4,6 +4,7 @@ general helper functions for xblocks
|
||||
|
||||
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)
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
|
||||
@@ -99,6 +99,15 @@ block_is_unit = is_unit(xblock)
|
||||
<ul class="actions-list nav-dd ui-right">
|
||||
% if not is_root:
|
||||
% if can_edit:
|
||||
% if use_tagging and tags_count:
|
||||
<li class="action-item">
|
||||
<button data-tooltip="${_("Manage Tags")}" class="btn-default action-button manage-tags-button" data-testid="tag-count-button">
|
||||
<span class="icon fa fa-tag" aria-hidden="true"></span>
|
||||
<span>${tags_count}</span>
|
||||
<span class="sr action-button-text">${_("Manage Tags")}</span>
|
||||
</button>
|
||||
</li>
|
||||
% endif
|
||||
% if not show_inline:
|
||||
<li class="action-item action-edit">
|
||||
<button class="btn-default edit-button action-button" data-usage-id=${xblock.scope_ids.usage_id}>
|
||||
@@ -128,7 +137,7 @@ block_is_unit = is_unit(xblock)
|
||||
% endif
|
||||
% if use_tagging:
|
||||
<li class="nav-item">
|
||||
<a class="tags-button" href="#" role="button">${_("Manage tags")}</a>
|
||||
<a class="manage-tags-button" href="#" role="button">${_("Manage tags")}</a>
|
||||
</li>
|
||||
% endif
|
||||
% if is_course:
|
||||
|
||||
@@ -182,5 +182,6 @@ def tag_content_object(
|
||||
get_taxonomy = oel_tagging.get_taxonomy
|
||||
get_taxonomies = oel_tagging.get_taxonomies
|
||||
get_tags = oel_tagging.get_tags
|
||||
get_object_tag_counts = oel_tagging.get_object_tag_counts
|
||||
delete_object_tags = oel_tagging.delete_object_tags
|
||||
resync_object_tags = oel_tagging.resync_object_tags
|
||||
|
||||
Reference in New Issue
Block a user