diff --git a/src/constants.js b/src/constants.js
index 80e7cdd778..a23758cefb 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -81,3 +81,5 @@ export const REGEX_RULES = {
export const IFRAME_FEATURE_POLICY = (
'microphone *; camera *; midi *; geolocation *; encrypted-media *; clipboard-write *'
);
+
+export const MULTI_LEVEL_XBLOCKS = ['conditional', 'problem-builder', 'step-builder'];
diff --git a/src/library-authoring/add-content/AddContentContainer.test.tsx b/src/library-authoring/add-content/AddContentContainer.test.tsx
index 229948c39e..b4c38aa24d 100644
--- a/src/library-authoring/add-content/AddContentContainer.test.tsx
+++ b/src/library-authoring/add-content/AddContentContainer.test.tsx
@@ -238,10 +238,23 @@ describe('', () => {
const pasteButton = await screen.findByRole('button', { name: /paste from clipboard/i });
fireEvent.click(pasteButton);
- await waitFor(() => {
- expect(axiosMock.history.post.length).toEqual(0);
- expect(mockShowToast).toHaveBeenCalledWith(errMsg);
- });
+ await waitFor(() => expect(axiosMock.history.post.length).toEqual(0));
+ await waitFor(() => expect(mockShowToast).toHaveBeenCalledWith(errMsg));
+ });
+
+ it('should stop user from pasting multilevel blocks and show toast', async () => {
+ // Simulate having an HTML block in the clipboard:
+ mockClipboardHtml.applyMock('conditional');
+
+ const errMsg = 'Libraries do not support this type of content yet.';
+
+ render();
+
+ const pasteButton = await screen.findByRole('button', { name: /paste from clipboard/i });
+ fireEvent.click(pasteButton);
+
+ await waitFor(() => expect(axiosMock.history.post.length).toEqual(0));
+ await waitFor(() => expect(mockShowToast).toHaveBeenCalledWith(errMsg));
});
test.each([
diff --git a/src/library-authoring/add-content/AddContentContainer.tsx b/src/library-authoring/add-content/AddContentContainer.tsx
index 1a2e28b1a9..995695134e 100644
--- a/src/library-authoring/add-content/AddContentContainer.tsx
+++ b/src/library-authoring/add-content/AddContentContainer.tsx
@@ -30,6 +30,7 @@ import { canEditComponent } from '../components/ComponentEditorModal';
import { PickLibraryContentModal } from './PickLibraryContentModal';
import messages from './messages';
+import { MULTI_LEVEL_XBLOCKS } from '../../constants';
type ContentType = {
name: string,
@@ -78,7 +79,6 @@ const AddContentContainer = () => {
const { showToast } = useContext(ToastContext);
const canEdit = useSelector(getCanEdit);
const { showPasteXBlock, sharedClipboardData } = useCopyToClipboard(canEdit);
-
const [isAddLibraryContentModalOpen, showAddLibraryContentModal, closeAddLibraryContentModal] = useToggle();
const parseErrorMsg = (
@@ -98,7 +98,13 @@ const AddContentContainer = () => {
return intl.formatMessage(defaultMessage);
};
- const isBlockTypeEnabled = (blockType: string) => getConfig().LIBRARY_SUPPORTED_BLOCKS.includes(blockType);
+ const isBlockTypeEnabled = (blockType: string) => {
+ // For now multilevel blocks are not supported in libraries
+ if (MULTI_LEVEL_XBLOCKS.includes(blockType)) {
+ return false;
+ }
+ return getConfig().LIBRARY_SUPPORTED_BLOCKS.includes(blockType);
+ };
const collectionButtonData = {
name: intl.formatMessage(messages.collectionButton),
diff --git a/src/library-authoring/component-info/ComponentInfo.test.tsx b/src/library-authoring/component-info/ComponentInfo.test.tsx
index 6ccebc29fe..fce6f2d21e 100644
--- a/src/library-authoring/component-info/ComponentInfo.test.tsx
+++ b/src/library-authoring/component-info/ComponentInfo.test.tsx
@@ -60,6 +60,17 @@ describe(' Sidebar', () => {
expect(screen.queryByRole('button', { name: /Edit component/ })).not.toBeInTheDocument();
});
+ it('should show a disabled "Edit" button when the component type is multilevel', async () => {
+ initializeMocks();
+ render(
+ ,
+ withLibraryId(mockContentLibrary.libraryId, mockLibraryBlockMetadata.usageKeyMultiLevelXBlock),
+ );
+
+ const editButton = await screen.findByRole('button', { name: /Edit component/ });
+ expect(editButton).toBeDisabled();
+ });
+
it('should show a working "Edit" button for a normal component', async () => {
initializeMocks();
render(
diff --git a/src/library-authoring/components/ComponentEditorModal.tsx b/src/library-authoring/components/ComponentEditorModal.tsx
index e139a8c409..fd94b9189e 100644
--- a/src/library-authoring/components/ComponentEditorModal.tsx
+++ b/src/library-authoring/components/ComponentEditorModal.tsx
@@ -6,6 +6,7 @@ import EditorPage from '../../editors/EditorPage';
import { getBlockType } from '../../generic/key-utils';
import { useLibraryContext } from '../common/context/LibraryContext';
import { invalidateComponentData } from '../data/apiHooks';
+import { MULTI_LEVEL_XBLOCKS } from '../../constants';
export function canEditComponent(usageKey: string): boolean {
let blockType: string;
@@ -15,6 +16,11 @@ export function canEditComponent(usageKey: string): boolean {
return false;
}
+ // For now multilevel blocks are not supported in libraries
+ if (MULTI_LEVEL_XBLOCKS.includes(blockType)) {
+ return false;
+ }
+
return getConfig().LIBRARY_SUPPORTED_BLOCKS.includes(blockType);
}
diff --git a/src/library-authoring/data/api.mocks.ts b/src/library-authoring/data/api.mocks.ts
index ce4be29168..268565d3ea 100644
--- a/src/library-authoring/data/api.mocks.ts
+++ b/src/library-authoring/data/api.mocks.ts
@@ -269,6 +269,7 @@ export async function mockXBlockFields(usageKey: string): Promise jest.spyOn(api, 'getXBlockFields').mockImplementation(mockXBlockFields);
@@ -378,6 +385,12 @@ mockLibraryBlockMetadata.dataThirdPartyXBlock = {
id: mockLibraryBlockMetadata.usageKeyThirdPartyXBlock,
blockType: 'third_party',
} satisfies api.LibraryBlockMetadata;
+mockLibraryBlockMetadata.usageKeyMultiLevelXBlock = mockXBlockFields.usageKeyMultiLevel;
+mockLibraryBlockMetadata.dataMultiLevelXBlock = {
+ ...mockLibraryBlockMetadata.dataPublished,
+ id: mockLibraryBlockMetadata.usageKeyMultiLevelXBlock,
+ blockType: 'conditional',
+} satisfies api.LibraryBlockMetadata;
mockLibraryBlockMetadata.usageKeyForTags = mockContentTaxonomyTagsData.largeTagsId;
mockLibraryBlockMetadata.usageKeyWithCollections = 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd';
mockLibraryBlockMetadata.dataWithCollections = {