-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Tag List on Unit page [FC-0036] #33645
Changes from 8 commits
4a95e8d
d8e327c
e36cb84
b383efe
a9f2afc
e19ff55
7305ed7
d79cf97
b423507
3db38e8
b96fd33
a005b34
694d164
6d70b80
91c03c1
76232ba
7aa790d
f19b1e8
aa12f5c
29f3b9c
d3c7603
aade38f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,10 +25,14 @@ | |
from common.djangoapps.student.auth import has_course_author_access | ||
from common.djangoapps.xblock_django.api import authorable_xblocks, disabled_xblocks | ||
from common.djangoapps.xblock_django.models import XBlockStudioConfigurationFlag | ||
from cms.djangoapps.contentstore.toggles import use_new_problem_editor | ||
from cms.djangoapps.contentstore.toggles import ( | ||
use_new_problem_editor, | ||
use_tagging_taxonomy_list_page, | ||
) | ||
from openedx.core.lib.xblock_utils import get_aside_from_xblock, is_xblock_aside | ||
from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration | ||
from openedx.core.djangoapps.content_staging import api as content_staging_api | ||
from openedx.core.djangoapps.content_tagging.api import get_content_tags | ||
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order | ||
from xmodule.modulestore.exceptions import ItemNotFoundError # lint-amnesty, pylint: disable=wrong-import-order | ||
from ..toggles import use_new_unit_page | ||
|
@@ -61,7 +65,7 @@ | |
"editor-mode-button", "upload-dialog", | ||
"add-xblock-component", "add-xblock-component-button", "add-xblock-component-menu", | ||
"add-xblock-component-support-legend", "add-xblock-component-support-level", "add-xblock-component-menu-problem", | ||
"xblock-string-field-editor", "xblock-access-editor", "publish-xblock", "publish-history", | ||
"xblock-string-field-editor", "xblock-access-editor", "publish-xblock", "publish-history", "tag-list", | ||
"unit-outline", "container-message", "container-access", "license-selector", "copy-clipboard-button", | ||
"edit-title-button", | ||
] | ||
|
@@ -178,9 +182,14 @@ def container_handler(request, usage_key_string): | |
prev_url = quote_plus(prev_url) if prev_url else None | ||
next_url = quote_plus(next_url) if next_url else None | ||
|
||
show_unit_tags = use_tagging_taxonomy_list_page() | ||
unit_tags = None | ||
if show_unit_tags and is_unit_page: | ||
unit_tags = get_unit_tags(usage_key) | ||
|
||
# Fetch the XBlock info for use by the container page. Note that it includes information | ||
# about the block's ancestors and siblings for use by the Unit Outline. | ||
xblock_info = create_xblock_info(xblock, include_ancestor_info=is_unit_page) | ||
xblock_info = create_xblock_info(xblock, include_ancestor_info=is_unit_page, tags=unit_tags) | ||
|
||
if is_unit_page: | ||
add_container_page_publishing_info(xblock, xblock_info) | ||
|
@@ -216,6 +225,7 @@ def container_handler(request, usage_key_string): | |
'draft_preview_link': preview_lms_link, | ||
'published_preview_link': lms_link, | ||
'templates': CONTAINER_TEMPLATES, | ||
'show_unit_tags': show_unit_tags, | ||
# Status of the user's clipboard, exactly as would be returned from the "GET clipboard" REST API. | ||
'user_clipboard': user_clipboard, | ||
}) | ||
|
@@ -598,3 +608,70 @@ def component_handler(request, usage_key_string, handler, suffix=''): | |
) | ||
|
||
return webob_to_django_response(resp) | ||
|
||
|
||
def get_unit_tags(usage_key): | ||
""" | ||
Get the tags of a Unit and build a json to be read by the UI | ||
""" | ||
# Get content tags from content tagging API | ||
content_tags = get_content_tags(usage_key) | ||
|
||
# Group content tags by taxonomy | ||
taxonomy_dict = {} | ||
for content_tag in content_tags: | ||
taxonomy_id = content_tag.taxonomy_id | ||
if taxonomy_id: | ||
if taxonomy_id not in taxonomy_dict: | ||
taxonomy_dict[taxonomy_id] = [] | ||
taxonomy_dict[taxonomy_id].append(content_tag) | ||
|
||
taxonomy_list = [] | ||
total_count = 0 | ||
|
||
def handle_tag(tags, root_ids, tag, child_tag_id=None): | ||
# Group each tag by parent to build a tree | ||
if tag.id not in tags: | ||
tags[tag.id] = { | ||
'id': tag.id, | ||
'value': tag.value, | ||
'children': [], | ||
} | ||
if child_tag_id: | ||
# Add a child into the children list | ||
tags[tag.id].get('children').append(tags[child_tag_id]) | ||
if tag.parent_id is None: | ||
if tag.id not in root_ids: | ||
root_ids.append(tag.id) | ||
else: | ||
# Group all the lineage of this tag | ||
handle_tag(tags, root_ids, tag.parent, tag.id) | ||
|
||
# Build a tag tree for each taxonomy | ||
for content_tag_list in taxonomy_dict.values(): | ||
tags = {} | ||
root_ids = [] | ||
|
||
for content_tag in content_tag_list: | ||
if content_tag.tag: | ||
handle_tag(tags, root_ids, content_tag.tag) | ||
|
||
taxonomy = content_tag_list[0].taxonomy | ||
|
||
if tags: | ||
count = len(tags) | ||
# Add the tree to the taxonomy list | ||
taxonomy_list.append({ | ||
'id': taxonomy.id, | ||
'value': taxonomy.name, | ||
'tags': [tags[tag_id] for tag_id in root_ids], | ||
'count': count, | ||
}) | ||
total_count += count | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ChrisChV It seems like this functionality does not properly handle multiple tags under the same sub-parent. This is how it is currently showing: for the following tags: When there aren't multiple tags, its seems to be working as expected: There is a recently created PR in the sample generation repo that provides a better distribution of the tags on components/units. (open-craft/taxonomy-sample-data#3). It can better help with testing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @yusuf-musleh Nice catch! I fixed that here 6d70b80 |
||
|
||
unit_tags = { | ||
'count': total_count, | ||
'taxonomies': taxonomy_list, | ||
} | ||
|
||
return unit_tags |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ChrisChV I'm wondering if there is a way to make use of @bradenmacdonald 's updated implementation in the
openedx-learning
repo that added the lineage information to the object tags and takes care of the grouping under taxonomies as well, rather than re-implementing it here as well we could potentially utilize that as a single source of truth.Here is a sample of how the data looks like:
Though I think to make use of that, it seems there needs to be some changes made to the
openedx-learning
repo, namely extracting the logic out of theObjectTagsByTaxonomySerializer
and exposing a python API that can be used in this repo. Since currently It is only available through the rest api.Any thoughts on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thinking was that it's OK to have this duplicated here, because eventually this will be re-implemented in the course-authoring MFE and fetch data using REST (that's out of scope for us now, but at some point ALL of these Studio pages will be using the new MFE only). When that happens, it can use the logic in openedx-learning.
We should definitely put in a comment stating that when this is moved into an MFE it should be simplified to use the REST API which already provides this grouping + sorting logic. But for now since it's already implemented this way, I think it's fine to leave it like this and get it done sooner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok @bradenmacdonald, that makes sense 👍
@yusuf-musleh Adding another comment, In addition to grouping by taxonomy, it is also necessary to group by parents, to be able to assemble each level of the component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bradenmacdonald I see, yup, that make sense to me as well!
@ChrisChV Sounds good!