Skip to content
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: Enable taxonomy/tagging feature in MFE by default #971

10 changes: 1 addition & 9 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -253,15 +253,7 @@ Requirements

* ``edx-platform`` Waffle flags:

* ``new_studio_mfe.use_tagging_taxonomy_list_page``: this feature flag must be enabled.

Configuration
-------------

In additional to the standard settings, the following local configuration items are required:

* ``ENABLE_TAGGING_TAXONOMY_PAGES``: must be enabled in order to actually present the new Tagging/Taxonomy pages.

* ``content_tagging.disable_tagging_feature``: this feature flag must NOT be checked.

Developing
**********
Expand Down
31 changes: 21 additions & 10 deletions src/CourseAuthoringPage.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import MockAdapter from 'axios-mock-adapter';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { AppProvider } from '@edx/frontend-platform/react';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
import initializeStore from './store';
import CourseAuthoringPage from './CourseAuthoringPage';
import PagesAndResources from './pages-and-resources/PagesAndResources';
Expand Down Expand Up @@ -38,6 +39,8 @@ beforeEach(() => {
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
});

const queryClient = new QueryClient();

describe('Editor Pages Load no header', () => {
const mockStoreSuccess = async () => {
const apiBaseUrl = getConfig().STUDIO_BASE_URL;
Expand All @@ -53,9 +56,11 @@ describe('Editor Pages Load no header', () => {
const wrapper = render(
<AppProvider store={store}>
<IntlProvider locale="en">
<CourseAuthoringPage courseId={courseId}>
<PagesAndResources courseId={courseId} />
</CourseAuthoringPage>
<QueryClientProvider client={queryClient}>
<CourseAuthoringPage courseId={courseId}>
<PagesAndResources courseId={courseId} />
</CourseAuthoringPage>
</QueryClientProvider>
</IntlProvider>
</AppProvider>
,
Expand All @@ -68,9 +73,11 @@ describe('Editor Pages Load no header', () => {
const wrapper = render(
<AppProvider store={store}>
<IntlProvider locale="en">
<CourseAuthoringPage courseId={courseId}>
<PagesAndResources courseId={courseId} />
</CourseAuthoringPage>
<QueryClientProvider client={queryClient}>
<CourseAuthoringPage courseId={courseId}>
<PagesAndResources courseId={courseId} />
</CourseAuthoringPage>
</QueryClientProvider>
</IntlProvider>
</AppProvider>
,
Expand Down Expand Up @@ -103,7 +110,9 @@ describe('Course authoring page', () => {
const wrapper = render(
<AppProvider store={store}>
<IntlProvider locale="en">
<CourseAuthoringPage courseId={courseId} />
<QueryClientProvider client={queryClient}>
<CourseAuthoringPage courseId={courseId} />
</QueryClientProvider>
</IntlProvider>
</AppProvider>
,
Expand All @@ -120,9 +129,11 @@ describe('Course authoring page', () => {
const wrapper = render(
<AppProvider store={store}>
<IntlProvider locale="en">
<CourseAuthoringPage courseId={courseId}>
<div data-testid={contentTestId} />
</CourseAuthoringPage>
<QueryClientProvider client={queryClient}>
<CourseAuthoringPage courseId={courseId}>
<div data-testid={contentTestId} />
</CourseAuthoringPage>
</QueryClientProvider>
</IntlProvider>
</AppProvider>
,
Expand Down
15 changes: 12 additions & 3 deletions src/CourseAuthoringRoutes.test.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { AppProvider } from '@edx/frontend-platform/react';
import { initializeMockApp } from '@edx/frontend-platform';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import CourseAuthoringRoutes from './CourseAuthoringRoutes';
Expand Down Expand Up @@ -48,6 +49,8 @@ jest.mock('./custom-pages/CustomPages', () => (props) => {
return customPagesMockText;
});

const queryClient = new QueryClient();

describe('<CourseAuthoringRoutes>', () => {
beforeEach(() => {
initializeMockApp({
Expand All @@ -65,7 +68,9 @@ describe('<CourseAuthoringRoutes>', () => {
render(
<AppProvider store={store} wrapWithRouter={false}>
<MemoryRouter initialEntries={['/pages-and-resources']}>
<CourseAuthoringRoutes />
<QueryClientProvider client={queryClient}>
<CourseAuthoringRoutes />
</QueryClientProvider>
</MemoryRouter>
</AppProvider>,
);
Expand All @@ -82,7 +87,9 @@ describe('<CourseAuthoringRoutes>', () => {
render(
<AppProvider store={store} wrapWithRouter={false}>
<MemoryRouter initialEntries={['/editor/video/block-id']}>
<CourseAuthoringRoutes />
<QueryClientProvider client={queryClient}>
<CourseAuthoringRoutes />
</QueryClientProvider>
</MemoryRouter>
</AppProvider>,
);
Expand All @@ -100,7 +107,9 @@ describe('<CourseAuthoringRoutes>', () => {
render(
<AppProvider store={store} wrapWithRouter={false}>
<MemoryRouter initialEntries={['/editor/course-videos/block-id']}>
<CourseAuthoringRoutes />
<QueryClientProvider client={queryClient}>
<CourseAuthoringRoutes />
</QueryClientProvider>
</MemoryRouter>
</AppProvider>,
);
Expand Down
7 changes: 6 additions & 1 deletion src/accessibility-page/AccessibilityPage.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
import { AppProvider } from '@edx/frontend-platform/react';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { initializeMockApp } from '@edx/frontend-platform';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
import initializeStore from '../store';
import AccessibilityPage from './index';

Expand All @@ -15,11 +16,15 @@ const initialState = {
};
let store;

const queryClient = new QueryClient();

const renderComponent = () => {
render(
<IntlProvider locale="en">
<AppProvider store={store}>
<AccessibilityPage />
<QueryClientProvider client={queryClient}>
<AccessibilityPage />
</QueryClientProvider>
</AppProvider>
</IntlProvider>,
);
Expand Down
2 changes: 1 addition & 1 deletion src/content-tags-drawer/__mocks__/contentDataMock.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ module.exports = {
taxonomyTagsWidgetUrl: 'http://localhost:2001/tagging/components/widget/',
staffOnlyMessage: false,
enableCopyPasteUnits: true,
useTaggingTaxonomyListPage: true,
isTaggingFeatureDisabled: false,
hasPartitionGroupComponents: false,
userPartitionInfo: {
selectablePartitions: [],
Expand Down
7 changes: 4 additions & 3 deletions src/course-outline/card-header/CardHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
EditOutline as EditIcon,
} from '@openedx/paragon/icons';

import { useContentTagsCount } from '../../generic/data/apiHooks';
import { useContentTagsCount, useTaggingFeaturesEnabled } from '../../generic/data/apiHooks';
import { ContentTagsDrawer } from '../../content-tags-drawer';
import TagCount from '../../generic/tag-count';
import { useEscapeClick } from '../../hooks';
Expand Down Expand Up @@ -71,6 +71,7 @@ const CardHeader = ({
|| status === ITEM_BADGE_STATUS.publishedNotLive) && !hasChanges;

const { data: contentTagCount } = useContentTagsCount(cardId);
const taxonomiesEnabled = useTaggingFeaturesEnabled();

useEffect(() => {
const locatorId = searchParams.get('show');
Expand Down Expand Up @@ -143,7 +144,7 @@ const CardHeader = ({
{(isVertical || isSequential) && (
<CardStatus status={status} showDiscussionsEnabledBadge={showDiscussionsEnabledBadge} />
)}
{ getConfig().ENABLE_TAGGING_TAXONOMY_PAGES === 'true' && contentTagCount > 0 && (
{ taxonomiesEnabled && contentTagCount > 0 && (
<TagCount count={contentTagCount} onClick={openManageTagsDrawer} />
)}
<Dropdown data-testid={`${namePrefix}-card-header__menu`} onClick={onClickMenuButton}>
Expand Down Expand Up @@ -181,7 +182,7 @@ const CardHeader = ({
>
{intl.formatMessage(messages.menuConfigure)}
</Dropdown.Item>
{getConfig().ENABLE_TAGGING_TAXONOMY_PAGES === 'true' && (
{taxonomiesEnabled && (
<Dropdown.Item
data-testid={`${namePrefix}-card-header__menu-manage-tags-button`}
onClick={openManageTagsDrawer}
Expand Down
50 changes: 26 additions & 24 deletions src/course-outline/card-header/CardHeader.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
import {
act, render, fireEvent, waitFor, screen,
} from '@testing-library/react';
import { setConfig, getConfig } from '@edx/frontend-platform';
import { getConfig } from '@edx/frontend-platform';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';

Expand All @@ -23,11 +23,16 @@ const onClickMoveDownMock = jest.fn();
const closeFormMock = jest.fn();

const mockGetTagsCount = jest.fn();
const mockTaggingFeaturesEnabled = jest.fn();

jest.mock('../../generic/data/api', () => ({
...jest.requireActual('../../generic/data/api'),
getTagsCount: () => mockGetTagsCount(),
}));
jest.mock('../../generic/data/apiHooks', () => ({
...jest.requireActual('../../generic/data/apiHooks'),
useTaggingFeaturesEnabled: () => mockTaggingFeaturesEnabled(),
}));

const cardHeaderProps = {
title: 'Some title',
Expand Down Expand Up @@ -85,6 +90,13 @@ const renderComponent = (props, entry = '/') => {
};

describe('<CardHeader />', () => {
beforeEach(() => {
jest.clearAllMocks();
queryClient.clear();
mockGetTagsCount.mockReturnValue({});
mockTaggingFeaturesEnabled.mockReturnValue(true);
});

it('render CardHeader component correctly', async () => {
const { findByText, findByTestId, queryByTestId } = renderComponent();

Expand Down Expand Up @@ -181,11 +193,16 @@ describe('<CardHeader />', () => {
expect(onClickPublishMock).toHaveBeenCalled();
});

it('only shows Manage tags menu if the waffle flag is enabled', async () => {
setConfig({
...getConfig(),
ENABLE_TAGGING_TAXONOMY_PAGES: 'false',
});
it('shows the "Manage tags" menu item by default', async () => {
renderComponent();
const menuButton = await screen.findByTestId('subsection-card-header__menu-button');
fireEvent.click(menuButton);

expect(screen.queryByText(messages.menuManageTags.defaultMessage)).toBeInTheDocument();
});

it('hides the "Manage tags" menu item if the tagging functionality is disabled', async () => {
mockTaggingFeaturesEnabled.mockReturnValue(false);
renderComponent();
const menuButton = await screen.findByTestId('subsection-card-header__menu-button');
fireEvent.click(menuButton);
Expand All @@ -194,10 +211,6 @@ describe('<CardHeader />', () => {
});

it('shows ContentTagsDrawer when the menu is clicked', async () => {
setConfig({
...getConfig(),
ENABLE_TAGGING_TAXONOMY_PAGES: 'true',
});
renderComponent();
const menuButton = await screen.findByTestId('subsection-card-header__menu-button');
fireEvent.click(menuButton);
Expand Down Expand Up @@ -310,31 +323,20 @@ describe('<CardHeader />', () => {
expect(queryByText(messages.discussionEnabledBadgeText.defaultMessage)).toBeInTheDocument();
});

it('should render tag count if is not zero and the waffle flag is enabled', async () => {
setConfig({
...getConfig(),
ENABLE_TAGGING_TAXONOMY_PAGES: 'true',
});
it('should render tag count if is not zero', async () => {
mockGetTagsCount.mockResolvedValue({ 12345: 17 });
renderComponent();
expect(await screen.findByText('17')).toBeInTheDocument();
});

it('shouldn render tag count if the waffle flag is disabled', async () => {
setConfig({
...getConfig(),
ENABLE_TAGGING_TAXONOMY_PAGES: 'false',
});
it('should not render tag count if the waffle flag is disabled', async () => {
mockTaggingFeaturesEnabled.mockReturnValue(false);
mockGetTagsCount.mockResolvedValue({ 12345: 17 });
renderComponent();
expect(screen.queryByText('17')).not.toBeInTheDocument();
});

it('should not render tag count if is zero', () => {
setConfig({
...getConfig(),
ENABLE_TAGGING_TAXONOMY_PAGES: 'true',
});
mockGetTagsCount.mockResolvedValue({ 12345: 0 });
renderComponent();
expect(screen.queryByText('0')).not.toBeInTheDocument();
Expand Down
6 changes: 3 additions & 3 deletions src/course-outline/status-bar/StatusBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@ import React, { useContext } from 'react';
import moment from 'moment/moment';
import PropTypes from 'prop-types';
import { FormattedDate, useIntl } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform/config';
import {
Button, Hyperlink, Form, Sheet, Stack, useToggle,
} from '@openedx/paragon';
import { AppContext } from '@edx/frontend-platform/react';

import { ContentTagsDrawer } from '../../content-tags-drawer';
import TagCount from '../../generic/tag-count';
import { useContentTagsCount, useTaggingFeaturesEnabled } from '../../generic/data/apiHooks';
import { useHelpUrls } from '../../help-urls/hooks';
import { VIDEO_SHARING_OPTIONS } from '../constants';
import { useContentTagsCount } from '../../generic/data/apiHooks';
import messages from './messages';
import { getVideoSharingOptionText } from '../utils';

Expand Down Expand Up @@ -71,6 +70,7 @@ const StatusBar = ({
} = useHelpUrls(['contentHighlights', 'socialSharing']);

const { data: courseTagCount } = useContentTagsCount(courseId);
const taxonomiesEnabled = useTaggingFeaturesEnabled();

const [isManageTagsDrawerOpen, openManageTagsDrawer, closeManageTagsDrawer] = useToggle(false);

Expand Down Expand Up @@ -136,7 +136,7 @@ const StatusBar = ({
</Hyperlink>
</div>
</StatusBarItem>
{getConfig().ENABLE_TAGGING_TAXONOMY_PAGES === 'true' && (
{taxonomiesEnabled && (
<StatusBarItem title={intl.formatMessage(messages.courseTagsTitle)}>
<div className="d-flex align-items-center">
<TagCount count={courseTagCount} />
Expand Down
Loading
Loading