diff --git a/cms/djangoapps/contentstore/views/block.py b/cms/djangoapps/contentstore/views/block.py index 6f7b879c994d..858155ba21d2 100644 --- a/cms/djangoapps/contentstore/views/block.py +++ b/cms/djangoapps/contentstore/views/block.py @@ -1394,7 +1394,8 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F # If the ENABLE_TAGGING_TAXONOMY_LIST_PAGE feature flag is enabled, we show the "Manage Tags" options if use_tagging_taxonomy_list_page(): xblock_info["use_tagging_taxonomy_list_page"] = True - xblock_info["tag_counts_by_unit"] = _get_course_unit_tags(xblock.location.context_key) + xblock_info["course_tags_count"] = _get_course_tags_count(course.id) + xblock_info["tag_counts_by_block"] = _get_course_block_tags(xblock.location.context_key) xblock_info['user_partition_info'] = get_visibility_partition_info(xblock, course=course) @@ -1642,16 +1643,29 @@ def _xblock_type_and_display_name(xblock): @request_cached() -def _get_course_unit_tags(course_key) -> dict: +def _get_course_tags_count(course_key) -> dict: """ - Get the count of tags that are applied to each unit (vertical) in this course, as a dict. + Get the count of tags that are applied to the course as a dict: {course_key: tags_count} + """ + if not course_key.is_course: + return {} # Unsupported key type + + return get_object_tag_counts(str(course_key), count_implicit=True) + + +@request_cached() +def _get_course_block_tags(course_key) -> dict: + """ + Get the count of tags that are applied to each block in this course, as a dict. """ if not course_key.is_course: return {} # Unsupported key type, e.g. a library - # 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 get_object_tag_counts(unit_key_pattern, count_implicit=True) + + # Create a pattern to match the IDs of all blocks, e.g. "block-v1:org+course+run+type@*" + catch_all_key = course_key.make_usage_key("*", "x") + catch_all_key_pattern = str(catch_all_key).rsplit("@*", 1)[0] + "@*" + + return get_object_tag_counts(catch_all_key_pattern, count_implicit=True) def get_children_tags_count(xblock): diff --git a/cms/static/js/views/course_manage_tags.js b/cms/static/js/views/course_manage_tags.js new file mode 100644 index 000000000000..b276069b345d --- /dev/null +++ b/cms/static/js/views/course_manage_tags.js @@ -0,0 +1,54 @@ +define([ + 'jquery', 'underscore', 'backbone', 'js/utils/templates', + 'edx-ui-toolkit/js/utils/html-utils', 'js/views/utils/tagging_drawer_utils', + 'js/views/tag_count', 'js/models/tag_count'], +function( + $, _, Backbone, TemplateUtils, HtmlUtils, TaggingDrawerUtils, TagCountView, TagCountModel +) { + 'use strict'; + + var CourseManageTagsView = Backbone.View.extend({ + events: { + 'click .manage-tags-button': 'openManageTagsDrawer', + }, + + initialize: function() { + this.template = TemplateUtils.loadTemplate('course-manage-tags'); + this.courseId = course.id; + }, + + openManageTagsDrawer: function(event) { + const taxonomyTagsWidgetUrl = this.model.get('taxonomy_tags_widget_url'); + const contentId = this.courseId; + TaggingDrawerUtils.openDrawer(taxonomyTagsWidgetUrl, contentId); + }, + + renderTagCount: function() { + const contentId = this.courseId; + const tagCountsForCourse = this.model.get('course_tags_count'); + const tagsCount = tagCountsForCourse !== undefined ? tagCountsForCourse[contentId] : 0; + var countModel = new TagCountModel({ + content_id: contentId, + tags_count: tagsCount, + course_authoring_url: this.model.get('course_authoring_url'), + }, {parse: true}); + var tagCountView = new TagCountView({el: this.$('.tag-count'), model: countModel}); + tagCountView.setupMessageListener(); + tagCountView.render(); + this.$('.tag-count').click((event) => { + event.preventDefault(); + this.openManageTagsDrawer(); + }); + }, + + render: function() { + var html = this.template(this.model.attributes); + HtmlUtils.setHtml(this.$el, HtmlUtils.HTML(html)); + this.renderTagCount(); + return this; + } + }); + + return CourseManageTagsView; +} +); diff --git a/cms/static/js/views/course_outline.js b/cms/static/js/views/course_outline.js index 322a421ae7a5..a9849fb53b00 100644 --- a/cms/static/js/views/course_outline.js +++ b/cms/static/js/views/course_outline.js @@ -29,17 +29,22 @@ function( renderTagCount: function() { const contentId = this.model.get('id'); - const tagCountsByUnit = this.model.get('tag_counts_by_unit') - const tagsCount = tagCountsByUnit !== undefined ? tagCountsByUnit[contentId] : 0 + const tagCountsByBlock = this.model.get('tag_counts_by_block') + // Skip the course block since that is handled elsewhere in course_manage_tags + if (contentId.includes('@course')) { + return + } + const tagsCount = tagCountsByBlock !== undefined ? tagCountsByBlock[contentId] : 0 + const tagCountElem = this.$(`.tag-count[data-locator="${contentId}"]`); var countModel = new TagCountModel({ content_id: contentId, tags_count: tagsCount, course_authoring_url: this.model.get('course_authoring_url'), }, {parse: true}); - var tagCountView = new TagCountView({el: this.$('.tag-count'), model: countModel}); + var tagCountView = new TagCountView({el: tagCountElem, model: countModel}); tagCountView.setupMessageListener(); tagCountView.render(); - this.$('.tag-count').click((event) => { + tagCountElem.click((event) => { event.preventDefault(); this.openManageTagsDrawer(); }); diff --git a/cms/static/js/views/pages/course_outline.js b/cms/static/js/views/pages/course_outline.js index 76eb84bcb29b..a2ebb3dc536f 100644 --- a/cms/static/js/views/pages/course_outline.js +++ b/cms/static/js/views/pages/course_outline.js @@ -4,9 +4,10 @@ define([ 'jquery', 'underscore', 'gettext', 'js/views/pages/base_page', 'js/views/utils/xblock_utils', 'js/views/course_outline', 'common/js/components/utils/view_utils', 'common/js/components/views/feedback_alert', - 'common/js/components/views/feedback_notification', 'js/views/course_highlights_enable'], + 'common/js/components/views/feedback_notification', 'js/views/course_highlights_enable', 'js/views/course_manage_tags'], function($, _, gettext, BasePage, XBlockViewUtils, CourseOutlineView, ViewUtils, AlertView, NoteView, - CourseHighlightsEnableView + CourseHighlightsEnableView, + CourseManageTagsView ) { 'use strict'; var expandedLocators, CourseOutlinePage; @@ -93,6 +94,15 @@ function($, _, gettext, BasePage, XBlockViewUtils, CourseOutlineView, ViewUtils, this.highlightsEnableView.render(); } + // if tagging enabled + if (this.model.get('use_tagging_taxonomy_list_page')) { + this.courseManageTagsView = new CourseManageTagsView({ + el: this.$('.status-manage-tags'), + model: this.model + }); + this.courseManageTagsView.render(); + } + this.outlineView = new this.outlineViewClass({ el: this.$('.outline'), model: this.model, diff --git a/cms/static/sass/views/_outline.scss b/cms/static/sass/views/_outline.scss index 01534b54808e..313c77d9a6fa 100644 --- a/cms/static/sass/views/_outline.scss +++ b/cms/static/sass/views/_outline.scss @@ -185,6 +185,7 @@ .status-release, .status-highlights-enabled, + .status-manage-tags, .status-studio-frontend { @extend %t-copy-base; @@ -200,15 +201,19 @@ } } - .status-highlights-enabled { + .status-highlights-enabled, + .status-manage-tags { vertical-align: top; } .status-release-label, .status-release-value, .status-highlights-enabled-label, + .status-course-manage-tags-label, .status-highlights-enabled-value, + .status-course-manage-tags-value, .status-highlights-enabled-info, + .status-course-manage-tags-info, .status-actions { display: inline-block; vertical-align: middle; @@ -216,13 +221,15 @@ } .status-release-value, - .status-highlights-enabled-value { + .status-highlights-enabled-value, + .status-course-manage-tags-value { @extend %t-strong; font-size: smaller; } - .status-highlights-enabled-info { + .status-highlights-enabled-info, + .status-course-manage-tags-info { font-size: smaller; margin-left: $baseline / 2; } diff --git a/cms/templates/course_outline.html b/cms/templates/course_outline.html index 5b1f0e9fbb3d..2546155e26f0 100644 --- a/cms/templates/course_outline.html +++ b/cms/templates/course_outline.html @@ -29,7 +29,7 @@ <%block name="header_extras"> -% 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', 'tag-count']: +% 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', 'tag-count']: @@ -269,6 +269,7 @@

${_("Page Actions")}

+
+

+ <%- gettext('Course tags') %> +

+
+ +<%- gettext('Manage tags') %> +
diff --git a/cms/templates/js/course-outline.underscore b/cms/templates/js/course-outline.underscore index 979649e4a2e5..0f51f98cd0f4 100644 --- a/cms/templates/js/course-outline.underscore +++ b/cms/templates/js/course-outline.underscore @@ -8,7 +8,7 @@ var userPartitionInfo = xblockInfo.get('user_partition_info'); var selectedGroupsLabel = userPartitionInfo['selected_groups_label']; var selectedPartitionIndex = userPartitionInfo['selected_partition_index']; var xblockId = xblockInfo.get('id') -var tagsCount = (xblockInfo.get('tag_counts_by_unit') || {})[xblockId] || 0; +var tagsCount = (xblockInfo.get('tag_counts_by_block') || {})[xblockId] || 0; var statusMessages = []; var messageType; @@ -190,7 +190,7 @@ if (is_proctored_exam) { <% } %> - <% if (xblockInfo.isVertical() && typeof useTaggingTaxonomyListPage !== "undefined" && useTaggingTaxonomyListPage) { %> + <% if (typeof useTaggingTaxonomyListPage !== "undefined" && useTaggingTaxonomyListPage) { %>
  • <% } %> diff --git a/cms/templates/js/tag-count.underscore b/cms/templates/js/tag-count.underscore index 253323109f3c..15aa1b7d7f53 100644 --- a/cms/templates/js/tag-count.underscore +++ b/cms/templates/js/tag-count.underscore @@ -4,4 +4,11 @@ <%- tags_count %> <%- gettext("Manage Tags") %> +<% } else { %> + <% } %> +