Skip to content
Closed
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
2 changes: 2 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'];
21 changes: 17 additions & 4 deletions src/library-authoring/add-content/AddContentContainer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,23 @@ describe('<AddContentContainer />', () => {
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([
Expand Down
10 changes: 8 additions & 2 deletions src/library-authoring/add-content/AddContentContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 = (
Expand All @@ -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),
Expand Down
11 changes: 11 additions & 0 deletions src/library-authoring/component-info/ComponentInfo.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ describe('<ComponentInfo> 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(
<ComponentInfo />,
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(
Expand Down
6 changes: 6 additions & 0 deletions src/library-authoring/components/ComponentEditorModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}

Expand Down
13 changes: 13 additions & 0 deletions src/library-authoring/data/api.mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ export async function mockXBlockFields(usageKey: string): Promise<api.XBlockFiel
case thisMock.usageKeyNewProblem: return thisMock.dataNewProblem;
case thisMock.usageKeyNewVideo: return thisMock.dataNewVideo;
case thisMock.usageKeyThirdParty: return thisMock.dataThirdParty;
case thisMock.usageKeyMultiLevel: return thisMock.dataMultiLevel;
default: throw new Error(`No mock has been set up for usageKey "${usageKey}"`);
}
}
Expand Down Expand Up @@ -305,6 +306,12 @@ mockXBlockFields.dataThirdParty = {
data: '',
metadata: { displayName: 'Third party XBlock' },
} satisfies api.XBlockFields;
mockXBlockFields.usageKeyMultiLevel = 'lb:Axim:TEST:conditional:12345';
mockXBlockFields.dataMultiLevel = {
displayName: 'Conditional (Multilevel) Block',
data: '',
metadata: { displayName: 'Conditional (Multilevel) Block' },
} satisfies api.XBlockFields;
/** Apply this mock. Returns a spy object that can tell you if it's been called. */
mockXBlockFields.applyMock = () => jest.spyOn(api, 'getXBlockFields').mockImplementation(mockXBlockFields);

Expand Down Expand Up @@ -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 = {
Expand Down