fix: Hide / error on Libraries v2 pages if !librariesV2Enabled (#1449)

Show an error message if the user tries to view a v2 Library while Libraries V2 are disabled in the platform.
This commit is contained in:
Jillian
2024-11-06 06:44:09 +10:30
committed by GitHub
parent fc94667a57
commit d7bbd40de1
8 changed files with 58 additions and 7 deletions

View File

@@ -18,6 +18,8 @@ import {
mockXBlockFields,
} from './data/api.mocks';
import { mockContentSearchConfig } from '../search-manager/data/api.mock';
import { studioHomeMock } from '../studio-home/__mocks__';
import { getStudioHomeApiUrl } from '../studio-home/data/api';
import { mockBroadcastChannel } from '../generic/data/api.mock';
import { LibraryLayout } from '.';
import { getLibraryCollectionsApiUrl } from './data/api';
@@ -79,7 +81,8 @@ const libraryTitle = mockContentLibrary.libraryData.title;
describe('<LibraryAuthoringPage />', () => {
beforeEach(() => {
initializeMocks();
const { axiosMock } = initializeMocks();
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock);
// The Meilisearch client-side API uses fetch, not Axios.
fetchMock.mockReset();
@@ -787,4 +790,16 @@ describe('<LibraryAuthoringPage />', () => {
});
});
});
it('Shows an error if libraries V2 is disabled', async () => {
const { axiosMock } = initializeMocks();
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, {
...studioHomeMock,
libraries_v2_enabled: false,
});
render(<LibraryLayout />, { path, params: { libraryId: mockContentLibrary.libraryId } });
await waitFor(() => { expect(axiosMock.history.get.length).toBe(1); });
expect(screen.getByRole('alert')).toHaveTextContent('This page cannot be shown: Libraries v2 are disabled.');
});
});

View File

@@ -4,6 +4,7 @@ import classNames from 'classnames';
import { StudioFooter } from '@edx/frontend-component-footer';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
Alert,
Badge,
Breadcrumb,
Button,
@@ -25,6 +26,7 @@ import Loading from '../generic/Loading';
import SubHeader from '../generic/sub-header/SubHeader';
import Header from '../header';
import NotFoundAlert from '../generic/NotFoundAlert';
import { useStudioHome } from '../studio-home/hooks';
import {
ClearFiltersButton,
FilterByBlockType,
@@ -143,6 +145,12 @@ const LibraryAuthoringPage = ({ returnToLibrarySelection }: LibraryAuthoringPage
const location = useLocation();
const navigate = useNavigate();
const {
isLoadingPage: isLoadingStudioHome,
isFailedLoadingPage: isFailedLoadingStudioHome,
librariesV2Enabled,
} = useStudioHome();
const {
libraryId,
libraryData,
@@ -178,6 +186,14 @@ const LibraryAuthoringPage = ({ returnToLibrarySelection }: LibraryAuthoringPage
return <Loading />;
}
if (!isLoadingStudioHome && (!librariesV2Enabled || isFailedLoadingStudioHome)) {
return (
<Alert variant="danger">
{intl.formatMessage(messages.librariesV2DisabledError)}
</Alert>
);
}
// istanbul ignore if: this should never happen
if (activeKey === undefined) {
return <NotFoundAlert />;

View File

@@ -19,6 +19,8 @@ import {
} from '../data/api.mocks';
import { mockBroadcastChannel, mockClipboardEmpty } from '../../generic/data/api.mock';
import { mockContentSearchConfig, mockSearchResult } from '../../search-manager/data/api.mock';
import { studioHomeMock } from '../../studio-home/__mocks__';
import { getStudioHomeApiUrl } from '../../studio-home/data/api';
import LibraryLayout from '../LibraryLayout';
mockContentSearchConfig.applyMock();
@@ -46,8 +48,12 @@ const renderOpts = {
};
describe('AddContentWorkflow test', () => {
beforeEach(() => {
const { axiosMock } = initializeMocks();
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock);
});
it('can create an HTML component', async () => {
initializeMocks();
render(<LibraryLayout />, renderOpts);
// Click "New [Component]"
@@ -84,7 +90,6 @@ describe('AddContentWorkflow test', () => {
});
it('can create a Problem component', async () => {
initializeMocks();
render(<LibraryLayout />, renderOpts);
// Click "New [Component]"
@@ -119,7 +124,6 @@ describe('AddContentWorkflow test', () => {
});
it('can create a Video component', async () => {
initializeMocks();
render(<LibraryLayout />, renderOpts);
// Click "New [Component]"

View File

@@ -6,6 +6,8 @@ import {
screen,
initializeMocks,
} from '../../testUtils';
import { studioHomeMock } from '../../studio-home/__mocks__';
import { getStudioHomeApiUrl } from '../../studio-home/data/api';
import mockResult from '../__mocks__/library-search.json';
import { LibraryProvider } from '../common/context';
import { ComponentPickerModal } from '../component-picker';
@@ -16,7 +18,6 @@ import {
} from '../data/api.mocks';
import { PickLibraryContentModal } from './PickLibraryContentModal';
initializeMocks();
mockContentSearchConfig.applyMock();
mockContentLibrary.applyMock();
mockGetCollectionMetadata.applyMock();
@@ -45,6 +46,7 @@ describe('<PickLibraryContentModal />', () => {
beforeEach(() => {
const mocks = initializeMocks();
mockShowToast = mocks.mockShowToast;
mocks.axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock);
});
it('can pick components from the modal', async () => {

View File

@@ -27,6 +27,13 @@ jest.mock('react-router-dom', () => ({
},
}),
}));
jest.mock('../../studio-home/hooks', () => ({
useStudioHome: () => ({
isLoadingPage: false,
isFailedLoadingPage: false,
librariesV2Enabled: true,
}),
}));
mockContentLibrary.applyMock();
mockContentSearchConfig.applyMock();
mockGetCollectionMetadata.applyMock();

View File

@@ -111,6 +111,11 @@ const messages = defineMessages({
defaultMessage: 'Change Library',
description: 'Breadcrumbs link to return to library selection',
},
librariesV2DisabledError: {
id: 'authoring.alert.error.libraries.v2.disabled',
defaultMessage: 'This page cannot be shown: Libraries v2 are disabled.',
description: 'Error message shown to users when trying to load a libraries V2 page while libraries v2 are disabled.',
},
});
export default messages;

View File

@@ -47,7 +47,7 @@ const StudioHome = () => {
setShowNewCourseContainer,
librariesV1Enabled,
librariesV2Enabled,
} = useStudioHome(isPaginationCoursesEnabled);
} = useStudioHome();
const v1LibraryTab = librariesV1Enabled && location?.pathname.split('/').pop() === 'libraries-v1';
const showV2LibraryURL = librariesV2Enabled && !v1LibraryTab;

View File

@@ -1,6 +1,7 @@
import { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { RequestStatus } from '../data/constants';
import { COURSE_CREATOR_STATES } from '../constants';
@@ -14,9 +15,10 @@ import {
} from './data/selectors';
import { updateSavingStatuses } from './data/slice';
const useStudioHome = (isPaginated = false) => {
const useStudioHome = () => {
const location = useLocation();
const dispatch = useDispatch();
const isPaginated = getConfig().ENABLE_HOME_PAGE_COURSE_API_V2;
const studioHomeData = useSelector(getStudioHomeData);
const studioHomeCoursesParams = useSelector(getStudioHomeCoursesParams);
const { isFiltered } = studioHomeCoursesParams;