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

Remove support for the (deprecated) library authoring MFE [FC-0062] #1327

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions src/editors/data/services/cms/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ describe('cms api', () => {

it('should call get with normal accept header for prod', async () => {
process.env.NODE_ENV = 'production';
process.env.MFE_NAME = 'frontend-app-library-authoring';
process.env.MFE_NAME = 'frontend-app-course-authoring';
// eslint-disable-next-line no-shadow, @typescript-eslint/no-shadow
const { apiMethods } = await import('./api');
// eslint-disable-next-line no-shadow, @typescript-eslint/no-shadow
Expand All @@ -90,18 +90,6 @@ describe('cms api', () => {
apiMethods.fetchByUnitId({ blockId, studioEndpointUrl });
expect(getSpy).toHaveBeenCalledWith(urls.blockAncestor({ studioEndpointUrl, blockId }), {});
});

it('should call get with special accept header "*/*" for course-authoring', async () => {
process.env.NODE_ENV = 'development';
process.env.MFE_NAME = 'frontend-app-library-authoring';
// eslint-disable-next-line no-shadow, @typescript-eslint/no-shadow
const { apiMethods } = await import('./api');
// eslint-disable-next-line no-shadow, @typescript-eslint/no-shadow
const utils = await import('./utils');
const getSpy = jest.spyOn(utils, 'get');
apiMethods.fetchByUnitId({ blockId, studioEndpointUrl });
expect(getSpy).toHaveBeenCalledWith(urls.blockAncestor({ studioEndpointUrl, blockId }), { headers: { Accept: '*/*' } });
});
});
});

Expand Down
8 changes: 0 additions & 8 deletions src/editors/data/services/cms/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@ import { durationStringFromValue } from '../../../containers/VideoEditor/compone

const fetchByUnitIdOptions: AxiosRequestConfig = {};

// For some reason, the local webpack-dev-server of library-authoring does not accept the normal Accept header.
// This is a workaround only for that specific case; the idea is to only do this locally and only for library-authoring.
if (process.env.NODE_ENV === 'development' && process.env.MFE_NAME === 'frontend-app-library-authoring') {
fetchByUnitIdOptions.headers = {
Accept: '*/*',
};
}

interface Pagination {
start: number;
end: number;
Expand Down
10 changes: 1 addition & 9 deletions src/search-modal/SearchResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@ import {
Stack,
} from '@openedx/paragon';
import { OpenInNew } from '@openedx/paragon/icons';
import { useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';

import { getItemIcon } from '../generic/block-type-utils';
import { isLibraryKey } from '../generic/key-utils';
import { useSearchContext, type ContentHit, Highlight } from '../search-manager';
import { getStudioHomeData } from '../studio-home/data/selectors';
import { constructLibraryAuthoringURL } from '../utils';
import messages from './messages';

/**
Expand Down Expand Up @@ -100,7 +97,6 @@ const SearchResult: React.FC<{ hit: ContentHit }> = ({ hit }) => {
const intl = useIntl();
const navigate = useNavigate();
const { closeSearchModal } = useSearchContext();
const { libraryAuthoringMfeUrl, redirectToLibraryAuthoringMfe } = useSelector(getStudioHomeData);

/**
* Returns the URL for the context of the hit
Expand All @@ -119,10 +115,6 @@ const SearchResult: React.FC<{ hit: ContentHit }> = ({ hit }) => {

if (isLibraryKey(contextKey)) {
const urlSuffix = getLibraryComponentUrlSuffix(hit);
if (redirectToLibraryAuthoringMfe && libraryAuthoringMfeUrl) {
return constructLibraryAuthoringURL(libraryAuthoringMfeUrl, urlSuffix);
}

if (newWindow) {
return `${getPath(getConfig().PUBLIC_PATH)}${urlSuffix}`;
}
Expand All @@ -131,7 +123,7 @@ const SearchResult: React.FC<{ hit: ContentHit }> = ({ hit }) => {

// istanbul ignore next - This case should never be reached
return undefined;
}, [libraryAuthoringMfeUrl, redirectToLibraryAuthoringMfe, hit]);
}, [hit]);

/**
* Opens the context of the hit in a new window
Expand Down
42 changes: 1 addition & 41 deletions src/search-modal/SearchUI.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ import fetchMock from 'fetch-mock-jest';
import type { Store } from 'redux';

import initializeStore from '../store';
import { executeThunk } from '../utils';
import { getStudioHomeApiUrl } from '../studio-home/data/api';
import { fetchStudioHomeData } from '../studio-home/data/thunks';
import { generateGetStudioHomeDataApiResponse } from '../studio-home/factories/mockApiResponses';
import mockResult from './__mocks__/search-result.json';
import mockEmptyResult from './__mocks__/empty-search-result.json';
import mockTagsFacetResult from './__mocks__/facet-search.json';
Expand Down Expand Up @@ -316,43 +312,7 @@ describe('<SearchUI />', () => {
);
});

test('click lib component result navigates to the context', async () => {
const data = generateGetStudioHomeDataApiResponse();
data.redirectToLibraryAuthoringMfe = true;
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, data);

await executeThunk(fetchStudioHomeData(), store.dispatch);

const { findByRole } = rendered;

const resultItem = await findByRole('button', { name: /Library Content/ });

// Clicking the "Open in new window" button should open the result in a new window:
const { open, location } = window;
window.open = jest.fn();
fireEvent.click(within(resultItem).getByRole('button', { name: 'Open in new window' }));
expect(window.open).toHaveBeenCalledWith(
'http://localhost:3001/library/lib:org1:libafter1',
'_blank',
);
window.open = open;

// @ts-ignore
window.location = { href: '' };
// Clicking in the result should navigate to the result's URL:
fireEvent.click(resultItem);
expect(window.location.href = 'http://localhost:3001/library/lib:org1:libafter1');
window.location = location;
});

test('click lib component result navigates to course-authoring/library without libraryAuthoringMfe', async () => {
const data = generateGetStudioHomeDataApiResponse();
data.redirectToLibraryAuthoringMfe = false;
data.libraryAuthoringMfeUrl = '';
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, data);

await executeThunk(fetchStudioHomeData(), store.dispatch);

test('click lib component result navigates to course-authoring/library', async () => {
const { findByRole } = rendered;

const resultItem = await findByRole('button', { name: /Library Content/ });
Expand Down
23 changes: 1 addition & 22 deletions src/studio-home/StudioHome.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import MockAdapter from 'axios-mock-adapter';
import initializeStore from '../store';
import { RequestStatus } from '../data/constants';
import { COURSE_CREATOR_STATES } from '../constants';
import { executeThunk, constructLibraryAuthoringURL } from '../utils';
import { executeThunk } from '../utils';
import { studioHomeMock } from './__mocks__';
import { getStudioHomeApiUrl } from './data/api';
import { fetchStudioHomeData } from './data/thunks';
Expand Down Expand Up @@ -193,27 +193,6 @@ describe('<StudioHome />', () => {
window.open = open;
});

it('should navigate to the library authoring mfe', () => {
useSelector.mockReturnValue({
...studioHomeMock,
courseCreatorStatus: COURSE_CREATOR_STATES.granted,
splitStudioHome: true,
redirectToLibraryAuthoringMfe: true,
});
const libraryAuthoringMfeUrl = 'http://localhost:3001';

const { getByTestId } = render(<RootWrapper />);
const createNewLibraryButton = getByTestId('new-library-button');

const { open } = window;
window.open = jest.fn();
fireEvent.click(createNewLibraryButton);
expect(window.open).toHaveBeenCalledWith(
`${constructLibraryAuthoringURL(libraryAuthoringMfeUrl, 'create')}`,
);
window.open = open;
});

it('should navigate to the library authoring page in course authoring', () => {
useSelector.mockReturnValue({
...studioHomeMock,
Expand Down
11 changes: 1 addition & 10 deletions src/studio-home/StudioHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { StudioFooter } from '@edx/frontend-component-footer';
import { getConfig } from '@edx/frontend-platform';
import { useLocation, useNavigate } from 'react-router-dom';

import { constructLibraryAuthoringURL } from '../utils';
import Loading from '../generic/Loading';
import InternetConnectionAlert from '../generic/internet-connection-alert';
import Header from '../header';
Expand Down Expand Up @@ -58,8 +57,6 @@ const StudioHome = () => {
userIsActive,
studioShortName,
studioRequestEmail,
libraryAuthoringMfeUrl,
redirectToLibraryAuthoringMfe,
showNewLibraryButton,
} = studioHomeData;

Expand Down Expand Up @@ -93,13 +90,7 @@ const StudioHome = () => {
if (showNewLibraryButton || showV2LibraryURL) {
const newLibraryClick = () => {
if (showV2LibraryURL) {
if (libraryAuthoringMfeUrl && redirectToLibraryAuthoringMfe) {
// Library authoring MFE
window.open(constructLibraryAuthoringURL(libraryAuthoringMfeUrl, 'create'));
} else {
// Use course-authoring route
navigate('/library/create');
}
navigate('/library/create');
} else {
// Studio home library for legacy libraries
window.open(`${getConfig().STUDIO_BASE_URL}/home_library`);
Expand Down
2 changes: 0 additions & 2 deletions src/studio-home/__mocks__/studioHomeMock.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ module.exports = {
},
],
librariesEnabled: true,
libraryAuthoringMfeUrl: 'http://localhost:3001',
optimizationEnabled: false,
redirectToLibraryAuthoringMfe: false,
requestCourseCreatorUrl: '/request_course_creator',
rerunCreatorStatus: true,
showNewLibraryButton: true,
Expand Down
2 changes: 1 addition & 1 deletion src/studio-home/card-item/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const CardItem: React.FC<Props> = ({
} = useSelector(getStudioHomeData);
const destinationUrl: string = path ?? new URL(url, getConfig().STUDIO_BASE_URL).toString();
const subtitle = isLibraries ? `${org} / ${number}` : `${org} / ${number} / ${run}`;
const readOnlyItem = !(lmsLink || rerunLink || url);
const readOnlyItem = !(lmsLink || rerunLink || url || path);
const showActions = !(readOnlyItem || isLibraries);
const isShowRerunLink = allowCourseReruns
&& rerunCreatorStatus
Expand Down
2 changes: 0 additions & 2 deletions src/studio-home/factories/mockApiResponses.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ export const generateGetStudioHomeDataApiResponse = () => ({
inProcessCourseActions: [],
libraries: [],
librariesEnabled: true,
libraryAuthoringMfeUrl: 'http://localhost:3001/',
optimizationEnabled: false,
redirectToLibraryAuthoringMfe: false,
requestCourseCreatorUrl: '/request_course_creator',
rerunCreatorStatus: true,
showNewLibraryButton: true,
Expand Down
16 changes: 0 additions & 16 deletions src/studio-home/tabs-section/TabsSection.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -428,22 +428,6 @@ describe('<TabsSection />', () => {
expect(screen.queryByText(tabMessages.legacyLibrariesTabTitle.defaultMessage)).toBeNull();
});

it('should redirect to library authoring mfe', async () => {
const data = generateGetStudioHomeDataApiResponse();
data.redirectToLibraryAuthoringMfe = true;

render();
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, data);
await executeThunk(fetchStudioHomeData(), store.dispatch);

const librariesTab = screen.getByText(tabMessages.legacyLibrariesTabTitle.defaultMessage);
fireEvent.click(librariesTab);

waitFor(() => {
expect(window.location.href).toBe(data.libraryAuthoringMfeUrl);
});
});

it('should render libraries fetch failure alert', async () => {
render();
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, generateGetStudioHomeDataApiResponse());
Expand Down
7 changes: 1 addition & 6 deletions src/studio-home/tabs-section/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ const TabsSection = ({
}, [pathname]);

const {
libraryAuthoringMfeUrl,
redirectToLibraryAuthoringMfe,
courses, librariesEnabled, libraries, archivedCourses,
numPages, coursesCount,
} = useSelector(getStudioHomeData);
Expand Down Expand Up @@ -125,10 +123,7 @@ const TabsSection = ({
eventKey={TABS_LIST.libraries}
title={intl.formatMessage(messages.librariesTabTitle)}
>
<LibrariesV2Tab
libraryAuthoringMfeUrl={libraryAuthoringMfeUrl}
redirectToLibraryAuthoringMfe={redirectToLibraryAuthoringMfe}
/>
<LibrariesV2Tab />
</Tab>,
);
}
Expand Down
23 changes: 4 additions & 19 deletions src/studio-home/tabs-section/libraries-v2-tab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,18 @@ import {
Button,
} from '@openedx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';
import { getConfig, getPath } from '@edx/frontend-platform';
import { Error } from '@openedx/paragon/icons';

import { useContentLibraryV2List } from '../../../library-authoring';
import { constructLibraryAuthoringURL } from '../../../utils';
import { LoadingSpinner } from '../../../generic/Loading';
import AlertMessage from '../../../generic/alert-message';
import CardItem from '../../card-item';
import messages from '../messages';
import LibrariesV2Filters from './libraries-v2-filters';

const LibrariesV2Tab: React.FC<{
libraryAuthoringMfeUrl: string,
redirectToLibraryAuthoringMfe: boolean
}> = ({
libraryAuthoringMfeUrl,
redirectToLibraryAuthoringMfe,
}) => {
type Props = Record<never, never>;

const LibrariesV2Tab: React.FC<Props> = () => {
const intl = useIntl();

const [currentPage, setCurrentPage] = useState(1);
Expand Down Expand Up @@ -55,15 +49,6 @@ const LibrariesV2Tab: React.FC<{
);
}

const libURL = (id: string) => (
libraryAuthoringMfeUrl && redirectToLibraryAuthoringMfe
? constructLibraryAuthoringURL(libraryAuthoringMfeUrl, `library/${id}`)
// Redirection to the placeholder is done in the MFE rather than
// through the backend i.e. redirection from cms, because this this will probably change,
// hence why we use the MFE's origin
: `${window.location.origin}${getPath(getConfig().PUBLIC_PATH)}library/${id}`
);

const hasV2Libraries = !isLoading && ((data!.results.length || 0) > 0);

return (
Expand Down Expand Up @@ -109,7 +94,7 @@ const LibrariesV2Tab: React.FC<{
displayName={title}
org={org}
number={slug}
url={libURL(id)}
path={`/library/${id}`}
/>
)) : isFiltered && !isLoading && (
<Alert className="mt-4">
Expand Down
24 changes: 0 additions & 24 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,27 +301,3 @@ export const getFileSizeToClosestByte = (fileSize) => {
const fileSizeFixedDecimal = Number.parseFloat(size).toFixed(2);
return `${fileSizeFixedDecimal} ${units[divides]}`;
};

/**
* Constructs library authoring MFE URL with correct slashes
* @param {string} libraryAuthoringMfeUrl - the base library authoring MFE url
* @param {string} path - the library authoring MFE url path
* @returns {string} - the correct internal route path
*/
export const constructLibraryAuthoringURL = (libraryAuthoringMfeUrl, path) => {
// Remove '/' at the beginning of path if any
const trimmedPath = path.startsWith('/')
? path.slice(1, path.length)
: path;

let constructedUrl = libraryAuthoringMfeUrl;
// Remove trailing `/` from base if found
if (libraryAuthoringMfeUrl.endsWith('/')) {
constructedUrl = constructedUrl.slice(0, -1);
}

// Add the `/` and path to url
constructedUrl = `${constructedUrl}/${trimmedPath}`;

return constructedUrl;
};
Loading