diff --git a/src/index.jsx b/src/index.jsx
index b0247846bd..3b50076d34 100755
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -28,7 +28,6 @@ import messages from './i18n';
import {
LibraryAndComponentPicker,
CreateLibrary,
- CreateLegacyLibrary,
LibraryLayout,
PreviewChangesEmbed,
} from './library-authoring';
@@ -77,7 +76,6 @@ const App = () => {
} />
} />
} />
- } />
} />
} />
({
- ...jest.requireActual('react-router-dom'),
- useNavigate: () => mockNavigate,
-}));
-
-jest.mock('@src/generic/data/apiHooks', () => ({
- ...jest.requireActual('@src/generic/data/apiHooks'),
- useOrganizationListData: () => ({
- data: ['org1', 'org2', 'org3', 'org4', 'org5'],
- isLoading: false,
- }),
-}));
-
-describe('', () => {
- beforeEach(() => {
- axiosMock = initializeMocks().axiosMock;
- axiosMock
- .onGet(getApiWaffleFlagsUrl(undefined))
- .reply(200, {});
- Object.defineProperty(window, 'location', {
- value: { assign: jest.fn() },
- });
- });
-
- afterEach(() => {
- jest.clearAllMocks();
- axiosMock.restore();
- window.location.assign = realWindowLocationAssign;
- });
-
- test('call api data with correct data', async () => {
- const user = userEvent.setup();
- axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock);
- axiosMock.onPost(getContentLibraryV1CreateApiUrl()).reply(200, {
- id: 'library-id',
- url: '/library/library-id',
- });
-
- render();
-
- const titleInput = await screen.findByRole('textbox', { name: /library name/i });
- await user.click(titleInput);
- await user.type(titleInput, 'Test Library Name');
-
- const orgInput = await screen.findByRole('combobox', { name: /organization/i });
- await user.click(orgInput);
- await user.type(orgInput, 'org1');
- await user.tab();
-
- const slugInput = await screen.findByRole('textbox', { name: /library id/i });
- await user.click(slugInput);
- await user.type(slugInput, 'test_library_slug');
-
- await user.click(await screen.findByRole('button', { name: /create/i }));
- await waitFor(() => {
- expect(axiosMock.history.post.length).toBe(1);
- expect(axiosMock.history.post[0].data).toBe(
- '{"display_name":"Test Library Name","org":"org1","number":"test_library_slug"}',
- );
- expect(window.location.assign).toHaveBeenCalledWith('http://localhost:18010/library/library-id');
- });
- });
-
- test('cannot create new org unless allowed', async () => {
- const user = userEvent.setup();
- axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock);
- axiosMock.onPost(getContentLibraryV1CreateApiUrl()).reply(200, {
- id: 'library-id',
- url: '/library/library-id',
- });
-
- render();
-
- const titleInput = await screen.findByRole('textbox', { name: /library name/i });
- await user.click(titleInput);
- await user.type(titleInput, 'Test Library Name');
-
- // We cannot create a new org, and so we're restricted to the allowed list
- const orgOptions = screen.getByTestId('autosuggest-iconbutton');
- await user.click(orgOptions);
- expect(screen.getByText('org1')).toBeInTheDocument();
- ['org2', 'org3', 'org4', 'org5'].forEach((org) => expect(screen.queryByText(org)).not.toBeInTheDocument());
-
- const orgInput = await screen.findByRole('combobox', { name: /organization/i });
- await user.click(orgInput);
- await user.type(orgInput, 'NewOrg');
- await user.tab();
-
- const slugInput = await screen.findByRole('textbox', { name: /library id/i });
- await user.click(slugInput);
- await user.type(slugInput, 'test_library_slug');
-
- await user.click(await screen.findByRole('button', { name: /create/i }));
- await waitFor(() => {
- expect(axiosMock.history.post.length).toBe(0);
- });
- expect(await screen.findByText('Required field.')).toBeInTheDocument();
- });
-
- test('can create new org if allowed', async () => {
- const user = userEvent.setup();
- axiosMock.onGet(getStudioHomeApiUrl()).reply(200, {
- ...studioHomeMock,
- allow_to_create_new_org: true,
- });
- axiosMock.onPost(getContentLibraryV1CreateApiUrl()).reply(200, {
- id: 'library-id',
- url: '/library/library-id',
- });
-
- render();
-
- const titleInput = await screen.findByRole('textbox', { name: /library name/i });
- await user.click(titleInput);
- await user.type(titleInput, 'Test Library Name');
-
- // We can create a new org, so we're also allowed to use any existing org
- const orgOptions = screen.getByTestId('autosuggest-iconbutton');
- await user.click(orgOptions);
- ['org1', 'org2', 'org3', 'org4', 'org5'].forEach((org) => expect(screen.queryByText(org)).toBeInTheDocument());
-
- const orgInput = await screen.findByRole('combobox', { name: /organization/i });
- await user.click(orgInput);
- await user.type(orgInput, 'NewOrg');
- await user.tab();
-
- const slugInput = await screen.findByRole('textbox', { name: /library id/i });
- await user.click(slugInput);
- await user.type(slugInput, 'test_library_slug');
-
- await user.click(await screen.findByRole('button', { name: /create/i }));
- await waitFor(() => {
- expect(axiosMock.history.post.length).toBe(1);
- expect(axiosMock.history.post[0].data).toBe(
- '{"display_name":"Test Library Name","org":"NewOrg","number":"test_library_slug"}',
- );
- expect(window.location.assign).toHaveBeenCalledWith('http://localhost:18010/library/library-id');
- });
- });
-
- test('show api error', async () => {
- const user = userEvent.setup();
- axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock);
- axiosMock.onPost(getContentLibraryV1CreateApiUrl()).reply(400, {
- field: 'Error message',
- });
- render();
-
- const titleInput = await screen.findByRole('textbox', { name: /library name/i });
- await user.click(titleInput);
- await user.type(titleInput, 'Test Library Name');
-
- const orgInput = await screen.findByRole('combobox', { name: /organization/i });
- await user.click(orgInput);
- await user.type(orgInput, 'org1');
- await user.tab();
-
- const slugInput = await screen.findByRole('textbox', { name: /library id/i });
- await user.click(slugInput);
- await user.type(slugInput, 'test_library_slug');
-
- await user.click(await screen.findByRole('button', { name: /create/i }));
- await waitFor(async () => {
- expect(axiosMock.history.post.length).toBe(1);
- expect(axiosMock.history.post[0].data).toBe(
- '{"display_name":"Test Library Name","org":"org1","number":"test_library_slug"}',
- );
- expect(mockNavigate).not.toHaveBeenCalled();
- });
- await screen.findByText('Request failed with status code 400');
- });
-
- test('cancel creating library navigates to libraries page', async () => {
- const user = userEvent.setup();
- render();
-
- await user.click(await screen.findByRole('button', { name: /cancel/i }));
- await waitFor(() => {
- expect(mockNavigate).toHaveBeenCalledWith('/libraries-v1');
- });
- });
-});
diff --git a/src/library-authoring/create-legacy-library/CreateLegacyLibrary.tsx b/src/library-authoring/create-legacy-library/CreateLegacyLibrary.tsx
deleted file mode 100644
index 373c38f90a..0000000000
--- a/src/library-authoring/create-legacy-library/CreateLegacyLibrary.tsx
+++ /dev/null
@@ -1,219 +0,0 @@
-import { StudioFooterSlot } from '@edx/frontend-component-footer';
-import { getConfig } from '@edx/frontend-platform';
-import { useIntl } from '@edx/frontend-platform/i18n';
-import {
- Alert,
- Container,
- Form,
- Button,
- StatefulButton,
- ActionRow,
-} from '@openedx/paragon';
-import { Warning } from '@openedx/paragon/icons';
-import { Formik } from 'formik';
-import { useNavigate, Link } from 'react-router-dom';
-import * as Yup from 'yup';
-import classNames from 'classnames';
-
-import { REGEX_RULES } from '@src/constants';
-import { useOrganizationListData } from '@src/generic/data/apiHooks';
-import { useStudioHome } from '@src/studio-home/hooks';
-import Header from '@src/header';
-import SubHeader from '@src/generic/sub-header/SubHeader';
-import FormikControl from '@src/generic/FormikControl';
-import FormikErrorFeedback from '@src/generic/FormikErrorFeedback';
-import AlertError from '@src/generic/alert-error';
-
-import messages from '@src/library-authoring/create-library/messages';
-import type { LibraryV1Data } from '@src/studio-home/data/api';
-import legacyMessages from './messages';
-import { useCreateLibraryV1 } from './data/apiHooks';
-
-/**
- * Renders the form and logic to create a new library.
- *
- * Use `showInModal` to render this component in a way that can be
- * used in a modal. Currently this component is used in a modal in the
- * legacy libraries migration flow.
- */
-export const CreateLegacyLibrary = ({
- showInModal = false,
- handleCancel,
- handlePostCreate,
-}: {
- showInModal?: boolean;
- handleCancel?: () => void;
- handlePostCreate?: (library: LibraryV1Data) => void;
-}) => {
- const intl = useIntl();
- const navigate = useNavigate();
-
- const { noSpaceRule, specialCharsRule } = REGEX_RULES;
- const validSlugIdRegex = /^[a-zA-Z\d]+(?:[\w-]*[a-zA-Z\d]+)*$/;
-
- const {
- mutate,
- data,
- isPending,
- isError,
- error,
- } = useCreateLibraryV1();
-
- const {
- data: allOrganizations,
- isLoading: isOrganizationListLoading,
- } = useOrganizationListData();
-
- const {
- studioHomeData: {
- allowedOrganizationsForLibraries,
- allowToCreateNewOrg,
- },
- } = useStudioHome();
-
- const organizations = (
- allowToCreateNewOrg
- ? allOrganizations
- : allowedOrganizationsForLibraries
- ) || [];
-
- const handleOnClickCancel = () => {
- if (handleCancel) {
- handleCancel();
- } else {
- navigate('/libraries-v1');
- }
- };
-
- if (data) {
- if (handlePostCreate) {
- handlePostCreate(data);
- } else {
- window.location.assign(`${getConfig().STUDIO_BASE_URL}${data.url}`);
- }
- }
-
- return (
- <>
- {!showInModal && }
-
- {!showInModal && (
-
- )}
-
- {intl.formatMessage(legacyMessages.warningTitle)}
- {intl.formatMessage(legacyMessages.warningBody, {
- libraryLink: (
-
- {intl.formatMessage(legacyMessages.warningLibraryFeature)}
-
- ),
- })}
-
- mutate(values)}
- >
- {(formikProps) => (
-
- )}
-
- {isError && }
-
- {!showInModal && }
- >
- );
-};
diff --git a/src/library-authoring/create-legacy-library/data/api.ts b/src/library-authoring/create-legacy-library/data/api.ts
deleted file mode 100644
index 2ba9425fdb..0000000000
--- a/src/library-authoring/create-legacy-library/data/api.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { camelCaseObject, snakeCaseObject, getConfig } from '@edx/frontend-platform';
-import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
-
-import type { LibraryV1Data } from '@src/studio-home/data/api';
-
-/**
- * Get the URL for creating a new library.
- */
-export const getContentLibraryV1CreateApiUrl = () => `${getConfig().STUDIO_BASE_URL}/library/`;
-
-export interface CreateContentLibraryV1Args {
- displayName: string;
- org: string;
- number: string;
-}
-
-/**
- * Create a new library
- */
-export async function createLibraryV1(data: CreateContentLibraryV1Args): Promise {
- const client = getAuthenticatedHttpClient();
- const url = getContentLibraryV1CreateApiUrl();
-
- const { data: newLibrary } = await client.post(url, { ...snakeCaseObject(data) });
-
- return camelCaseObject(newLibrary);
-}
diff --git a/src/library-authoring/create-legacy-library/data/apiHooks.ts b/src/library-authoring/create-legacy-library/data/apiHooks.ts
deleted file mode 100644
index 1d10760b6f..0000000000
--- a/src/library-authoring/create-legacy-library/data/apiHooks.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import {
- useMutation,
- useQueryClient,
-} from '@tanstack/react-query';
-
-import { studioHomeQueryKeys } from '@src/studio-home/data/apiHooks';
-import { createLibraryV1 } from './api';
-
-/**
- * Hook that provides a "mutation" that can be used to create a new content library.
- */
-export const useCreateLibraryV1 = () => {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: createLibraryV1,
- onSettled: () => {
- queryClient.invalidateQueries({ queryKey: studioHomeQueryKeys.librariesV1() });
- },
- });
-};
diff --git a/src/library-authoring/create-legacy-library/index.ts b/src/library-authoring/create-legacy-library/index.ts
deleted file mode 100644
index b31a5c4243..0000000000
--- a/src/library-authoring/create-legacy-library/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { CreateLegacyLibrary } from './CreateLegacyLibrary';
diff --git a/src/library-authoring/create-legacy-library/messages.ts b/src/library-authoring/create-legacy-library/messages.ts
deleted file mode 100644
index c6e7549766..0000000000
--- a/src/library-authoring/create-legacy-library/messages.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { defineMessages } from '@edx/frontend-platform/i18n';
-
-const messages = defineMessages({
- createLibrary: {
- id: 'course-authoring.library-authoring.create-legacy-library',
- defaultMessage: 'Create new legacy library',
- description: 'Header for the create legacy library form',
- },
- titleLabel: {
- id: 'course-authoring.library-authoring.create-legacy-library.form.title.label',
- defaultMessage: 'Legacy library name',
- description: 'Label for the title field when creating a legacy library.',
- },
- warningTitle: {
- id: 'course-authoring.library-authoring.create-legacy-library.warning.title',
- defaultMessage: 'You are creating content in a deprecated format',
- description: 'Warning to discourage users from creating a new Legacy Library',
- },
- warningBody: {
- id: 'course-authoring.library-authoring.create-legacy-library.warning.body',
- defaultMessage: 'Legacy libraries will be unsupported in Willow. Any content you create in a legacy library will soon need to be migrated. Consider using the {libraryLink} instead.',
- description: 'Warning to discourage users from creating a new Legacy Library',
- },
- warningLibraryFeature: {
- id: 'course-authoring.library-authoring.create-legacy-library.warning.library-feature',
- defaultMessage: 'Library feature',
- description: 'Link to the Libraries feature page',
- },
- createLibraryButton: {
- id: 'course-authoring.library-authoring.create-legacy-library.form.create-library.button',
- defaultMessage: 'Create legacy library',
- description: 'Button text for creating a new legacy library.',
- },
- createLibraryButtonPending: {
- id: 'course-authoring.library-authoring.create-legacy-library.form.create-library.button.pending',
- defaultMessage: 'Creating legacy library..',
- description: 'Button text while the legacy library is being created.',
- },
-});
-
-export default messages;
diff --git a/src/library-authoring/index.tsx b/src/library-authoring/index.tsx
index 6c9ecd97bd..e40fdf27fe 100644
--- a/src/library-authoring/index.tsx
+++ b/src/library-authoring/index.tsx
@@ -1,6 +1,5 @@
export { type SelectedComponent } from './common/context/ComponentPickerContext';
export { LibraryAndComponentPicker, ComponentPicker } from './component-picker';
-export { CreateLegacyLibrary } from './create-legacy-library';
export { CreateLibrary, CreateLibraryModal } from './create-library';
export { libraryAuthoringQueryKeys, useContentLibraryV2List } from './data/apiHooks';
export { default as PreviewChangesEmbed } from './legacy-integration/PreviewChangesEmbed';
diff --git a/src/studio-home/StudioHome.test.tsx b/src/studio-home/StudioHome.test.tsx
index ec3d195e76..09e894e533 100644
--- a/src/studio-home/StudioHome.test.tsx
+++ b/src/studio-home/StudioHome.test.tsx
@@ -126,18 +126,22 @@ describe('', () => {
});
describe('render new library button', () => {
- it('should navigate to legacy library creation when libraries-v2 disabled', async () => {
+ it('should navigate to home_library when libraries-v2 disabled', async () => {
mockUseSelector.mockReturnValue({
...studioHomeMock,
courseCreatorStatus: COURSE_CREATOR_STATES.granted,
librariesV2Enabled: false,
});
+ const studioBaseUrl = 'http://localhost:18010';
+
render(, { path: '/home' });
await waitFor(() => {
const createNewLibraryButton = screen.getByRole('button', { name: 'New library' });
+ const mockWindowOpen = jest.spyOn(window, 'open');
fireEvent.click(createNewLibraryButton);
- expect(mockNavigate).toHaveBeenCalledWith('/libraries-v1/create');
+ expect(mockWindowOpen).toHaveBeenCalledWith(`${studioBaseUrl}/home_library`);
+ mockWindowOpen.mockRestore();
});
});
diff --git a/src/studio-home/StudioHome.tsx b/src/studio-home/StudioHome.tsx
index a2be1984da..8fb453a589 100644
--- a/src/studio-home/StudioHome.tsx
+++ b/src/studio-home/StudioHome.tsx
@@ -108,7 +108,8 @@ const StudioHome = () => {
if (showV2LibraryURL) {
navigate('/library/create');
} else {
- navigate('/libraries-v1/create');
+ // Studio home library for legacy libraries
+ window.open(`${getConfig().STUDIO_BASE_URL}/home_library`);
}
};