Skip to content

Commit e0e5b00

Browse files
committed
refactor(course-outline): clean up outline polish items
- Replace CourseOutlineState interface with OutlineLoadingStatus type - Replace AccessManagedXBlockDataTypes with Pick<XBlockBase, ...> - Remove cancelReorderPreview alias in useOutlineReorderState - Fix useCreateBlockSidebar payload type (CreateCourseXBlockType & ParentIds) - Simplify OutlineModals props (import hook output types directly) - Pass highlights/configure hook objects directly in CourseOutline - Multiple low-impact dedups: pickDefined, forEachDismissedKey, PageWrap layout, dead error fields, createBlock helper 143/143 affected tests + 3/3 CourseAuthoringRoutes pass.
1 parent cc57925 commit e0e5b00

23 files changed

Lines changed: 352 additions & 412 deletions

src/CourseAuthoringRoutes.tsx

Lines changed: 113 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
Routes,
44
Route,
55
useParams,
6+
Outlet,
67
} from 'react-router-dom';
78
import { getConfig } from '@edx/frontend-platform';
89
import { PageWrap } from '@edx/frontend-platform/react';
@@ -38,6 +39,13 @@ import { CourseAuthoringProvider } from './CourseAuthoringContext';
3839
import { CourseImportProvider } from './import-page/CourseImportContext';
3940
import { CourseExportProvider } from './export-page/CourseExportContext';
4041

42+
/** Layout route: renders its child routes inside PageWrap. */
43+
const PageWrapLayout = () => (
44+
<PageWrap>
45+
<Outlet />
46+
</PageWrap>
47+
);
48+
4149
/**
4250
* As of this writing, these routes are mounted at a path prefixed with the following:
4351
*
@@ -62,208 +70,134 @@ const CourseAuthoringRoutes = () => {
6270
throw new Error('Error: route is missing courseId.');
6371
}
6472

73+
const enableVideos = getConfig().ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN === 'true';
74+
const enableCertificates = getConfig().ENABLE_CERTIFICATE_PAGE === 'true';
75+
6576
return (
6677
<CourseAuthoringProvider courseId={courseId}>
6778
<CourseAuthoringPage>
6879
<Routes>
69-
<Route
70-
path="/"
71-
element={
72-
<PageWrap>
80+
<Route element={<PageWrapLayout />}>
81+
<Route
82+
path="/"
83+
element={
7384
<CourseOutlineProvider key={courseId}>
7485
<OutlineSidebarPagesProvider>
7586
<OutlineSidebarProvider>
7687
<CourseOutline />
7788
</OutlineSidebarProvider>
7889
</OutlineSidebarPagesProvider>
7990
</CourseOutlineProvider>
80-
</PageWrap>
81-
}
82-
/>
83-
<Route
84-
path="course_info"
85-
element={
86-
<PageWrap>
87-
<CourseUpdates />
88-
</PageWrap>
89-
}
90-
/>
91-
<Route
92-
path="libraries"
93-
element={
94-
<PageWrap>
95-
<CourseLibraries />
96-
</PageWrap>
97-
}
98-
/>
99-
<Route
100-
path="assets"
101-
element={
102-
<PageWrap>
103-
<FilesPage />
104-
</PageWrap>
105-
}
106-
/>
107-
<Route
108-
path="videos"
109-
element={getConfig().ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN === 'true'
110-
? (
111-
<PageWrap>
112-
<VideosPage />
113-
</PageWrap>
114-
)
115-
: null}
116-
/>
117-
<Route
118-
path="pages-and-resources/*"
119-
element={
120-
<PageWrap>
121-
<PagesAndResources />
122-
</PageWrap>
123-
}
124-
/>
125-
<Route
126-
path="proctored-exam-settings"
127-
element={<Navigate replace to={`/course/${courseId}/pages-and-resources`} />}
128-
/>
129-
<Route
130-
path="custom-pages/*"
131-
element={
132-
<PageWrap>
133-
<CustomPages />
134-
</PageWrap>
135-
}
136-
/>
137-
<Route
138-
path="/subsection/:subsectionId"
139-
element={
140-
<PageWrap>
141-
<SubsectionUnitRedirect />
142-
</PageWrap>
143-
}
144-
/>
145-
{DECODED_ROUTES.COURSE_UNIT.map((path) => (
91+
}
92+
/>
14693
<Route
147-
key={path}
148-
path={path}
149-
element={
150-
<PageWrap>
94+
path="course_info"
95+
element={<CourseUpdates />}
96+
/>
97+
<Route
98+
path="libraries"
99+
element={<CourseLibraries />}
100+
/>
101+
<Route
102+
path="assets"
103+
element={<FilesPage />}
104+
/>
105+
{enableVideos && (
106+
<Route
107+
path="videos"
108+
element={<VideosPage />}
109+
/>
110+
)}
111+
<Route
112+
path="pages-and-resources/*"
113+
element={<PagesAndResources />}
114+
/>
115+
<Route
116+
path="custom-pages/*"
117+
element={<CustomPages />}
118+
/>
119+
<Route
120+
path="/subsection/:subsectionId"
121+
element={<SubsectionUnitRedirect />}
122+
/>
123+
{DECODED_ROUTES.COURSE_UNIT.map((path) => (
124+
<Route
125+
key={path}
126+
path={path}
127+
element={
151128
<IframeProvider>
152129
<CourseUnit />
153130
</IframeProvider>
154-
</PageWrap>
155-
}
131+
}
132+
/>
133+
))}
134+
<Route
135+
path="editor/course-videos/:blockId"
136+
element={<VideoSelectorContainer />}
156137
/>
157-
))}
158-
<Route
159-
path="editor/course-videos/:blockId"
160-
element={
161-
<PageWrap>
162-
<VideoSelectorContainer />
163-
</PageWrap>
164-
}
165-
/>
166-
<Route
167-
path="editor/:blockType/:blockId?"
168-
element={
169-
<PageWrap>
170-
<EditorContainer learningContextId={courseId} />
171-
</PageWrap>
172-
}
173-
/>
174-
<Route
175-
path="settings/details"
176-
element={
177-
<PageWrap>
178-
<ScheduleAndDetails />
179-
</PageWrap>
180-
}
181-
/>
182-
<Route
183-
path="settings/grading"
184-
element={
185-
<PageWrap>
186-
<GradingSettings />
187-
</PageWrap>
188-
}
189-
/>
190-
<Route
191-
path="course_team"
192-
element={
193-
<PageWrap>
194-
<CourseTeam />
195-
</PageWrap>
196-
}
197-
/>
198-
<Route
199-
path="group_configurations"
200-
element={
201-
<PageWrap>
202-
<GroupConfigurations />
203-
</PageWrap>
204-
}
205-
/>
206-
<Route
207-
path="settings/advanced"
208-
element={
209-
<PageWrap>
210-
<AdvancedSettings />
211-
</PageWrap>
212-
}
213-
/>
214-
<Route
215-
path="import"
216-
element={
217-
<PageWrap>
138+
<Route
139+
path="editor/:blockType/:blockId?"
140+
element={<EditorContainer learningContextId={courseId} />}
141+
/>
142+
<Route
143+
path="settings/details"
144+
element={<ScheduleAndDetails />}
145+
/>
146+
<Route
147+
path="settings/grading"
148+
element={<GradingSettings />}
149+
/>
150+
<Route
151+
path="course_team"
152+
element={<CourseTeam />}
153+
/>
154+
<Route
155+
path="group_configurations"
156+
element={<GroupConfigurations />}
157+
/>
158+
<Route
159+
path="settings/advanced"
160+
element={<AdvancedSettings />}
161+
/>
162+
<Route
163+
path="import"
164+
element={
218165
<CourseImportProvider>
219166
<CourseImportPage />
220167
</CourseImportProvider>
221-
</PageWrap>
222-
}
223-
/>
224-
<Route
225-
path="export"
226-
element={
227-
<PageWrap>
168+
}
169+
/>
170+
<Route
171+
path="export"
172+
element={
228173
<CourseExportProvider>
229174
<CourseExportPage />
230175
</CourseExportProvider>
231-
</PageWrap>
232-
}
233-
/>
234-
<Route
235-
path="optimizer"
236-
element={
237-
<PageWrap>
238-
<CourseOptimizerPage />
239-
</PageWrap>
240-
}
241-
/>
242-
<Route
243-
path="checklists"
244-
element={
245-
<PageWrap>
246-
<CourseChecklist />
247-
</PageWrap>
248-
}
249-
/>
250-
<Route
251-
path="certificates"
252-
element={getConfig().ENABLE_CERTIFICATE_PAGE === 'true'
253-
? (
254-
<PageWrap>
255-
<Certificates />
256-
</PageWrap>
257-
)
258-
: null}
259-
/>
176+
}
177+
/>
178+
<Route
179+
path="optimizer"
180+
element={<CourseOptimizerPage />}
181+
/>
182+
<Route
183+
path="checklists"
184+
element={<CourseChecklist />}
185+
/>
186+
{enableCertificates && (
187+
<Route
188+
path="certificates"
189+
element={<Certificates />}
190+
/>
191+
)}
192+
<Route
193+
path="textbooks"
194+
element={<Textbooks />}
195+
/>
196+
</Route>
197+
{/* Routes without PageWrap */}
260198
<Route
261-
path="textbooks"
262-
element={
263-
<PageWrap>
264-
<Textbooks />
265-
</PageWrap>
266-
}
199+
path="proctored-exam-settings"
200+
element={<Navigate replace to={`/course/${courseId}/pages-and-resources`} />}
267201
/>
268202
</Routes>
269203
</CourseAuthoringPage>

src/course-outline/CourseOutline.tsx

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import { RequestStatus } from '@src/data/constants';
1919
import SubHeader from '@src/generic/sub-header/SubHeader';
2020
import InternetConnectionAlert from '@src/generic/internet-connection-alert';
2121

22-
2322
import AlertMessage from '@src/generic/alert-message';
2423
import getPageHeadTitle from '@src/generic/utils';
2524
import CourseOutlineHeaderActionsSlot from '@src/plugin-slots/CourseOutlineHeaderActionsSlot';
@@ -319,18 +318,8 @@ const CourseOutline = () => {
319318
</div>
320319
</section>
321320
<OutlineModals
322-
isEnableHighlightsModalOpen={highlightsModal.isEnableHighlightsModalOpen}
323-
closeEnableHighlightsModal={highlightsModal.closeEnableHighlightsModal}
324-
handleEnableHighlightsSubmit={highlightsModal.handleEnableHighlightsSubmit}
325-
isHighlightsModalOpen={highlightsModal.isHighlightsModalOpen}
326-
closeHighlightsModal={highlightsModal.closeHighlightsModal}
327-
handleHighlightsFormSubmit={highlightsModal.handleHighlightsFormSubmit}
328-
highlightsModalCurrentId={highlightsModal.highlightsModalCurrentId}
329-
isConfigureModalOpen={configureDialog.isConfigureModalOpen}
330-
handleConfigureModalClose={configureDialog.handleConfigureModalClose}
331-
handleConfigureItemSubmitWrapper={configureDialog.handleConfigureItemSubmitWrapper}
332-
isOverflowVisible={configureDialog.isOverflowVisible}
333-
configureItemData={configureDialog.currentItemData}
321+
highlights={highlightsModal}
322+
configure={configureDialog}
334323
/>
335324
</Container>
336325
<div className="alert-toast">
@@ -342,7 +331,7 @@ const CourseOutline = () => {
342331
{toastMessage && (
343332
<Toast
344333
show
345-
onClose={/* istanbul ignore next */ () => setToastMessage(null)}
334+
onClose={/* istanbul ignore next: toast dismissal, trivial setState */ () => setToastMessage(null)}
346335
data-testid="taxonomy-toast"
347336
>
348337
{toastMessage}

src/course-outline/CourseOutlineContext.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import type { ModalState } from '@src/CourseAuthoringContext';
3232

3333
import {
3434
CourseOutline,
35-
CourseOutlineState as LegacyCourseOutlineState,
35+
OutlineLoadingStatus,
3636
CourseOutlineStatusBar,
3737
} from './data';
3838

@@ -45,7 +45,7 @@ type CourseOutlineContextData = {
4545
statusBarData: CourseOutlineStatusBar;
4646
savingStatus: string;
4747
errors: OutlinePageErrors;
48-
loadingStatus: LegacyCourseOutlineState['loadingStatus'];
48+
loadingStatus: OutlineLoadingStatus;
4949
isLoading: boolean;
5050
isLoadingDenied: boolean;
5151
isCustomRelativeDatesActive: boolean;

0 commit comments

Comments
 (0)