diff --git a/src/content-tags-drawer/ContentTagsDrawer.scss b/src/content-tags-drawer/ContentTagsDrawer.scss
index 6124ff9332..ce73c6b959 100644
--- a/src/content-tags-drawer/ContentTagsDrawer.scss
+++ b/src/content-tags-drawer/ContentTagsDrawer.scss
@@ -22,6 +22,11 @@
.other-description {
font-size: .9rem;
}
+
+ .enable-taxonomies-button:not([disabled]):hover {
+ background-color: transparent;
+ color: $info-900 !important;
+ }
}
// Apply styles to sheet only if it has a child with a .tags-drawer class
diff --git a/src/content-tags-drawer/ContentTagsDrawer.test.jsx b/src/content-tags-drawer/ContentTagsDrawer.test.jsx
index b9891fde25..8f2e517c35 100644
--- a/src/content-tags-drawer/ContentTagsDrawer.test.jsx
+++ b/src/content-tags-drawer/ContentTagsDrawer.test.jsx
@@ -20,17 +20,20 @@ import {
import { getTaxonomyListData } from '../taxonomy/data/api';
import messages from './messages';
import { ContentTagsDrawerSheetContext } from './common/context';
+import { languageExportId } from './utils';
const contentId = 'block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@vertical+block@7f47fe2dbcaf47c5a071671c741fe1ab';
const mockOnClose = jest.fn();
const mockMutate = jest.fn();
const mockSetBlockingSheet = jest.fn();
+const mockNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: () => ({
contentId,
}),
+ useNavigate: () => mockNavigate,
}));
// FIXME: replace these mocks with API mocks
@@ -256,6 +259,83 @@ describe('', () => {
});
};
+ const setupMockDataLanguageTaxonomyTestings = (hasTags) => {
+ useContentTaxonomyTagsData.mockReturnValue({
+ isSuccess: true,
+ data: {
+ taxonomies: [
+ {
+ name: 'Languages',
+ taxonomyId: 123,
+ exportId: languageExportId,
+ canTagObject: true,
+ tags: hasTags ? [
+ {
+ value: 'Tag 1',
+ lineage: ['Tag 1'],
+ canDeleteObjecttag: true,
+ },
+ ] : [],
+ },
+ {
+ name: 'Taxonomy 1',
+ taxonomyId: 1234,
+ canTagObject: true,
+ tags: [
+ {
+ value: 'Tag 1',
+ lineage: ['Tag 1'],
+ canDeleteObjecttag: true,
+ },
+ {
+ value: 'Tag 2',
+ lineage: ['Tag 2'],
+ canDeleteObjecttag: true,
+ },
+ ],
+ },
+ ],
+ },
+ });
+ getTaxonomyListData.mockResolvedValue({
+ results: [
+ {
+ id: 123,
+ name: 'Languages',
+ description: 'This is a description 1',
+ exportId: languageExportId,
+ canTagObject: true,
+ },
+ {
+ id: 1234,
+ name: 'Taxonomy 1',
+ description: 'This is a description 2',
+ canTagObject: true,
+ },
+ ],
+ });
+
+ useTaxonomyTagsData.mockReturnValue({
+ hasMorePages: false,
+ canAddTag: false,
+ tagPages: {
+ isLoading: false,
+ isError: false,
+ data: [{
+ value: 'Tag 1',
+ externalId: null,
+ childCount: 0,
+ depth: 0,
+ parentValue: null,
+ id: 12345,
+ subTagsUrl: null,
+ canChangeTag: false,
+ canDeleteTag: false,
+ }],
+ },
+ });
+ };
+
const setupLargeMockDataForStagedTagsTesting = () => {
useContentTaxonomyTagsData.mockReturnValue({
isSuccess: true,
@@ -1057,4 +1137,47 @@ describe('', () => {
expect(screen.getByText(/tag 3/i)).toBeInTheDocument();
});
+
+ it('should show Language Taxonomy', async () => {
+ setupMockDataLanguageTaxonomyTestings(true);
+ render();
+ expect(await screen.findByText('Languages')).toBeInTheDocument();
+ });
+
+ it('should hide Language Taxonomy', async () => {
+ setupMockDataLanguageTaxonomyTestings(false);
+ render();
+ expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
+
+ expect(screen.queryByText('Languages')).not.toBeInTheDocument();
+ });
+
+ it('should show empty drawer message', async () => {
+ useContentTaxonomyTagsData.mockReturnValue({
+ isSuccess: true,
+ data: {
+ taxonomies: [],
+ },
+ });
+ getTaxonomyListData.mockResolvedValue({
+ results: [],
+ });
+ useTaxonomyTagsData.mockReturnValue({
+ hasMorePages: false,
+ canAddTag: false,
+ tagPages: {
+ isLoading: false,
+ isError: false,
+ data: [],
+ },
+ });
+
+ render();
+ expect(await screen.findByText(/to use tags, please or contact your administrator\./i)).toBeInTheDocument();
+ const enableButton = screen.getByRole('button', {
+ name: /enable a taxonomy/i,
+ });
+ fireEvent.click(enableButton);
+ expect(mockNavigate).toHaveBeenCalledWith('/taxonomies');
+ });
});
diff --git a/src/content-tags-drawer/ContentTagsDrawerHelper.jsx b/src/content-tags-drawer/ContentTagsDrawerHelper.jsx
index 8eb3e0e578..16ec9f6d94 100644
--- a/src/content-tags-drawer/ContentTagsDrawerHelper.jsx
+++ b/src/content-tags-drawer/ContentTagsDrawerHelper.jsx
@@ -4,7 +4,7 @@ import { useIntl } from '@edx/frontend-platform/i18n';
import { cloneDeep } from 'lodash';
import { useContentData, useContentTaxonomyTagsData, useContentTaxonomyTagsUpdater } from './data/apiHooks';
import { useTaxonomyList } from '../taxonomy/data/apiHooks';
-import { extractOrgFromContentId } from './utils';
+import { extractOrgFromContentId, languageExportId } from './utils';
import messages from './messages';
import { ContentTagsDrawerSheetContext } from './common/context';
@@ -142,8 +142,14 @@ const useContentTagsDrawerContext = (contentId) => {
}
});
+ // Delete Language taxonomy if is empty
+ const filteredTaxonomies = taxonomiesList.filter(
+ (taxonomy) => taxonomy.exportId !== languageExportId
+ || taxonomy.contentTags.length !== 0,
+ );
+
return {
- fechedTaxonomies: sortTaxonomies(taxonomiesList),
+ fechedTaxonomies: sortTaxonomies(filteredTaxonomies),
fechedOtherTaxonomies: otherTaxonomiesList,
};
}
diff --git a/src/content-tags-drawer/ContentTagsDropDownSelector.jsx b/src/content-tags-drawer/ContentTagsDropDownSelector.jsx
index 4960e30912..491d442ed2 100644
--- a/src/content-tags-drawer/ContentTagsDropDownSelector.jsx
+++ b/src/content-tags-drawer/ContentTagsDropDownSelector.jsx
@@ -323,7 +323,9 @@ const ContentTagsDropDownSelector = ({
{ tagPages.data.length === 0 && !tagPages.isLoading && (
-
+ { searchTerm
+ ?
+ : }
)}
diff --git a/src/content-tags-drawer/ContentTagsDropDownSelector.test.jsx b/src/content-tags-drawer/ContentTagsDropDownSelector.test.jsx
index 70d95187f2..08cc6e9bd5 100644
--- a/src/content-tags-drawer/ContentTagsDropDownSelector.test.jsx
+++ b/src/content-tags-drawer/ContentTagsDropDownSelector.test.jsx
@@ -282,4 +282,28 @@ describe('
', () => {
expect(getByText(message)).toBeInTheDocument();
});
});
+
+ it('should render "noTagsInTaxonomy" message if taxonomy is empty', async () => {
+ useTaxonomyTagsData.mockReturnValueOnce({
+ hasMorePages: false,
+ tagPages: {
+ isLoading: false,
+ isError: false,
+ isSuccess: true,
+ data: [],
+ },
+ });
+
+ const searchTerm = '';
+ await act(async () => {
+ const { getByText } = await getComponent({ ...data, searchTerm });
+
+ await waitFor(() => {
+ expect(useTaxonomyTagsData).toBeCalledWith(data.taxonomyId, null, 1, searchTerm);
+ });
+
+ const message = 'No tags in this taxonomy yet';
+ expect(getByText(message)).toBeInTheDocument();
+ });
+ });
});
diff --git a/src/content-tags-drawer/messages.js b/src/content-tags-drawer/messages.js
index ca9c7896c5..4b69010e58 100644
--- a/src/content-tags-drawer/messages.js
+++ b/src/content-tags-drawer/messages.js
@@ -25,6 +25,11 @@ const messages = defineMessages({
id: 'course-authoring.content-tags-drawer.tags-dropdown-selector.no-tags-found',
defaultMessage: 'No tags found with the search term "{searchTerm}"',
},
+ noTagsInTaxonomyMessage: {
+ id: 'course-authoring.content-tags-drawer.tags-dropdown-selector.no-tags-in-taxonomy',
+ defaultMessage: 'No tags in this taxonomy yet',
+ description: 'Message when the user uses the tags dropdown selector of an empty taxonomy',
+ },
taxonomyTagChecked: {
id: 'course-authoring.content-tags-drawer.tags-dropdown-selector.tag-checked',
defaultMessage: 'Checked',
@@ -124,6 +129,16 @@ const messages = defineMessages({
defaultMessage: 'These tags are already applied, but you can\'t add new ones as you don\'t have access to their taxonomies.',
description: 'Description of "Other tags" subsection in tags drawer',
},
+ emptyDrawerContent: {
+ id: 'course-authoring.content-tags-drawer.empty',
+ defaultMessage: 'To use tags, please {link} or contact your administrator.',
+ description: 'Message when there are no taxonomies.',
+ },
+ emptyDrawerContentLink: {
+ id: 'course-authoring.content-tags-drawer.empty-link',
+ defaultMessage: 'enable a taxonomy',
+ description: 'Message of the link used in empty drawer message.',
+ },
});
export default messages;
diff --git a/src/content-tags-drawer/utils.js b/src/content-tags-drawer/utils.js
index ac81f8dc48..06dd9f5784 100644
--- a/src/content-tags-drawer/utils.js
+++ b/src/content-tags-drawer/utils.js
@@ -1,2 +1,3 @@
// eslint-disable-next-line import/prefer-default-export
export const extractOrgFromContentId = (contentId) => contentId.split('+')[0].split(':')[1];
+export const languageExportId = 'languages-v1';