Skip to content

Commit a9f343a

Browse files
committed
Merge branch 'master' into chris/FAL-4337-sidebar-menus
2 parents a2583bc + ca42550 commit a9f343a

94 files changed

Lines changed: 6385 additions & 647 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/validate.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
path: coverage
3434
merge-multiple: true
3535
- name: Upload coverage
36-
uses: codecov/codecov-action@v5
36+
uses: codecov/codecov-action@v6
3737
with:
3838
fail_ci_if_error: true
3939
token: ${{ secrets.CODECOV_TOKEN }}

package-lock.json

Lines changed: 224 additions & 176 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@
6666
"@openedx/paragon": "^23.5.0",
6767
"@redux-devtools/extension": "^3.3.0",
6868
"@reduxjs/toolkit": "2.11.2",
69-
"@tanstack/react-query": "5.90.21",
69+
"@tanstack/react-query": "5.95.2",
70+
"@tanstack/react-table": "^8.21.3",
7071
"@tinymce/tinymce-react": "^6.0.0",
7172
"classnames": "2.5.1",
7273
"codemirror": "^6.0.0",
@@ -119,7 +120,7 @@
119120
"jest-canvas-mock": "^2.5.2",
120121
"jest-expect-message": "^1.1.3",
121122
"oxlint": "^1.42.0",
122-
"oxlint-tsgolint": "^0.16.0",
123+
"oxlint-tsgolint": "^0.17.0",
123124
"react-test-renderer": "^18.3.1",
124125
"redux-mock-store": "^1.5.4"
125126
}

src/authz/data/api.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import {
55
PermissionValidationRequestItem,
66
PermissionValidationResponseItem,
77
} from '@src/authz/types';
8-
import { getApiUrl } from './utils';
8+
import { getConfig } from '@edx/frontend-platform';
9+
10+
export const getAuthzApiUrl = (path: string) => `${getConfig().STUDIO_BASE_URL}/api/authz/${path || ''}`;
911

1012
export const validateUserPermissions = async (
1113
query: PermissionValidationQuery,
@@ -14,7 +16,7 @@ export const validateUserPermissions = async (
1416
const request: PermissionValidationRequestItem[] = Object.values(query);
1517

1618
const { data }: { data: PermissionValidationResponseItem[] } = await getAuthenticatedHttpClient().post(
17-
getApiUrl('/api/authz/v1/permissions/validate/me'),
19+
getAuthzApiUrl('v1/permissions/validate/me'),
1820
request,
1921
);
2022

src/authz/data/utils.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,9 @@ export const BROKEN = 'broken';
116116
export const LOCKED = 'locked';
117117

118118
export const MANUAL = 'manual';
119+
120+
export enum AgreementGated {
121+
UPLOAD = 'upload',
122+
UPLOAD_VIDEOS = 'upload.videos',
123+
UPLOAD_FILES = 'upload.files',
124+
}

src/course-checklist/ChecklistSection/ChecklistItemBody.jsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,21 @@ import { ActionRow, Button, Icon } from '@openedx/paragon';
55
import { CheckCircle, RadioButtonUnchecked } from '@openedx/paragon/icons';
66
import { getConfig } from '@edx/frontend-platform';
77

8-
import { useWaffleFlags } from '../../data/apiHooks';
8+
import { useWaffleFlags } from '@src/data/apiHooks';
9+
910
import messages from './messages';
1011

1112
const getUpdateLinks = (courseId, waffleFlags) => {
1213
const baseUrl = getConfig().STUDIO_BASE_URL;
13-
const isLegacyGradingUrl = !waffleFlags.useNewGradingPage;
1414
const isLegacyCertificateUrl = !waffleFlags.useNewCertificatesPage;
15-
const isLegacyCourseDatesUrl = !waffleFlags.useNewScheduleDetailsPage;
1615
const isLegacyOutlineUrl = !waffleFlags.useNewCourseOutlinePage;
1716

1817
return {
1918
welcomeMessage: `/course/${courseId}/course_info`,
20-
gradingPolicy: isLegacyGradingUrl
21-
? `${baseUrl}/settings/grading/${courseId}` : `/course/${courseId}/settings/grading`,
19+
gradingPolicy: `/course/${courseId}/settings/grading`,
2220
certificate: isLegacyCertificateUrl
2321
? `${baseUrl}/certificates/${courseId}` : `/course/${courseId}/certificates`,
24-
courseDates: isLegacyCourseDatesUrl
25-
? `${baseUrl}/settings/details/${courseId}#schedule` : `/course/${courseId}/settings/details/#schedule`,
22+
courseDates: `/course/${courseId}/settings/details/#schedule`,
2623
proctoringEmail: `${baseUrl}/pages-and-resources/proctoring/settings`,
2724
outline: isLegacyOutlineUrl ? `${baseUrl}/course/${courseId}` : `/course/${courseId}`,
2825
};

src/course-checklist/ChecklistSection/ChecklistSection.test.jsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { camelCaseObject } from '@edx/frontend-platform';
22

33
import {
44
initializeMocks, render, screen, within,
5-
} from '../../testUtils';
6-
import { getApiWaffleFlagsUrl } from '../../data/api';
5+
} from '@src/testUtils';
6+
import { getApiWaffleFlagsUrl } from '@src/data/api';
7+
78
import { generateCourseLaunchData } from '../factories/mockApiResponses';
89
import { checklistItems } from './utils/courseChecklistData';
910
import messages from './messages';
@@ -36,9 +37,7 @@ describe('ChecklistSection', () => {
3637
axiosMock
3738
.onGet(getApiWaffleFlagsUrl(courseId))
3839
.reply(200, {
39-
useNewGradingPage: true,
4040
useNewCertificatesPage: true,
41-
useNewScheduleDetailsPage: true,
4241
useNewCourseOutlinePage: true,
4342
});
4443
});

src/course-outline/CourseOutline.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,11 @@ const CourseOutline = () => {
436436
isOpen={isConfigureModalOpen}
437437
onClose={handleConfigureModalClose}
438438
onConfigureSubmit={handleConfigureItemSubmit}
439+
/**
440+
* Only sections need overflow visible (for the Release date datepicker, fixed in #2901);
441+
* enabling it for subsection/unit modals causes the Visibility tab background to clip.
442+
*/
443+
isOverflowVisible={itemCategory === COURSE_BLOCK_NAMES.chapter.id}
439444
currentItemData={currentItemData}
440445
enableProctoredExams={enableProctoredExams}
441446
enableTimedExams={enableTimedExams}

src/course-outline/outline-sidebar/info-sidebar/CourseInfoSidebar.tsx

Lines changed: 131 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,36 @@
1+
import { getConfig } from '@edx/frontend-platform';
12
import { useIntl } from '@edx/frontend-platform/i18n';
2-
import { useToggle } from '@openedx/paragon';
3+
import {
4+
Tab,
5+
Tabs,
6+
useToggle,
7+
} from '@openedx/paragon';
38
import { SchoolOutline, Tag } from '@openedx/paragon/icons';
49

10+
import { useUserPermissions } from '@src/authz/data/apiHooks';
11+
import { COURSE_PERMISSIONS } from '@src/authz/constants';
512
import { ContentTagsDrawerSheet, ContentTagsSnippet } from '@src/content-tags-drawer';
13+
import { useCourseSettings, useWaffleFlags } from '@src/data/apiHooks';
614
import { ComponentCountSnippet } from '@src/generic/block-type-utils';
15+
import { HelpSidebarLink, otherLinkURLParams, messages as helpSidebarMessages } from '@src/generic/help-sidebar';
16+
import { SidebarContent, SidebarSection, SidebarTitle } from '@src/generic/sidebar';
717
import { useGetBlockTypes } from '@src/search-manager';
818
import { useCourseAuthoringContext } from '@src/CourseAuthoringContext';
919

10-
import { SidebarContent, SidebarSection, SidebarTitle } from '@src/generic/sidebar';
11-
1220
import { useCourseDetails } from '@src/course-outline/data/apiHooks';
1321
import messages from '../messages';
1422

15-
export const CourseInfoSidebar = () => {
23+
const DetailsTab = () => {
1624
const intl = useIntl();
17-
const { courseId } = useCourseAuthoringContext();
18-
const { data: courseDetails } = useCourseDetails(courseId);
1925

26+
const { courseId } = useCourseAuthoringContext();
2027
const { data: componentData } = useGetBlockTypes(
2128
[`context_key = "${courseId}"`],
2229
);
23-
2430
const [isManageTagsDrawerOpen, openManageTagsDrawer, closeManageTagsDrawer] = useToggle(false);
2531

2632
return (
27-
<div>
28-
<SidebarTitle
29-
title={courseDetails?.title || ''}
30-
icon={SchoolOutline}
31-
/>
33+
<>
3234
<SidebarContent>
3335
<SidebarSection
3436
title={intl.formatMessage(messages.sidebarSectionSummary)}
@@ -54,6 +56,122 @@ export const CourseInfoSidebar = () => {
5456
onClose={closeManageTagsDrawer}
5557
showSheet={isManageTagsDrawerOpen}
5658
/>
57-
</div>
59+
</>
60+
);
61+
};
62+
63+
const SettingsTab = () => {
64+
const intl = useIntl();
65+
const { courseId } = useCourseAuthoringContext();
66+
const { data: courseSettingsData } = useCourseSettings(courseId);
67+
68+
const {
69+
grading,
70+
courseTeam,
71+
advancedSettings,
72+
scheduleAndDetails,
73+
groupConfigurations,
74+
} = otherLinkURLParams;
75+
const waffleFlags = useWaffleFlags(courseId);
76+
77+
const proctoredExamSettingsUrl = courseSettingsData?.mfeProctoredExamSettingsUrl;
78+
79+
/*
80+
AuthZ for Course Authoring
81+
If authz.enable_course_authoring flag is enabled, validate permissions using AuthZ API.
82+
*/
83+
const isAuthzEnabled = waffleFlags.enableAuthzCourseAuthoring;
84+
const { isLoading: isLoadingUserPermissions, data: userPermissions } = useUserPermissions({
85+
canManageAdvancedSettings: {
86+
action: COURSE_PERMISSIONS.MANAGE_ADVANCED_SETTINGS,
87+
scope: courseId,
88+
},
89+
}, isAuthzEnabled);
90+
91+
// If it's still loading, don't show the Advanced Settings link, otherwise, use the permission to decide
92+
const authzCanManageAdvancedSettings = isLoadingUserPermissions
93+
? false
94+
: !!userPermissions?.canManageAdvancedSettings;
95+
96+
// When authz is enabled, use permission, otherwise it's always allowed (legacy behavior)
97+
const canManageAdvancedSettings = isAuthzEnabled ? authzCanManageAdvancedSettings : true;
98+
99+
return (
100+
<SidebarSection
101+
title={intl.formatMessage(messages.settingsTabText)}
102+
>
103+
<HelpSidebarLink
104+
as="span"
105+
pathToPage={`/course/${courseId}/${scheduleAndDetails}`}
106+
title={intl.formatMessage(
107+
helpSidebarMessages.sidebarLinkToScheduleAndDetails,
108+
)}
109+
isNewPage
110+
/>
111+
<HelpSidebarLink
112+
as="span"
113+
pathToPage={`/course/${courseId}/${grading}`}
114+
title={intl.formatMessage(helpSidebarMessages.sidebarLinkToGrading)}
115+
isNewPage
116+
/>
117+
<HelpSidebarLink
118+
as="span"
119+
pathToPage={`/course/${courseId}/${courseTeam}`}
120+
title={intl.formatMessage(helpSidebarMessages.sidebarLinkToCourseTeam)}
121+
isNewPage
122+
/>
123+
<HelpSidebarLink
124+
as="span"
125+
pathToPage={`/course/${courseId}/${groupConfigurations}`}
126+
title={intl.formatMessage(helpSidebarMessages.sidebarLinkToGroupConfigurations)}
127+
isNewPage
128+
/>
129+
{canManageAdvancedSettings && (
130+
<HelpSidebarLink
131+
as="span"
132+
pathToPage={`/course/${courseId}/${advancedSettings}`}
133+
title={intl.formatMessage(helpSidebarMessages.sidebarLinkToAdvancedSettings)}
134+
isNewPage
135+
/>
136+
)}
137+
{proctoredExamSettingsUrl && (
138+
<HelpSidebarLink
139+
as="span"
140+
pathToPage={proctoredExamSettingsUrl}
141+
title={intl.formatMessage(
142+
helpSidebarMessages.sidebarLinkToProctoredExamSettings,
143+
)}
144+
isNewPage
145+
/>
146+
)}
147+
</SidebarSection>
148+
);
149+
};
150+
151+
export const CourseInfoSidebar = () => {
152+
const intl = useIntl();
153+
const { courseId } = useCourseAuthoringContext();
154+
const { data: courseDetails } = useCourseDetails(courseId);
155+
156+
return (
157+
<>
158+
<SidebarTitle
159+
title={courseDetails?.title || ''}
160+
icon={SchoolOutline}
161+
/>
162+
<Tabs
163+
variant="tabs"
164+
className="my-2 mx-n3.5"
165+
id="course-info-tabs"
166+
mountOnEnter
167+
>
168+
<Tab eventKey="info" title={intl.formatMessage(messages.infoTabText)}>
169+
<DetailsTab />
170+
</Tab>
171+
<Tab eventKey="settings" title={intl.formatMessage(messages.settingsTabText)}>
172+
<SettingsTab />
173+
</Tab>
174+
</Tabs>
175+
</>
58176
);
59177
};

0 commit comments

Comments
 (0)