diff --git a/src/course-libraries/CourseLibraries.test.tsx b/src/course-libraries/CourseLibraries.test.tsx index 4c44144246..486c995bd7 100644 --- a/src/course-libraries/CourseLibraries.test.tsx +++ b/src/course-libraries/CourseLibraries.test.tsx @@ -82,7 +82,7 @@ describe('', () => { expect(reviewTab).toHaveAttribute('aria-selected', 'true'); userEvent.click(allTab); - const alert = await screen.findByRole('alert'); + const alert = (await screen.findAllByRole('alert'))[0]; expect(await within(alert).findByText( '5 library components are out of sync. Review updates to accept or ignore changes', )).toBeInTheDocument(); @@ -105,7 +105,7 @@ describe('', () => { userEvent.click(allTab); expect(allTab).toHaveAttribute('aria-selected', 'true'); - const alert = await screen.findByRole('alert'); + const alert = (await screen.findAllByRole('alert'))[0]; expect(await within(alert).findByText( '5 library components are out of sync. Review updates to accept or ignore changes', )).toBeInTheDocument(); @@ -133,7 +133,7 @@ describe('', () => { expect(reviewTab).toHaveAttribute('aria-selected', 'true'); userEvent.click(allTab); - const alert = await screen.findByRole('alert'); + const alert = (await screen.findAllByRole('alert'))[0]; expect(await within(alert).findByText( '5 library components are out of sync. Review updates to accept or ignore changes', )).toBeInTheDocument(); @@ -156,7 +156,7 @@ describe('', () => { screen.logTestingPlaygroundURL(); - expect(screen.queryByRole('alert')).not.toBeInTheDocument(); + expect(screen.queryAllByRole('alert').length).toEqual(1); }); }); diff --git a/src/course-libraries/CourseLibraries.tsx b/src/course-libraries/CourseLibraries.tsx index 2d0cfadf0f..9298c5d2cb 100644 --- a/src/course-libraries/CourseLibraries.tsx +++ b/src/course-libraries/CourseLibraries.tsx @@ -17,7 +17,7 @@ import { Tabs, } from '@openedx/paragon'; import { - Cached, CheckCircle, Launch, Loop, + Cached, CheckCircle, Launch, Loop, Info, } from '@openedx/paragon/icons'; import sumBy from 'lodash/sumBy'; @@ -33,6 +33,7 @@ import { useStudioHome } from '../studio-home/hooks'; import NewsstandIcon from '../generic/NewsstandIcon'; import ReviewTabContent from './ReviewTabContent'; import { OutOfSyncAlert } from './OutOfSyncAlert'; +import AlertMessage from '../generic/alert-message'; interface Props { courseId: string; @@ -199,6 +200,12 @@ export const CourseLibraries: React.FC = ({ courseId }) => { showAlert={showReviewAlert && tabKey === CourseLibraryTabs.all} setShowAlert={setShowReviewAlert} /> + { /* TODO: Remove this alert after implement container in this page */} + {titleComponent} - {readyToSync && ( - - )} - + {intl.formatMessage( + isDisabledEditField ? messages.cannotEditTooltip : messages.altButtonRename, + )} + + )} iconAs={EditIcon} onClick={onClickEdit} // @ts-ignore @@ -161,6 +168,15 @@ const CardHeader = ({ )} {extraActionsComponent} + {readyToSync && ( + {intl.formatMessage(messages.readyToSyncButtonAlt)}} + onClick={onClickSync} + /> + )} ', () => { // Should open compare preview modal expect(screen.getByRole('heading', { name: /preview changes: unit name/i })).toBeInTheDocument(); - expect(screen.getByText('Preview not available')).toBeInTheDocument(); + expect(screen.getByText('Preview not available for unit changes at this time')).toBeInTheDocument(); // Click on accept changes const acceptChangesButton = screen.getByText(/accept changes/i); @@ -196,7 +196,7 @@ describe('', () => { // Should open compare preview modal expect(screen.getByRole('heading', { name: /preview changes: unit name/i })).toBeInTheDocument(); - expect(screen.getByText('Preview not available')).toBeInTheDocument(); + expect(screen.getByText('Preview not available for unit changes at this time')).toBeInTheDocument(); // Click on ignore changes const ignoreChangesButton = screen.getByRole('button', { name: /ignore changes/i }); diff --git a/src/course-unit/CourseUnit.test.jsx b/src/course-unit/CourseUnit.test.jsx index 6985d3ce09..8795f996ff 100644 --- a/src/course-unit/CourseUnit.test.jsx +++ b/src/course-unit/CourseUnit.test.jsx @@ -17,7 +17,6 @@ import { cloneDeep, set } from 'lodash'; import { getCourseSectionVerticalApiUrl, - getCourseUnitApiUrl, getCourseVerticalChildrenApiUrl, getCourseOutlineInfoUrl, getXBlockBaseApiUrl, @@ -28,7 +27,6 @@ import { deleteUnitItemQuery, editCourseUnitVisibilityAndData, fetchCourseSectionVerticalData, - fetchCourseUnitQuery, fetchCourseVerticalChildrenData, getCourseOutlineInfoQuery, patchUnitItemQuery, @@ -37,13 +35,12 @@ import initializeStore from '../store'; import { courseCreateXblockMock, courseSectionVerticalMock, - courseUnitIndexMock, courseUnitMock, courseVerticalChildrenMock, clipboardMockResponse, courseOutlineInfoMock, } from './__mocks__'; -import { clipboardUnit, clipboardXBlock } from '../__mocks__'; +import { clipboardUnit } from '../__mocks__'; import { executeThunk } from '../utils'; import { IFRAME_FEATURE_POLICY } from '../constants'; import pasteComponentMessages from '../generic/clipboard/paste-component/messages'; @@ -72,7 +69,8 @@ let store; let queryClient; const courseId = '123'; const blockId = '567890'; -const unitDisplayName = courseUnitIndexMock.metadata.display_name; +const sequenceId = 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@19a30717eff543078a5d94ae9d6c18a5'; +const unitDisplayName = courseSectionVerticalMock.xblock_info.display_name; const mockedUsedNavigate = jest.fn(); const userName = 'openedx'; const handleConfigureSubmitMock = jest.fn(); @@ -90,7 +88,7 @@ const postXBlockBody = { jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), - useParams: () => ({ blockId }), + useParams: () => ({ blockId, sequenceId }), useNavigate: () => mockedUsedNavigate, })); @@ -146,14 +144,10 @@ describe('', () => { axiosMock .onGet(getClipboardUrl()) .reply(200, clipboardUnit); - axiosMock - .onGet(getCourseUnitApiUrl(courseId)) - .reply(200, courseUnitIndexMock); - await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); axiosMock .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, courseSectionVerticalMock); - await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); + await executeThunk(fetchCourseSectionVerticalData(blockId, courseId), store.dispatch); axiosMock .onGet(getCourseVerticalChildrenApiUrl(blockId)) .reply(200, courseVerticalChildrenMock); @@ -168,8 +162,8 @@ describe('', () => { it('render CourseUnit component correctly', async () => { render(); - const currentSectionName = courseUnitIndexMock.ancestor_info.ancestors[1].display_name; - const currentSubSectionName = courseUnitIndexMock.ancestor_info.ancestors[1].display_name; + const currentSectionName = courseSectionVerticalMock.xblock_info.ancestor_info.ancestors[1].display_name; + const currentSubSectionName = courseSectionVerticalMock.xblock_info.ancestor_info.ancestors[1].display_name; await waitFor(() => { const unitHeaderTitle = screen.getByTestId('unit-header-title'); @@ -278,11 +272,14 @@ describe('', () => { }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - has_changes: true, - published_by: userName, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + has_changes: true, + published_by: userName, + }, }); await waitFor(() => { @@ -314,11 +311,14 @@ describe('', () => { }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - has_changes: true, - published_by: userName, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + has_changes: true, + published_by: userName, + }, }); await waitFor(() => { @@ -381,12 +381,15 @@ describe('', () => { }) .reply(200, { dummy: 'value' }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - visibility_state: UNIT_VISIBILITY_STATES.live, - has_changes: false, - published_by: userName, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + visibility_state: UNIT_VISIBILITY_STATES.live, + has_changes: false, + published_by: userName, + }, }); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); @@ -395,7 +398,7 @@ describe('', () => { expect(screen.getByText(sidebarMessages.sidebarTitlePublishedAndLive.defaultMessage)).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.publishLastPublished.defaultMessage - .replace('{publishedOn}', courseUnitIndexMock.published_on) + .replace('{publishedOn}', courseSectionVerticalMock.xblock_info.published_on) .replace('{publishedBy}', userName), )).toBeInTheDocument(); expect(screen.queryByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })).not.toBeInTheDocument(); @@ -405,6 +408,9 @@ describe('', () => { axiosMock .onDelete(getXBlockBaseApiUrl(courseVerticalChildrenMock.children[0].block_id)) .reply(200, { dummy: 'value' }); + axiosMock + .onGet(getCourseSectionVerticalApiUrl(courseId)) + .reply(200, courseSectionVerticalMock); await executeThunk(deleteUnitItemQuery( courseId, courseVerticalChildrenMock.children[0].block_id, @@ -425,8 +431,8 @@ describe('', () => { await executeThunk(fetchCourseVerticalChildrenData(blockId), store.dispatch); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) - .reply(200, courseUnitIndexMock); + .onGet(getCourseSectionVerticalApiUrl(blockId)) + .reply(200, courseSectionVerticalMock); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); await waitFor(() => { @@ -445,15 +451,15 @@ describe('', () => { expect(screen.getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument(); - expect(screen.getByText(courseUnitIndexMock.release_date)).toBeInTheDocument(); + expect(screen.getByText(courseSectionVerticalMock.xblock_info.release_date)).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.publishInfoDraftSaved.defaultMessage - .replace('{editedOn}', courseUnitIndexMock.edited_on) - .replace('{editedBy}', courseUnitIndexMock.edited_by), + .replace('{editedOn}', courseSectionVerticalMock.xblock_info.edited_on) + .replace('{editedBy}', courseSectionVerticalMock.xblock_info.edited_by), )).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.releaseInfoWithSection.defaultMessage - .replace('{sectionName}', courseUnitIndexMock.release_date_from), + .replace('{sectionName}', courseSectionVerticalMock.xblock_info.release_date_from), )).toBeInTheDocument(); }); }); @@ -465,10 +471,6 @@ describe('', () => { id: courseVerticalChildrenMock.children[0].block_id, }); - axiosMock - .onGet(getCourseUnitApiUrl(blockId)) - .reply(200, courseUnitIndexMock); - axiosMock .onPost(postXBlockBaseApiUrl({ parent_locator: blockId, @@ -518,12 +520,15 @@ describe('', () => { }) .reply(200, { dummy: 'value' }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - visibility_state: UNIT_VISIBILITY_STATES.live, - has_changes: false, - published_by: userName, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + visibility_state: UNIT_VISIBILITY_STATES.live, + has_changes: false, + published_by: userName, + }, }); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); @@ -532,7 +537,7 @@ describe('', () => { expect(screen.getByText(sidebarMessages.sidebarTitlePublishedAndLive.defaultMessage)).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.publishLastPublished.defaultMessage - .replace('{publishedOn}', courseUnitIndexMock.published_on) + .replace('{publishedOn}', courseSectionVerticalMock.xblock_info.published_on) .replace('{publishedBy}', userName), )).toBeInTheDocument(); expect(screen.queryByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })).not.toBeInTheDocument(); @@ -540,8 +545,8 @@ describe('', () => { }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) - .reply(200, courseUnitIndexMock); + .onGet(getCourseSectionVerticalApiUrl(blockId)) + .reply(200, courseSectionVerticalMock); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); await waitFor(() => { @@ -561,15 +566,15 @@ describe('', () => { expect(screen.getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument(); - expect(screen.getByText(courseUnitIndexMock.release_date)).toBeInTheDocument(); + expect(screen.getByText(courseSectionVerticalMock.xblock_info.release_date)).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.publishInfoDraftSaved.defaultMessage - .replace('{editedOn}', courseUnitIndexMock.edited_on) - .replace('{editedBy}', courseUnitIndexMock.edited_by), + .replace('{editedOn}', courseSectionVerticalMock.xblock_info.edited_on) + .replace('{editedBy}', courseSectionVerticalMock.xblock_info.edited_by), )).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.releaseInfoWithSection.defaultMessage - .replace('{sectionName}', courseUnitIndexMock.release_date_from), + .replace('{sectionName}', courseSectionVerticalMock.xblock_info.release_date_from), )).toBeInTheDocument(); }); }); @@ -612,12 +617,15 @@ describe('', () => { })) .reply(200, { dummy: 'value' }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - metadata: { - ...courseUnitIndexMock.metadata, - display_name: newDisplayName, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + metadata: { + ...courseSectionVerticalMock.xblock_info.metadata, + display_name: newDisplayName, + }, }, }); axiosMock @@ -690,12 +698,15 @@ describe('', () => { }) .reply(200, { dummy: 'value' }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - visibility_state: UNIT_VISIBILITY_STATES.live, - has_changes: false, - published_by: userName, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + visibility_state: UNIT_VISIBILITY_STATES.live, + has_changes: false, + published_by: userName, + }, }); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); @@ -710,8 +721,8 @@ describe('', () => { }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) - .reply(200, courseUnitIndexMock); + .onGet(getCourseSectionVerticalApiUrl(blockId)) + .reply(200, courseSectionVerticalMock); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); @@ -724,15 +735,15 @@ describe('', () => { expect(screen.getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument(); - expect(screen.getByText(courseUnitIndexMock.release_date)).toBeInTheDocument(); + expect(screen.getByText(courseSectionVerticalMock.xblock_info.release_date)).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.publishInfoDraftSaved.defaultMessage - .replace('{editedOn}', courseUnitIndexMock.edited_on) - .replace('{editedBy}', courseUnitIndexMock.edited_by), + .replace('{editedOn}', courseSectionVerticalMock.xblock_info.edited_on) + .replace('{editedBy}', courseSectionVerticalMock.xblock_info.edited_by), )).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.releaseInfoWithSection.defaultMessage - .replace('{sectionName}', courseUnitIndexMock.release_date_from), + .replace('{sectionName}', courseSectionVerticalMock.xblock_info.release_date_from), )).toBeInTheDocument(); }); @@ -794,12 +805,15 @@ describe('', () => { }, })) .reply(200, { dummy: 'value' }) - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - metadata: { - ...courseUnitIndexMock.metadata, - display_name: newDisplayName, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + metadata: { + ...courseSectionVerticalMock.xblock_info.metadata, + display_name: newDisplayName, + }, }, }) .onGet(getCourseSectionVerticalApiUrl(blockId)) @@ -844,12 +858,15 @@ describe('', () => { }) .reply(200, { dummy: 'value' }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - visibility_state: UNIT_VISIBILITY_STATES.live, - has_changes: false, - published_by: userName, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + visibility_state: UNIT_VISIBILITY_STATES.live, + has_changes: false, + published_by: userName, + }, }); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); @@ -861,7 +878,7 @@ describe('', () => { expect(screen.getByText( sidebarMessages.publishLastPublished.defaultMessage - .replace('{publishedOn}', courseUnitIndexMock.published_on) + .replace('{publishedOn}', courseSectionVerticalMock.xblock_info.published_on) .replace('{publishedBy}', userName), )).toBeInTheDocument(); expect(screen.queryByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })).not.toBeInTheDocument(); @@ -874,8 +891,8 @@ describe('', () => { userEvent.click(videoButton); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) - .reply(200, courseUnitIndexMock); + .onGet(getCourseSectionVerticalApiUrl(blockId)) + .reply(200, courseSectionVerticalMock); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); @@ -888,15 +905,15 @@ describe('', () => { expect(screen.getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument(); - expect(screen.getByText(courseUnitIndexMock.release_date)).toBeInTheDocument(); + expect(screen.getByText(courseSectionVerticalMock.xblock_info.release_date)).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.publishInfoDraftSaved.defaultMessage - .replace('{editedOn}', courseUnitIndexMock.edited_on) - .replace('{editedBy}', courseUnitIndexMock.edited_by), + .replace('{editedOn}', courseSectionVerticalMock.xblock_info.edited_on) + .replace('{editedBy}', courseSectionVerticalMock.xblock_info.edited_by), )).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.releaseInfoWithSection.defaultMessage - .replace('{sectionName}', courseUnitIndexMock.release_date_from), + .replace('{sectionName}', courseSectionVerticalMock.xblock_info.release_date_from), )).toBeInTheDocument(); expect(screen.getByRole('heading', { name: /add video to your course/i, hidden: true })).toBeInTheDocument(); waffleSpy.mockRestore(); @@ -918,12 +935,15 @@ describe('', () => { }) .reply(200, { dummy: 'value' }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - visibility_state: UNIT_VISIBILITY_STATES.live, - has_changes: false, - published_by: userName, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + visibility_state: UNIT_VISIBILITY_STATES.live, + has_changes: false, + published_by: userName, + }, }); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); @@ -933,7 +953,7 @@ describe('', () => { expect(screen.getByText(sidebarMessages.sidebarTitlePublishedAndLive.defaultMessage)).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.publishLastPublished.defaultMessage - .replace('{publishedOn}', courseUnitIndexMock.published_on) + .replace('{publishedOn}', courseSectionVerticalMock.xblock_info.published_on) .replace('{publishedBy}', userName), )).toBeInTheDocument(); expect(screen.queryByRole('button', { name: sidebarMessages.actionButtonPublishTitle.defaultMessage })).not.toBeInTheDocument(); @@ -953,8 +973,8 @@ describe('', () => { */ axiosMock - .onGet(getCourseUnitApiUrl(blockId)) - .reply(200, courseUnitIndexMock); + .onGet(getCourseSectionVerticalApiUrl(blockId)) + .reply(200, courseSectionVerticalMock); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); @@ -967,15 +987,15 @@ describe('', () => { expect(screen.getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument(); - expect(screen.getByText(courseUnitIndexMock.release_date)).toBeInTheDocument(); + expect(screen.getByText(courseSectionVerticalMock.xblock_info.release_date)).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.publishInfoDraftSaved.defaultMessage - .replace('{editedOn}', courseUnitIndexMock.edited_on) - .replace('{editedBy}', courseUnitIndexMock.edited_by), + .replace('{editedOn}', courseSectionVerticalMock.xblock_info.edited_on) + .replace('{editedBy}', courseSectionVerticalMock.xblock_info.edited_by), )).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.releaseInfoWithSection.defaultMessage - .replace('{sectionName}', courseUnitIndexMock.release_date_from), + .replace('{sectionName}', courseSectionVerticalMock.xblock_info.release_date_from), )).toBeInTheDocument(); }); @@ -991,22 +1011,22 @@ describe('', () => { expect(screen.getByText(sidebarMessages.visibilityCheckboxTitle.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(sidebarMessages.actionButtonPublishTitle.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(sidebarMessages.actionButtonDiscardChangesTitle.defaultMessage)).toBeInTheDocument(); - expect(screen.getByText(courseUnitIndexMock.release_date)).toBeInTheDocument(); + expect(screen.getByText(courseSectionVerticalMock.xblock_info.release_date)).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.publishInfoDraftSaved.defaultMessage - .replace('{editedOn}', courseUnitIndexMock.edited_on) - .replace('{editedBy}', courseUnitIndexMock.edited_by), + .replace('{editedOn}', courseSectionVerticalMock.xblock_info.edited_on) + .replace('{editedBy}', courseSectionVerticalMock.xblock_info.edited_by), )).toBeInTheDocument(); expect(screen.getByText( sidebarMessages.releaseInfoWithSection.defaultMessage - .replace('{sectionName}', courseUnitIndexMock.release_date_from), + .replace('{sectionName}', courseSectionVerticalMock.xblock_info.release_date_from), )).toBeInTheDocument(); }); }); it('renders course unit details in the sidebar', async () => { render(); - const courseUnitLocationId = extractCourseUnitId(courseUnitIndexMock.id); + const courseUnitLocationId = extractCourseUnitId(courseSectionVerticalMock.xblock_info.id); await waitFor(() => { expect(screen.getByText(sidebarMessages.sidebarHeaderUnitLocationTitle.defaultMessage)).toBeInTheDocument(); @@ -1033,13 +1053,16 @@ describe('', () => { render(); axiosMock - .onGet(getCourseUnitApiUrl(courseId)) + .onGet(getCourseSectionVerticalApiUrl(courseId)) .reply(200, { - ...courseUnitIndexMock, - currently_visible_to_students: false, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + currently_visible_to_students: false, + }, }); - await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); + await executeThunk(fetchCourseSectionVerticalData(courseId), store.dispatch); await waitFor(() => { const alert = screen.queryAllByRole('alert').find( @@ -1076,11 +1099,14 @@ describe('', () => { }) .reply(200, { dummy: 'value' }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - visibility_state: UNIT_VISIBILITY_STATES.staffOnly, - has_explicit_staff_lock: true, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + visibility_state: UNIT_VISIBILITY_STATES.staffOnly, + has_explicit_staff_lock: true, + }, }); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.republish, true), store.dispatch); @@ -1113,8 +1139,8 @@ describe('', () => { }) .reply(200, { dummy: 'value' }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) - .reply(200, courseUnitIndexMock); + .onGet(getCourseSectionVerticalApiUrl(blockId)) + .reply(200, courseSectionVerticalMock); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.republish, null), store.dispatch); @@ -1143,12 +1169,15 @@ describe('', () => { }) .reply(200, { dummy: 'value' }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - visibility_state: UNIT_VISIBILITY_STATES.live, - has_changes: false, - published_by: userName, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + visibility_state: UNIT_VISIBILITY_STATES.live, + has_changes: false, + published_by: userName, + }, }); await executeThunk(editCourseUnitVisibilityAndData(blockId, PUBLISH_TYPES.makePublic, true), store.dispatch); @@ -1157,7 +1186,7 @@ describe('', () => { .getByText(sidebarMessages.sidebarTitlePublishedAndLive.defaultMessage)).toBeInTheDocument(); expect(within(courseUnitSidebar).getByText( sidebarMessages.publishLastPublished.defaultMessage - .replace('{publishedOn}', courseUnitIndexMock.published_on) + .replace('{publishedOn}', courseSectionVerticalMock.xblock_info.published_on) .replace('{publishedBy}', userName), )).toBeInTheDocument(); expect(publishBtn).not.toBeInTheDocument(); @@ -1199,9 +1228,14 @@ describe('', () => { }) .reply(200, { dummy: 'value' }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, published: true, has_changes: false, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + published: true, + has_changes: false, + }, }); await executeThunk(editCourseUnitVisibilityAndData( @@ -1258,17 +1292,20 @@ describe('', () => { }); axiosMock - .onPost(getXBlockBaseApiUrl(courseUnitIndexMock.id), { + .onPost(getXBlockBaseApiUrl(courseSectionVerticalMock.xblock_info.id), { publish: null, metadata: { visible_to_staff_only: true, group_access: { 50: [2] }, discussion_enabled: true }, }) .reply(200, { dummy: 'value' }); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) - .replyOnce(200, { - ...courseUnitIndexMock, - visibility_state: UNIT_VISIBILITY_STATES.staffOnly, - has_explicit_staff_lock: true, + .onGet(getCourseSectionVerticalApiUrl(blockId)) + .reply(200, { + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + visibility_state: UNIT_VISIBILITY_STATES.staffOnly, + has_explicit_staff_lock: true, + }, }); const modalSaveBtn = within(configureModal) @@ -1307,13 +1344,15 @@ describe('', () => { render(); axiosMock - .onGet(getCourseUnitApiUrl(courseId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - enable_copy_paste_units: true, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + enable_copy_paste_units: true, + }, }); - await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage })); @@ -1362,20 +1401,17 @@ describe('', () => { }); axiosMock - .onGet(getClipboardUrl()) - .reply(200, clipboardXBlock); - - axiosMock - .onGet(getCourseUnitApiUrl(courseId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - enable_copy_paste_units: true, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + enable_copy_paste_units: true, + }, }); - await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage })); - userEvent.click(screen.getByRole('button', { name: messages.pasteButtonText.defaultMessage })); await waitFor(() => { const iframe = screen.getByTitle(xblockContainerIframeMessages.xblockIframeTitle.defaultMessage); @@ -1427,13 +1463,15 @@ describe('', () => { render(); axiosMock - .onGet(getCourseUnitApiUrl(courseId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - enable_copy_paste_units: true, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + enable_copy_paste_units: true, + }, }); - await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage })); @@ -1477,13 +1515,15 @@ describe('', () => { render(); axiosMock - .onGet(getCourseUnitApiUrl(courseId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - enable_copy_paste_units: true, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + enable_copy_paste_units: true, + }, }); - await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage })); @@ -1529,13 +1569,15 @@ describe('', () => { render(); axiosMock - .onGet(getCourseUnitApiUrl(courseId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - enable_copy_paste_units: true, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + enable_copy_paste_units: true, + }, }); - await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); userEvent.click(screen.getByRole('button', { name: sidebarMessages.actionButtonCopyUnitTitle.defaultMessage })); @@ -1687,8 +1729,8 @@ describe('', () => { .reply(200, {}); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) - .reply(200, courseUnitIndexMock); + .onGet(getCourseSectionVerticalApiUrl(blockId)) + .reply(200, courseSectionVerticalMock); await screen.findByText(unitDisplayName); @@ -1970,7 +2012,6 @@ describe('', () => { describe('Library Content page', () => { const newUnitId = '12345'; - const sequenceId = courseSectionVerticalMock.subsection_location; beforeEach(async () => { axiosMock @@ -1987,20 +2028,6 @@ describe('', () => { }, }); await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); - axiosMock - .onGet(getCourseUnitApiUrl(courseId)) - .reply(200, { - ...courseUnitIndexMock, - category: 'library_content', - ancestor_info: { - ...courseUnitIndexMock.ancestor_info, - child_info: { - ...courseUnitIndexMock.ancestor_info.child_info, - category: 'library_content', - }, - }, - }); - await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); }); it('navigates to library content page on receive window event', async () => { @@ -2020,8 +2047,8 @@ describe('', () => { findByTestId, } = render(); - const currentSectionName = courseUnitIndexMock.ancestor_info.ancestors[1].display_name; - const currentSubSectionName = courseUnitIndexMock.ancestor_info.ancestors[1].display_name; + const currentSectionName = courseSectionVerticalMock.xblock_info.ancestor_info.ancestors[1].display_name; + const currentSubSectionName = courseSectionVerticalMock.xblock_info.ancestor_info.ancestors[1].display_name; const unitHeaderTitle = await findByTestId('unit-header-title'); await findByText(unitDisplayName); @@ -2049,7 +2076,6 @@ describe('', () => { describe('Split Test Content page', () => { const newUnitId = '12345'; - const sequenceId = courseSectionVerticalMock.subsection_location; beforeEach(async () => { axiosMock @@ -2066,20 +2092,6 @@ describe('', () => { }, }); await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); - axiosMock - .onGet(getCourseUnitApiUrl(courseId)) - .reply(200, { - ...courseUnitIndexMock, - category: 'split_test', - ancestor_info: { - ...courseUnitIndexMock.ancestor_info, - child_info: { - ...courseUnitIndexMock.ancestor_info.child_info, - category: 'split_test', - }, - }, - }); - await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); }); it('navigates to split test content page on receive window event', async () => { @@ -2124,8 +2136,8 @@ describe('', () => { it('should render split test content page correctly', async () => { render(); - const currentSectionName = courseUnitIndexMock.ancestor_info.ancestors[1].display_name; - const currentSubSectionName = courseUnitIndexMock.ancestor_info.ancestors[1].display_name; + const currentSectionName = courseSectionVerticalMock.xblock_info.ancestor_info.ancestors[1].display_name; + const currentSubSectionName = courseSectionVerticalMock.xblock_info.ancestor_info.ancestors[1].display_name; const helpLinkUrl = 'https://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/latest/developing_course/course_components.html#components-that-contain-other-components'; waitFor(() => { @@ -2210,10 +2222,6 @@ describe('', () => { ? { ...child, block_type: 'html' } : child)); - axiosMock - .onGet(getCourseUnitApiUrl(blockId)) - .reply(200, courseUnitIndexMock); - axiosMock .onPost(postXBlockBaseApiUrl({ parent_locator: blockId, @@ -2251,15 +2259,19 @@ describe('', () => { render(); axiosMock - .onGet(getCourseUnitApiUrl(courseId)) + .onGet(getCourseSectionVerticalApiUrl(courseId)) .reply(200, { - ...courseUnitIndexMock, - upstreamInfo: { - upstreamRef: 'lct:org:lib:unit:unit-1', - upstreamLink: 'some-link', + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + upstreamInfo: { + ...courseSectionVerticalMock.xblock_info, + upstreamRef: 'lct:org:lib:unit:unit-1', + upstreamLink: 'some-link', + }, }, }); - await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); + await executeThunk(fetchCourseSectionVerticalData(courseId), store.dispatch); expect(screen.getByText(/this unit can only be edited from the \./i)).toBeInTheDocument(); diff --git a/src/course-unit/__mocks__/courseUnitIndex.js b/src/course-unit/__mocks__/courseUnitIndex.js deleted file mode 100644 index 69b083d176..0000000000 --- a/src/course-unit/__mocks__/courseUnitIndex.js +++ /dev/null @@ -1,1126 +0,0 @@ -module.exports = { - id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@867dddb6f55d410caaa9c1eb9c6743ec', - display_name: 'Getting Started', - category: 'vertical', - has_children: true, - edited_on: 'Jan 03, 2024 at 12:06 UTC', - published: true, - published_on: 'Dec 28, 2023 at 10:00 UTC', - studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@867dddb6f55d410caaa9c1eb9c6743ec', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: 'needs_attention', - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: true, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - discussion_enabled: true, - data: '', - metadata: { - display_name: 'Getting Started', - xml_attributes: { - filename: [ - 'vertical/867dddb6f55d410caaa9c1eb9c6743ec.xml', - 'vertical/867dddb6f55d410caaa9c1eb9c6743ec.xml', - ], - }, - }, - ancestor_info: { - ancestors: [ - { - id: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@19a30717eff543078a5d94ae9d6c18a5', - display_name: 'Lesson 1 - Getting Started', - category: 'sequential', - has_children: true, - edited_on: 'Jan 03, 2024 at 12:06 UTC', - published: true, - published_on: 'Dec 28, 2023 at 10:00 UTC', - studio_url: '/course/course-v1:edX+DemoX+Demo_Course?show=block-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40sequential%2Bblock%4019a30717eff543078a5d94ae9d6c18a5', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: 'needs_attention', - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: null, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - hide_after_due: false, - is_proctored_exam: false, - was_exam_ever_linked_with_external: false, - online_proctoring_rules: '', - is_practice_exam: false, - is_onboarding_exam: false, - is_time_limited: false, - exam_review_rules: '', - default_time_limit_minutes: null, - proctoring_exam_configuration_link: null, - supports_onboarding: false, - show_review_rules: true, - child_info: { - category: 'vertical', - display_name: 'Unit', - children: [ - { - id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@867dddb6f55d410caaa9c1eb9c6743ec', - display_name: 'Getting Started', - category: 'vertical', - has_children: true, - edited_on: 'Jan 03, 2024 at 12:06 UTC', - published: true, - published_on: 'Dec 28, 2023 at 10:00 UTC', - studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@867dddb6f55d410caaa9c1eb9c6743ec', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: 'needs_attention', - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: true, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - discussion_enabled: true, - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - enable_copy_paste_units: false, - }, - { - id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@4f6c1b4e316a419ab5b6bf30e6c708e9', - display_name: 'Working with Videos', - category: 'vertical', - has_children: true, - edited_on: 'Dec 28, 2023 at 10:00 UTC', - published: true, - published_on: 'Dec 28, 2023 at 10:00 UTC', - studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@4f6c1b4e316a419ab5b6bf30e6c708e9', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: 'live', - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: false, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - discussion_enabled: true, - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - enable_copy_paste_units: false, - }, - { - id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@3dc16db8d14842e38324e95d4030b8a0', - display_name: 'Videos on edX', - category: 'vertical', - has_children: true, - edited_on: 'Dec 28, 2023 at 10:00 UTC', - published: true, - published_on: 'Dec 28, 2023 at 10:00 UTC', - studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@3dc16db8d14842e38324e95d4030b8a0', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: 'live', - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: false, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - discussion_enabled: true, - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - enable_copy_paste_units: false, - }, - { - id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@4a1bba2a403f40bca5ec245e945b0d76', - display_name: 'Video Demonstrations', - category: 'vertical', - has_children: true, - edited_on: 'Dec 28, 2023 at 10:00 UTC', - published: true, - published_on: 'Dec 28, 2023 at 10:00 UTC', - studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@4a1bba2a403f40bca5ec245e945b0d76', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: 'live', - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: false, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - discussion_enabled: true, - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - enable_copy_paste_units: false, - }, - { - id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@256f17a44983429fb1a60802203ee4e0', - display_name: 'Video Presentation Styles', - category: 'vertical', - has_children: true, - edited_on: 'Dec 28, 2023 at 10:00 UTC', - published: true, - published_on: 'Dec 28, 2023 at 10:00 UTC', - studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@256f17a44983429fb1a60802203ee4e0', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: 'live', - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: false, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - discussion_enabled: true, - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - enable_copy_paste_units: false, - }, - { - id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@e3601c0abee6427d8c17e6d6f8fdddd1', - display_name: 'Interactive Questions', - category: 'vertical', - has_children: true, - edited_on: 'Dec 28, 2023 at 10:00 UTC', - published: true, - published_on: 'Dec 28, 2023 at 10:00 UTC', - studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@e3601c0abee6427d8c17e6d6f8fdddd1', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: 'live', - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: false, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - discussion_enabled: true, - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - enable_copy_paste_units: false, - }, - { - id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@a79d59cd72034188a71d388f4954a606', - display_name: 'Exciting Labs and Tools', - category: 'vertical', - has_children: true, - edited_on: 'Dec 28, 2023 at 10:00 UTC', - published: true, - published_on: 'Dec 28, 2023 at 10:00 UTC', - studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@a79d59cd72034188a71d388f4954a606', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: 'live', - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: false, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - discussion_enabled: true, - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - enable_copy_paste_units: false, - }, - { - id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@134df56c516a4a0dbb24dd5facef746e', - display_name: 'Reading Assignments', - category: 'vertical', - has_children: true, - edited_on: 'Dec 28, 2023 at 10:00 UTC', - published: true, - published_on: 'Dec 28, 2023 at 10:00 UTC', - studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@134df56c516a4a0dbb24dd5facef746e', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: 'live', - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: false, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - discussion_enabled: true, - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - enable_copy_paste_units: false, - }, - { - id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@d91b9e5d8bc64d57a1332d06bf2f2193', - display_name: 'When Are Your Exams? ', - category: 'vertical', - has_children: true, - edited_on: 'Dec 28, 2023 at 10:00 UTC', - published: true, - published_on: 'Dec 28, 2023 at 10:00 UTC', - studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@d91b9e5d8bc64d57a1332d06bf2f2193', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: 'live', - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: false, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - discussion_enabled: true, - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - enable_copy_paste_units: false, - }, - ], - }, - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - }, - { - id: 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@graded_interactions', - display_name: 'Example Week 1: Getting Started', - category: 'chapter', - has_children: true, - edited_on: 'Jan 03, 2024 at 12:06 UTC', - published: true, - published_on: 'Dec 28, 2023 at 10:00 UTC', - studio_url: '/course/course-v1:edX+DemoX+Demo_Course?show=block-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40chapter%2Bblock%40interactive_demonstrations', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: 'live', - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: null, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - highlights: [], - highlights_enabled: true, - highlights_preview_only: false, - highlights_doc_url: 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/manage_course_highlight_emails.html', - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - }, - { - id: 'block-v1:edX+DemoX+Demo_Course+type@course+block@course', - display_name: 'Demonstration Course', - category: 'course', - has_children: true, - unit_level_discussions: false, - edited_on: 'Jan 03, 2024 at 12:06 UTC', - published: true, - published_on: 'Jan 03, 2024 at 08:57 UTC', - studio_url: '/course/course-v1:edX+DemoX+Demo_Course', - released_to_students: true, - release_date: 'Feb 05, 2013 at 05:00 UTC', - visibility_state: null, - has_explicit_staff_lock: false, - start: '2013-02-05T05:00:00Z', - graded: false, - due_date: '', - due: null, - relative_weeks_due: null, - format: null, - course_graders: [ - 'Homework', - 'Exam', - ], - has_changes: null, - actions: { - deletable: true, - draggable: true, - childAddable: true, - duplicable: true, - }, - explanatory_message: null, - group_access: {}, - user_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - show_correctness: 'always', - highlights_enabled_for_messaging: false, - highlights_enabled: true, - highlights_preview_only: false, - highlights_doc_url: 'https://docs.openedx.org/en/latest/educators/how-tos/course_development/manage_course_highlight_emails.html', - enable_proctored_exams: false, - create_zendesk_tickets: true, - enable_timed_exams: true, - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - }, - ], - }, - ancestor_has_staff_lock: false, - user_partition_info: { - selectable_partitions: [ - { - id: 50, - name: 'Enrollment Track Groups', - scheme: 'enrollment_track', - groups: [ - { - id: 2, - name: 'Verified Certificate', - selected: false, - deleted: false, - }, - { - id: 1, - name: 'Audit', - selected: false, - deleted: false, - }, - ], - }, - ], - selected_partition_index: -1, - selected_groups_label: '', - }, - enable_copy_paste_units: false, - edited_by: 'edx', - published_by: null, - currently_visible_to_students: true, - has_partition_group_components: false, - release_date_from: 'Section "Example Week 1: Getting Started"', - staff_lock_from: null, - upstreamInfo: { - upstreamLink: undefined, - }, -}; diff --git a/src/course-unit/__mocks__/index.js b/src/course-unit/__mocks__/index.js index bfbbb9a4bb..0b8b7f5f44 100644 --- a/src/course-unit/__mocks__/index.js +++ b/src/course-unit/__mocks__/index.js @@ -1,4 +1,3 @@ -export { default as courseUnitIndexMock } from './courseUnitIndex'; export { default as courseSectionVerticalMock } from './courseSectionVertical'; export { default as courseUnitMock } from './courseUnit'; export { default as courseCreateXblockMock } from './courseCreateXblock'; diff --git a/src/course-unit/breadcrumbs/Breadcrumbs.test.tsx b/src/course-unit/breadcrumbs/Breadcrumbs.test.tsx index e4c93deb8f..fb727d8033 100644 --- a/src/course-unit/breadcrumbs/Breadcrumbs.test.tsx +++ b/src/course-unit/breadcrumbs/Breadcrumbs.test.tsx @@ -5,11 +5,11 @@ import { } from '../../testUtils'; import { executeThunk } from '../../utils'; -import { getCourseSectionVerticalApiUrl, getCourseUnitApiUrl } from '../data/api'; +import { getCourseSectionVerticalApiUrl } from '../data/api'; import { getApiWaffleFlagsUrl } from '../../data/api'; import { fetchWaffleFlags } from '../../data/thunks'; -import { fetchCourseSectionVerticalData, fetchCourseUnitQuery } from '../data/thunk'; -import { courseSectionVerticalMock, courseUnitIndexMock } from '../__mocks__'; +import { fetchCourseSectionVerticalData } from '../data/thunk'; +import { courseSectionVerticalMock } from '../__mocks__'; import Breadcrumbs from './Breadcrumbs'; let axiosMock; @@ -43,9 +43,9 @@ describe('', () => { reduxStore = mocks.reduxStore; axiosMock - .onGet(getCourseUnitApiUrl(courseId)) - .reply(200, courseUnitIndexMock); - await executeThunk(fetchCourseUnitQuery(courseId), reduxStore.dispatch); + .onGet(getCourseSectionVerticalApiUrl(courseId)) + .reply(200, courseSectionVerticalMock); + await executeThunk(fetchCourseSectionVerticalData(courseId), reduxStore.dispatch); axiosMock .onGet(getCourseSectionVerticalApiUrl(courseId)) .reply(200, courseSectionVerticalMock); diff --git a/src/course-unit/course-sequence/sequence-navigation/SequenceNavigation.jsx b/src/course-unit/course-sequence/sequence-navigation/SequenceNavigation.jsx index 0af7ef63bf..59bfaaafe2 100644 --- a/src/course-unit/course-sequence/sequence-navigation/SequenceNavigation.jsx +++ b/src/course-unit/course-sequence/sequence-navigation/SequenceNavigation.jsx @@ -35,7 +35,7 @@ const SequenceNavigation = ({ const shouldDisplayNotificationTriggerInSequence = useWindowSize().width < breakpoints.small.minWidth; const renderUnitButtons = () => { - if (sequence?.unitIds?.length === 0 || unitId === null) { + if (sequence.unitIds.length === 0 || unitId === null) { return (
); diff --git a/src/course-unit/data/api.js b/src/course-unit/data/api.js index 58aa284264..ba505c3dda 100644 --- a/src/course-unit/data/api.js +++ b/src/course-unit/data/api.js @@ -7,7 +7,6 @@ import { isUnitReadOnly, normalizeCourseSectionVerticalData, updateXBlockBlockId const getStudioBaseUrl = () => getConfig().STUDIO_BASE_URL; -export const getCourseUnitApiUrl = (itemId) => `${getStudioBaseUrl()}/xblock/container/${itemId}`; export const getXBlockBaseApiUrl = (itemId) => `${getStudioBaseUrl()}/xblock/${itemId}`; export const getCourseSectionVerticalApiUrl = (itemId) => `${getStudioBaseUrl()}/api/contentstore/v1/container_handler/${itemId}`; export const getCourseVerticalChildrenApiUrl = (itemId) => `${getStudioBaseUrl()}/api/contentstore/v1/container/vertical/${itemId}/children`; @@ -15,20 +14,6 @@ export const getCourseOutlineInfoUrl = (courseId) => `${getStudioBaseUrl()}/cour export const postXBlockBaseApiUrl = () => `${getStudioBaseUrl()}/xblock/`; export const libraryBlockChangesUrl = (blockId) => `${getStudioBaseUrl()}/api/contentstore/v2/downstreams/${blockId}/sync`; -/** - * Get course unit. - * @param {string} unitId - * @returns {Promise} - */ -export async function getCourseUnitData(unitId) { - const { data } = await getAuthenticatedHttpClient() - .get(getCourseUnitApiUrl(unitId)); - - const result = camelCaseObject(data); - result.readOnly = isUnitReadOnly(result); - return result; -} - /** * Edit course unit display name. * @param {string} unitId @@ -47,15 +32,18 @@ export async function editUnitDisplayName(unitId, displayName) { } /** - * Get an object containing course section vertical data. + * Fetch vertical block data from the container_handler endpoint. * @param {string} unitId * @returns {Promise} */ -export async function getCourseSectionVerticalData(unitId) { +export async function getVerticalData(unitId) { const { data } = await getAuthenticatedHttpClient() .get(getCourseSectionVerticalApiUrl(unitId)); - return normalizeCourseSectionVerticalData(data); + const courseSectionVerticalData = normalizeCourseSectionVerticalData(data); + courseSectionVerticalData.xblockInfo.readOnly = isUnitReadOnly(courseSectionVerticalData.xblockInfo); + + return courseSectionVerticalData; } /** diff --git a/src/course-unit/data/selectors.js b/src/course-unit/data/selectors.js index 872bc85305..322c39e8ce 100644 --- a/src/course-unit/data/selectors.js +++ b/src/course-unit/data/selectors.js @@ -1,7 +1,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { RequestStatus } from 'CourseAuthoring/data/constants'; -export const getCourseUnitData = (state) => state.courseUnit.unit; +export const getCourseUnitData = (state) => state.courseUnit.courseSectionVertical.xblockInfo ?? {}; export const getCanEdit = (state) => state.courseUnit.canEdit; export const getStaticFileNotices = (state) => state.courseUnit.staticFileNotices; export const getCourseUnit = (state) => state.courseUnit; diff --git a/src/course-unit/data/slice.js b/src/course-unit/data/slice.js index 1755d0960f..3d87139087 100644 --- a/src/course-unit/data/slice.js +++ b/src/course-unit/data/slice.js @@ -12,11 +12,9 @@ const slice = createSlice({ isTitleEditFormOpen: false, canEdit: true, loadingStatus: { - fetchUnitLoadingStatus: RequestStatus.IN_PROGRESS, courseSectionVerticalLoadingStatus: RequestStatus.IN_PROGRESS, courseVerticalChildrenLoadingStatus: RequestStatus.IN_PROGRESS, }, - unit: {}, courseSectionVertical: {}, courseVerticalChildren: { children: [], isPublished: true }, staticFileNotices: {}, @@ -31,15 +29,6 @@ const slice = createSlice({ }, }, reducers: { - fetchCourseItemSuccess: (state, { payload }) => { - state.unit = payload; - }, - updateLoadingCourseUnitStatus: (state, { payload }) => { - state.loadingStatus = { - ...state.loadingStatus, - fetchUnitLoadingStatus: payload.status, - }; - }, updateQueryPendingStatus: (state, { payload }) => { state.isQueryPending = payload; }, @@ -81,12 +70,6 @@ const slice = createSlice({ createUnitXblockLoadingStatus: payload.status, }; }, - addNewUnitStatus: (state, { payload }) => { - state.loadingStatus = { - ...state.loadingStatus, - fetchUnitLoadingStatus: payload.status, - }; - }, updateCourseVerticalChildren: (state, { payload }) => { state.courseVerticalChildren = payload; }, @@ -109,8 +92,6 @@ const slice = createSlice({ }); export const { - fetchCourseItemSuccess, - updateLoadingCourseUnitStatus, updateSavingStatus, updateModel, fetchSequenceRequest, diff --git a/src/course-unit/data/thunk.js b/src/course-unit/data/thunk.js index 481b9c6ca8..9374a3d078 100644 --- a/src/course-unit/data/thunk.js +++ b/src/course-unit/data/thunk.js @@ -10,9 +10,8 @@ import { NOTIFICATION_MESSAGES } from '../../constants'; import { updateModel, updateModels } from '../../generic/model-store'; import { messageTypes } from '../constants'; import { - getCourseUnitData, editUnitDisplayName, - getCourseSectionVerticalData, + getVerticalData, createCourseXblock, getCourseVerticalChildren, handleCourseUnitVisibilityAndData, @@ -22,8 +21,6 @@ import { patchUnitItem, } from './api'; import { - updateLoadingCourseUnitStatus, - fetchCourseItemSuccess, updateSavingStatus, fetchSequenceRequest, fetchSequenceFailure, @@ -40,30 +37,13 @@ import { } from './slice'; import { getNotificationMessage } from './utils'; -export function fetchCourseUnitQuery(courseId) { - return async (dispatch) => { - dispatch(updateLoadingCourseUnitStatus({ status: RequestStatus.IN_PROGRESS })); - - try { - const courseUnit = await getCourseUnitData(courseId); - - dispatch(fetchCourseItemSuccess(courseUnit)); - dispatch(updateLoadingCourseUnitStatus({ status: RequestStatus.SUCCESSFUL })); - return true; - } catch (error) { - dispatch(updateLoadingCourseUnitStatus({ status: RequestStatus.FAILED })); - return false; - } - }; -} - export function fetchCourseSectionVerticalData(courseId, sequenceId) { return async (dispatch) => { dispatch(updateLoadingCourseSectionVerticalDataStatus({ status: RequestStatus.IN_PROGRESS })); dispatch(fetchSequenceRequest({ sequenceId })); try { - const courseSectionVerticalData = await getCourseSectionVerticalData(courseId); + const courseSectionVerticalData = await getVerticalData(courseId); dispatch(fetchCourseSectionVerticalDataSuccess(courseSectionVerticalData)); dispatch(updateLoadingCourseSectionVerticalDataStatus({ status: RequestStatus.SUCCESSFUL })); dispatch(updateModel({ @@ -94,8 +74,7 @@ export function editCourseItemQuery(itemId, displayName, sequenceId) { try { await editUnitDisplayName(itemId, displayName).then(async (result) => { if (result) { - const courseUnit = await getCourseUnitData(itemId); - const courseSectionVerticalData = await getCourseSectionVerticalData(itemId); + const courseSectionVerticalData = await getVerticalData(itemId); dispatch(fetchCourseSectionVerticalDataSuccess(courseSectionVerticalData)); dispatch(updateLoadingCourseSectionVerticalDataStatus({ status: RequestStatus.SUCCESSFUL })); dispatch(updateModel({ @@ -107,7 +86,6 @@ export function editCourseItemQuery(itemId, displayName, sequenceId) { models: courseSectionVerticalData.units || [], })); dispatch(fetchSequenceSuccess({ sequenceId })); - dispatch(fetchCourseItemSuccess(courseUnit)); dispatch(hideProcessingNotification()); dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); } @@ -146,8 +124,8 @@ export function editCourseUnitVisibilityAndData( if (callback) { callback(); } - const courseUnit = await getCourseUnitData(blockId); - dispatch(fetchCourseItemSuccess(courseUnit)); + const courseSectionVerticalData = await getVerticalData(blockId); + dispatch(fetchCourseSectionVerticalDataSuccess(courseSectionVerticalData)); const courseVerticalChildrenData = await getCourseVerticalChildren(blockId); dispatch(updateCourseVerticalChildren(courseVerticalChildrenData)); dispatch(hideProcessingNotification()); @@ -174,7 +152,7 @@ export function createNewCourseXBlock(body, callback, blockId, sendMessageToIfra if (result) { const formattedResult = camelCaseObject(result); if (body.category === 'vertical') { - const courseSectionVerticalData = await getCourseSectionVerticalData(formattedResult.locator); + const courseSectionVerticalData = await getVerticalData(formattedResult.locator); dispatch(fetchCourseSectionVerticalDataSuccess(courseSectionVerticalData)); } if (body.stagedContent) { @@ -194,8 +172,8 @@ export function createNewCourseXBlock(body, callback, blockId, sendMessageToIfra sendMessageToIframe(messageTypes.addXBlock, { data: result }); } const currentBlockId = body.category === 'vertical' ? formattedResult.locator : blockId; - const courseUnit = await getCourseUnitData(currentBlockId); - dispatch(fetchCourseItemSuccess(courseUnit)); + const courseSectionVerticalData = await getVerticalData(currentBlockId); + dispatch(fetchCourseSectionVerticalDataSuccess(courseSectionVerticalData)); } }); } catch (error) { @@ -240,8 +218,8 @@ export function deleteUnitItemQuery(itemId, xblockId, sendMessageToIframe) { try { await deleteUnitItem(xblockId); sendMessageToIframe(messageTypes.completeXBlockDeleting, { locator: xblockId }); - const courseUnit = await getCourseUnitData(itemId); - dispatch(fetchCourseItemSuccess(courseUnit)); + const courseSectionVerticalData = await getVerticalData(itemId); + dispatch(fetchCourseSectionVerticalDataSuccess(courseSectionVerticalData)); dispatch(hideProcessingNotification()); dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); } catch (error) { @@ -259,8 +237,8 @@ export function duplicateUnitItemQuery(itemId, xblockId, callback) { try { const { courseKey, locator } = await duplicateUnitItem(itemId, xblockId); callback(courseKey, locator); - const courseUnit = await getCourseUnitData(itemId); - dispatch(fetchCourseItemSuccess(courseUnit)); + const courseSectionVerticalData = await getVerticalData(itemId); + dispatch(fetchCourseSectionVerticalDataSuccess(courseSectionVerticalData)); const courseVerticalChildrenData = await getCourseVerticalChildren(itemId); dispatch(updateCourseVerticalChildren(courseVerticalChildrenData)); dispatch(hideProcessingNotification()); @@ -316,8 +294,8 @@ export function patchUnitItemQuery({ dispatch(updateCourseOutlineInfoLoadingStatus({ status: RequestStatus.IN_PROGRESS })); callbackFn(sourceLocator); try { - const courseUnit = await getCourseUnitData(currentParentLocator); - dispatch(fetchCourseItemSuccess(courseUnit)); + const courseSectionVerticalData = await getVerticalData(currentParentLocator); + dispatch(fetchCourseSectionVerticalDataSuccess(courseSectionVerticalData)); } catch (error) { handleResponseErrors(error, dispatch, updateSavingStatus); } @@ -335,8 +313,8 @@ export function updateCourseUnitSidebar(itemId) { dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.saving)); try { - const courseUnit = await getCourseUnitData(itemId); - dispatch(fetchCourseItemSuccess(courseUnit)); + const courseSectionVerticalData = await getVerticalData(itemId); + dispatch(fetchCourseSectionVerticalDataSuccess(courseSectionVerticalData)); dispatch(hideProcessingNotification()); dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); } catch (error) { diff --git a/src/course-unit/header-title/HeaderTitle.test.jsx b/src/course-unit/header-title/HeaderTitle.test.jsx index fbb08b0e62..550b804da5 100644 --- a/src/course-unit/header-title/HeaderTitle.test.jsx +++ b/src/course-unit/header-title/HeaderTitle.test.jsx @@ -8,9 +8,9 @@ import { initializeMockApp } from '@edx/frontend-platform'; import initializeStore from '../../store'; import { executeThunk } from '../../utils'; -import { getCourseUnitApiUrl } from '../data/api'; -import { fetchCourseUnitQuery } from '../data/thunk'; -import { courseUnitIndexMock } from '../__mocks__'; +import { getCourseSectionVerticalApiUrl } from '../data/api'; +import { fetchCourseSectionVerticalData } from '../data/thunk'; +import { courseSectionVerticalMock } from '../__mocks__'; import HeaderTitle from './HeaderTitle'; import messages from './messages'; @@ -52,9 +52,9 @@ describe('', () => { store = initializeStore(); axiosMock = new MockAdapter(getAuthenticatedHttpClient()); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) - .reply(200, courseUnitIndexMock); - await executeThunk(fetchCourseUnitQuery(blockId), store.dispatch); + .onGet(getCourseSectionVerticalApiUrl(blockId)) + .reply(200, courseSectionVerticalMock); + await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); }); it('render HeaderTitle component correctly', () => { @@ -80,14 +80,18 @@ describe('', () => { // Override mock unit with one sourced from an upstream library axiosMock = new MockAdapter(getAuthenticatedHttpClient()); axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - upstreamInfo: { - upstreamRef: 'lct:org:lib:unit:unit-1', + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + upstreamInfo: { + ...courseSectionVerticalMock.xblock_info.upstreamInfo, + upstreamRef: 'lct:org:lib:unit:unit-1', + }, }, }); - await executeThunk(fetchCourseUnitQuery(blockId), store.dispatch); + await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); const { getByRole } = renderComponent(); @@ -122,16 +126,19 @@ describe('', () => { it('displays a visibility message with the selected groups for the unit', async () => { axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - user_partition_info: { - ...courseUnitIndexMock.user_partition_info, - selected_partition_index: 1, - selected_groups_label: 'Visibility group 1', + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + user_partition_info: { + ...courseSectionVerticalMock.xblock_info.user_partition_info, + selected_partition_index: 1, + selected_groups_label: 'Visibility group 1', + }, }, }); - await executeThunk(fetchCourseUnitQuery(blockId), store.dispatch); + await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); const { getByText } = renderComponent(); const visibilityMessage = messages.definedVisibilityMessage.defaultMessage .replace('{selectedGroupsLabel}', 'Visibility group 1'); @@ -143,12 +150,15 @@ describe('', () => { it('displays a visibility message with the selected groups for some of xblock', async () => { axiosMock - .onGet(getCourseUnitApiUrl(blockId)) + .onGet(getCourseSectionVerticalApiUrl(blockId)) .reply(200, { - ...courseUnitIndexMock, - has_partition_group_components: true, + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + has_partition_group_components: true, + }, }); - await executeThunk(fetchCourseUnitQuery(blockId), store.dispatch); + await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); const { getByText } = renderComponent(); await waitFor(() => { diff --git a/src/course-unit/hooks.jsx b/src/course-unit/hooks.jsx index f707bae452..ffd1c25614 100644 --- a/src/course-unit/hooks.jsx +++ b/src/course-unit/hooks.jsx @@ -18,7 +18,6 @@ import { editCourseItemQuery, editCourseUnitVisibilityAndData, fetchCourseSectionVerticalData, - fetchCourseUnitQuery, fetchCourseVerticalChildrenData, getCourseOutlineInfoQuery, patchUnitItemQuery, @@ -198,7 +197,6 @@ export const useCourseUnit = ({ courseId, blockId }) => { }, [savingStatus]); useEffect(() => { - dispatch(fetchCourseUnitQuery(blockId)); dispatch(fetchCourseSectionVerticalData(blockId, sequenceId)); dispatch(fetchCourseVerticalChildrenData(blockId, isSplitTestType)); handleNavigate(sequenceId); diff --git a/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.test.jsx b/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.test.jsx index 16bd0ef9af..a68c2f238a 100644 --- a/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.test.jsx +++ b/src/course-unit/sidebar/components/sidebar-footer/ActionButtons.test.jsx @@ -10,10 +10,10 @@ import userEvent from '@testing-library/user-event'; import initializeStore from '../../../../store'; import { executeThunk } from '../../../../utils'; import { clipboardUnit } from '../../../../__mocks__'; -import { getCourseUnitApiUrl } from '../../../data/api'; +import { getCourseSectionVerticalApiUrl } from '../../../data/api'; import { getClipboardUrl } from '../../../../generic/data/api'; -import { fetchCourseUnitQuery } from '../../../data/thunk'; -import { courseUnitIndexMock } from '../../../__mocks__'; +import { fetchCourseSectionVerticalData } from '../../../data/thunk'; +import { courseSectionVerticalMock } from '../../../__mocks__'; import messages from '../../messages'; import ActionButtons from './ActionButtons'; @@ -46,8 +46,14 @@ describe('', () => { store = initializeStore(); axiosMock = new MockAdapter(getAuthenticatedHttpClient()); axiosMock - .onGet(getCourseUnitApiUrl(courseId)) - .reply(200, { ...courseUnitIndexMock, enable_copy_paste_units: true }); + .onGet(getCourseSectionVerticalApiUrl(courseId)) + .reply(200, { + ...courseSectionVerticalMock, + xblock_info: { + ...courseSectionVerticalMock.xblock_info, + enable_copy_paste_units: true, + }, + }); axiosMock .onPost(getClipboardUrl()) .reply(200, clipboardUnit); @@ -57,7 +63,7 @@ describe('', () => { queryClient = new QueryClient(); - await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); + await executeThunk(fetchCourseSectionVerticalData(courseId), store.dispatch); }); it('render ActionButtons component with Copy to clipboard', () => { @@ -74,7 +80,9 @@ describe('', () => { userEvent.click(copyXBlockBtn); expect(axiosMock.history.post.length).toBe(1); - expect(axiosMock.history.post[0].data).toBe(JSON.stringify({ usage_key: courseUnitIndexMock.id })); + expect(axiosMock.history.post[0].data).toBe( + JSON.stringify({ usage_key: courseSectionVerticalMock.xblock_info.id }), + ); jest.resetAllMocks(); }); }); diff --git a/src/files-and-videos/videos-page/VideoThumbnail.jsx b/src/files-and-videos/videos-page/VideoThumbnail.jsx index 2929c6d32d..fb7bf62054 100644 --- a/src/files-and-videos/videos-page/VideoThumbnail.jsx +++ b/src/files-and-videos/videos-page/VideoThumbnail.jsx @@ -48,21 +48,30 @@ const VideoThumbnail = ({ const isFailed = VIDEO_FAILURE_STATUSES.includes(status); const failedMessage = intl.formatMessage(messages.failedCheckboxLabel); - const showThumbnail = allowThumbnailUpload && thumbnail && isUploaded; + const showThumbnail = allowThumbnailUpload && isUploaded; return (
- {allowThumbnailUpload && showThumbnail &&
} + {allowThumbnailUpload && isUploaded &&
} {showThumbnail && !thumbnailError && pageLoadStatus === RequestStatus.SUCCESSFUL ? ( <>
- {intl.formatMessage(messages.thumbnailAltMessage, setThumbnailError(true)} - /> + { thumbnail ? ( + {intl.formatMessage(messages.thumbnailAltMessage, setThumbnailError(true)} + /> + ) : ( +
+ +
+ )}