Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ab0e0d7
refactor: remove custom order function from course libraries list (#1…
navinkarkera May 1, 2025
b375806
perf: use Library search results to populate container card preview […
pomegranited May 2, 2025
8ffafc0
fix: manage access modal on duplicated xblock (#1874)
ihor-romaniuk May 7, 2025
d5e36cf
fix: unit pages ux bugs [FC-0083] (#1884) (#1916)
rpenido May 7, 2025
79f865b
fix: UX issues in unit page (#1913) (#1923)
navinkarkera May 8, 2025
6c4634e
fix: invalidate search results when publishing all changes in library…
pomegranited May 9, 2025
a162929
fix: improve focus/selected style on library authoring (#1918) (#1930)
rpenido May 12, 2025
fab786a
fix: review/sync bugs [FC-0083] (#1905) (#1941)
rpenido May 12, 2025
3d6e221
fix: Issue with read-only units in libraries & published version of u…
ChrisChV May 13, 2025
1919eb4
fix: search modal refresh on typing (#1938) (#1948)
navinkarkera May 14, 2025
403dfa1
[Teak] backport #1949, #1999 and #2002 (#2006)
navinkarkera May 21, 2025
976dfca
fix: change InplaceTextEditor style and add optimistic update (#1953)…
rpenido May 21, 2025
dd731a0
fix: rename library publish button (#2015)
rpenido May 21, 2025
944d131
fix: do open editor of new xblock when duplicating (#2017)
DanielVZ96 May 22, 2025
212a54f
[Teak] fix: Inconsistent publish status filter menu placement & fix: …
ChrisChV May 22, 2025
317bc75
fix: refresh xblock inline after accepting/rejecting library sync (#2…
pomegranited May 23, 2025
e34df7f
fix: set maxHeight on TextEditor TinyMce widget [FC-0090] (#2024) (#2…
pomegranited May 26, 2025
7dfd93d
fix: upstreamInfo is not always provided (#2041) (#2042)
pomegranited May 29, 2025
d325a92
fix: selection card wiggle (#2047)
rpenido May 29, 2025
2beb91c
fix: set unit preview readonly on sidebar (#2008) (#2059)
rpenido Jun 2, 2025
19ef805
fix: backport changes for html button in text component markdown edit…
tonybusa Jun 4, 2025
1ff5e5b
fix: markdown editor issues in modal (#2076)
Anas12091101 Jun 4, 2025
efb1a28
fix: Expand all now expands subsections (#2085)
vmnavarro94 Jun 5, 2025
fcdf1fd
fix: files & uploads menu was truncated due to overflow-x (#2071) (#2…
diana-villalvazo-wgu Jun 5, 2025
3e737b5
fix: (backport) remove an extra editing xblock modal on unit page (#2…
ihor-romaniuk Jun 11, 2025
1968d14
fix: (backport) enable markdown editor in libraries (#2098)
bradenmacdonald Jun 12, 2025
86d0a7e
fix: remove icon and empty breadcrumb from libraries (#2129) (#2133)
diana-villalvazo-wgu Jun 12, 2025
4ba8cde
fix: (backport) text truncate issue in the search modal (#2151)
bydawen Jun 16, 2025
c9896a8
[Teak] fix: published name in unit sidebar in container picker & Issu…
ChrisChV Jun 18, 2025
b6bd94c
feat: add `v2` `CourseAuthoringUnitSidebarSlot` (#2000)
tecoholic Jun 10, 2025
92c59cb
fix: advanced-settings api should not camel-case return value (backpo…
jignaciopm Jun 19, 2025
bdc99fd
fix: clear selection on files & uploads page after deleting (backport…
bra-i-am Jul 7, 2025
2973614
fix: loading unit page directly from link after logging in in Teak (#…
Anas12091101 Jul 9, 2025
4bc34c2
fix: pages and resources plugins not rendered (#1885)
jansenk Apr 30, 2025
7e0b7f9
docs: (backport) adding comprehensive readme documentation for plugin…
jacobo-dominguez-wgu Jul 29, 2025
06497bf
fix: publish btn doesn't show after component edit
Jun 27, 2025
088675f
feat: add logic for ai creation
filippovskii09 Nov 29, 2025
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
1 change: 1 addition & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ coverage:
threshold: 0%
ignore:
- "src/grading-settings/grading-scale/react-ranger.js"
- "src/generic/DraggableList/verticalSortableList.ts"
- "src/index.js"
193 changes: 98 additions & 95 deletions src/CourseAuthoringRoutes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import CourseChecklist from './course-checklist';
import GroupConfigurations from './group-configurations';
import { CourseLibraries } from './course-libraries';
import { IframeProvider } from './generic/hooks/context/iFrameContext';
import { AiAssistantProvider } from './assistant/context/AIAssistantProvider';

/**
* As of this writing, these routes are mounted at a path prefixed with the following:
Expand All @@ -48,101 +49,103 @@ const CourseAuthoringRoutes = () => {
const { courseId } = useParams();

return (
<CourseAuthoringPage courseId={courseId}>
<Routes>
<Route
path="/"
element={<PageWrap><CourseOutline courseId={courseId} /></PageWrap>}
/>
<Route
path="course_info"
element={<PageWrap><CourseUpdates courseId={courseId} /></PageWrap>}
/>
<Route
path="libraries"
element={<PageWrap><CourseLibraries courseId={courseId} /></PageWrap>}
/>
<Route
path="assets"
element={<PageWrap><FilesPage courseId={courseId} /></PageWrap>}
/>
<Route
path="videos"
element={getConfig().ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN === 'true' ? <PageWrap><VideosPage courseId={courseId} /></PageWrap> : null}
/>
<Route
path="pages-and-resources/*"
element={<PageWrap><PagesAndResources courseId={courseId} /></PageWrap>}
/>
<Route
path="proctored-exam-settings"
element={<Navigate replace to={`/course/${courseId}/pages-and-resources`} />}
/>
<Route
path="custom-pages/*"
element={<PageWrap><CustomPages courseId={courseId} /></PageWrap>}
/>
{DECODED_ROUTES.COURSE_UNIT.map((path) => (
<Route
key={path}
path={path}
element={<PageWrap><IframeProvider><CourseUnit courseId={courseId} /></IframeProvider></PageWrap>}
/>
))}
<Route
path="editor/course-videos/:blockId"
element={<PageWrap><VideoSelectorContainer courseId={courseId} /></PageWrap>}
/>
<Route
path="editor/:blockType/:blockId?"
element={<PageWrap><EditorContainer learningContextId={courseId} /></PageWrap>}
/>
<Route
path="settings/details"
element={<PageWrap><ScheduleAndDetails courseId={courseId} /></PageWrap>}
/>
<Route
path="settings/grading"
element={<PageWrap><GradingSettings courseId={courseId} /></PageWrap>}
/>
<Route
path="course_team"
element={<PageWrap><CourseTeam courseId={courseId} /></PageWrap>}
/>
<Route
path="group_configurations"
element={<PageWrap><GroupConfigurations courseId={courseId} /></PageWrap>}
/>
<Route
path="settings/advanced"
element={<PageWrap><AdvancedSettings courseId={courseId} /></PageWrap>}
/>
<Route
path="import"
element={<PageWrap><CourseImportPage courseId={courseId} /></PageWrap>}
/>
<Route
path="export"
element={<PageWrap><CourseExportPage courseId={courseId} /></PageWrap>}
/>
<Route
path="optimizer"
element={<PageWrap><CourseOptimizerPage courseId={courseId} /></PageWrap>}
/>
<Route
path="checklists"
element={<PageWrap><CourseChecklist courseId={courseId} /></PageWrap>}
/>
<Route
path="certificates"
element={getConfig().ENABLE_CERTIFICATE_PAGE === 'true' ? <PageWrap><Certificates courseId={courseId} /></PageWrap> : null}
/>
<Route
path="textbooks"
element={<PageWrap><Textbooks courseId={courseId} /></PageWrap>}
/>
</Routes>
</CourseAuthoringPage>
<AiAssistantProvider>
<CourseAuthoringPage courseId={courseId}>
<Routes>
<Route
path="/"
element={<PageWrap><CourseOutline courseId={courseId} /></PageWrap>}
/>
<Route
path="course_info"
element={<PageWrap><CourseUpdates courseId={courseId} /></PageWrap>}
/>
<Route
path="libraries"
element={<PageWrap><CourseLibraries courseId={courseId} /></PageWrap>}
/>
<Route
path="assets"
element={<PageWrap><FilesPage courseId={courseId} /></PageWrap>}
/>
<Route
path="videos"
element={getConfig().ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN === 'true' ? <PageWrap><VideosPage courseId={courseId} /></PageWrap> : null}
/>
<Route
path="pages-and-resources/*"
element={<PageWrap><PagesAndResources courseId={courseId} /></PageWrap>}
/>
<Route
path="proctored-exam-settings"
element={<Navigate replace to={`/course/${courseId}/pages-and-resources`} />}
/>
<Route
path="custom-pages/*"
element={<PageWrap><CustomPages courseId={courseId} /></PageWrap>}
/>
{DECODED_ROUTES.COURSE_UNIT.map((path) => (
<Route
key={path}
path={path}
element={<PageWrap><IframeProvider><CourseUnit courseId={courseId} /></IframeProvider></PageWrap>}
/>
))}
<Route
path="editor/course-videos/:blockId"
element={<PageWrap><VideoSelectorContainer courseId={courseId} /></PageWrap>}
/>
<Route
path="editor/:blockType/:blockId?"
element={<PageWrap><EditorContainer learningContextId={courseId} /></PageWrap>}
/>
<Route
path="settings/details"
element={<PageWrap><ScheduleAndDetails courseId={courseId} /></PageWrap>}
/>
<Route
path="settings/grading"
element={<PageWrap><GradingSettings courseId={courseId} /></PageWrap>}
/>
<Route
path="course_team"
element={<PageWrap><CourseTeam courseId={courseId} /></PageWrap>}
/>
<Route
path="group_configurations"
element={<PageWrap><GroupConfigurations courseId={courseId} /></PageWrap>}
/>
<Route
path="settings/advanced"
element={<PageWrap><AdvancedSettings courseId={courseId} /></PageWrap>}
/>
<Route
path="import"
element={<PageWrap><CourseImportPage courseId={courseId} /></PageWrap>}
/>
<Route
path="export"
element={<PageWrap><CourseExportPage courseId={courseId} /></PageWrap>}
/>
<Route
path="optimizer"
element={<PageWrap><CourseOptimizerPage courseId={courseId} /></PageWrap>}
/>
<Route
path="checklists"
element={<PageWrap><CourseChecklist courseId={courseId} /></PageWrap>}
/>
<Route
path="certificates"
element={getConfig().ENABLE_CERTIFICATE_PAGE === 'true' ? <PageWrap><Certificates courseId={courseId} /></PageWrap> : null}
/>
<Route
path="textbooks"
element={<PageWrap><Textbooks courseId={courseId} /></PageWrap>}
/>
</Routes>
</CourseAuthoringPage>
</AiAssistantProvider>
);
};

Expand Down
49 changes: 45 additions & 4 deletions src/advanced-settings/data/api.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { camelCaseObject, getConfig } from '@edx/frontend-platform';
/* eslint-disable import/prefer-default-export */
import {
camelCaseObject,
getConfig,
} from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { camelCase } from 'lodash';
import { convertObjectToSnakeCase } from '../../utils';

const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL;
Expand All @@ -14,7 +19,19 @@ const getProctoringErrorsApiUrl = () => `${getApiBaseUrl()}/api/contentstore/v1/
export async function getCourseAdvancedSettings(courseId) {
const { data } = await getAuthenticatedHttpClient()
.get(`${getCourseAdvancedSettingsApiUrl(courseId)}?fetch_all=0`);
return camelCaseObject(data);
const keepValues = {};
Object.keys(data).forEach((key) => {
keepValues[camelCase(key)] = { value: data[key].value };
});
const formattedData = {};
const formattedCamelCaseData = camelCaseObject(data);
Object.keys(formattedCamelCaseData).forEach((key) => {
formattedData[key] = {
...formattedCamelCaseData[key],
value: keepValues[key]?.value,
};
});
return formattedData;
}

/**
Expand All @@ -26,7 +43,19 @@ export async function getCourseAdvancedSettings(courseId) {
export async function updateCourseAdvancedSettings(courseId, settings) {
const { data } = await getAuthenticatedHttpClient()
.patch(`${getCourseAdvancedSettingsApiUrl(courseId)}`, convertObjectToSnakeCase(settings));
return camelCaseObject(data);
const keepValues = {};
Object.keys(data).forEach((key) => {
keepValues[camelCase(key)] = { value: data[key].value };
});
const formattedData = {};
const formattedCamelCaseData = camelCaseObject(data);
Object.keys(formattedCamelCaseData).forEach((key) => {
formattedData[key] = {
...formattedCamelCaseData[key],
value: keepValues[key]?.value,
};
});
return formattedData;
}

/**
Expand All @@ -36,5 +65,17 @@ export async function updateCourseAdvancedSettings(courseId, settings) {
*/
export async function getProctoringExamErrors(courseId) {
const { data } = await getAuthenticatedHttpClient().get(`${getProctoringErrorsApiUrl()}${courseId}`);
return camelCaseObject(data);
const keepValues = {};
Object.keys(data).forEach((key) => {
keepValues[camelCase(key)] = { value: data[key].value };
});
const formattedData = {};
const formattedCamelCaseData = camelCaseObject(data);
Object.keys(formattedCamelCaseData).forEach((key) => {
formattedData[key] = {
...formattedCamelCaseData[key],
value: keepValues[key]?.value,
};
});
return formattedData;
}
Loading