Skip to content

Commit 54cfbeb

Browse files
authored
feat: import course in library stepper [FC-0112] (#2567)
- Implemented the course import stepper described in #2524 - Adds the new `ENABLE_COURSE_IMPORT_IN_LIBRARY` flag
1 parent 7cf01de commit 54cfbeb

File tree

32 files changed

+1058
-284
lines changed

32 files changed

+1058
-284
lines changed

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ ENABLE_ASSETS_PAGE=false
3636
ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN=false
3737
ENABLE_TAGGING_TAXONOMY_PAGES=true
3838
ENABLE_CERTIFICATE_PAGE=true
39+
ENABLE_COURSE_IMPORT_IN_LIBRARY=false
3940
BBB_LEARN_MORE_URL=''
4041
HOTJAR_APP_ID=''
4142
HOTJAR_VERSION=6

.env.development

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ ENABLE_UNIT_PAGE=false
3737
ENABLE_ASSETS_PAGE=false
3838
ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN=true
3939
ENABLE_CERTIFICATE_PAGE=true
40+
ENABLE_COURSE_IMPORT_IN_LIBRARY=true
4041
ENABLE_NEW_VIDEO_UPLOAD_PAGE=true
4142
ENABLE_TAGGING_TAXONOMY_PAGES=true
4243
BBB_LEARN_MORE_URL=''

.env.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ ENABLE_UNIT_PAGE=true
3333
ENABLE_ASSETS_PAGE=false
3434
ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN=true
3535
ENABLE_CERTIFICATE_PAGE=true
36+
ENABLE_COURSE_IMPORT_IN_LIBRARY=true
3637
ENABLE_TAGGING_TAXONOMY_PAGES=true
3738
BBB_LEARN_MORE_URL=''
3839
INVITE_STUDENTS_EMAIL_TO="[email protected]"

src/course-outline/data/api.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import { camelCaseObject, getConfig } from '@edx/frontend-platform';
22
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
33
import { XBlock } from '@src/data/types';
4-
import { CourseOutline } from './types';
4+
import { CourseOutline, CourseDetails } from './types';
55

66
const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL;
77

88
export const getCourseOutlineIndexApiUrl = (
99
courseId: string,
1010
) => `${getApiBaseUrl()}/api/contentstore/v1/course_index/${courseId}`;
1111

12+
export const getCourseDetailsApiUrl = (courseId) => `${getApiBaseUrl()}/api/contentstore/v1/course_details/${courseId}`;
13+
1214
export const getCourseBestPracticesApiUrl = ({
1315
courseId,
1416
excludeGraded,
@@ -46,7 +48,7 @@ export const createDiscussionsTopicsUrl = (courseId: string) => `${getApiBaseUrl
4648
/**
4749
* Get course outline index.
4850
* @param {string} courseId
49-
* @returns {Promise<courseOutline>}
51+
* @returns {Promise<CourseOutline>}
5052
*/
5153
export async function getCourseOutlineIndex(courseId: string): Promise<CourseOutline> {
5254
const { data } = await getAuthenticatedHttpClient()
@@ -55,6 +57,18 @@ export async function getCourseOutlineIndex(courseId: string): Promise<CourseOut
5557
return camelCaseObject(data);
5658
}
5759

60+
/**
61+
* Get course details.
62+
* @param {string} courseId
63+
* @returns {Promise<CourseDetails>}
64+
*/
65+
export async function getCourseDetails(courseId: string): Promise<CourseDetails> {
66+
const { data } = await getAuthenticatedHttpClient()
67+
.get(getCourseDetailsApiUrl(courseId));
68+
69+
return camelCaseObject(data);
70+
}
71+
5872
/**
5973
*
6074
* @param courseId

src/course-outline/data/apiHooks.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { useMutation, useQuery } from '@tanstack/react-query';
1+
import { skipToken, useMutation, useQuery } from '@tanstack/react-query';
22
import { createCourseXblock } from '@src/course-unit/data/api';
3-
import { getCourseItem } from './api';
3+
import { getCourseDetails, getCourseItem } from './api';
44

55
export const courseOutlineQueryKeys = {
66
all: ['courseOutline'],
@@ -9,7 +9,7 @@ export const courseOutlineQueryKeys = {
99
*/
1010
contentLibrary: (courseId?: string) => [...courseOutlineQueryKeys.all, courseId],
1111
courseItemId: (itemId?: string) => [...courseOutlineQueryKeys.all, itemId],
12-
12+
courseDetails: (courseId?: string) => [...courseOutlineQueryKeys.all, courseId, 'details'],
1313
};
1414

1515
/**
@@ -33,3 +33,10 @@ export const useCourseItemData = (itemId?: string, enabled: boolean = true) => (
3333
enabled: enabled && itemId !== undefined,
3434
})
3535
);
36+
37+
export const useCourseDetails = (courseId?: string) => (
38+
useQuery({
39+
queryKey: courseOutlineQueryKeys.courseDetails(courseId),
40+
queryFn: courseId ? () => getCourseDetails(courseId) : skipToken,
41+
})
42+
);

src/course-outline/data/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ export interface CourseOutline {
2424
rerunNotificationId: null;
2525
}
2626

27+
// TODO: This interface has only basic data, all the rest needs to be added.
28+
export interface CourseDetails {
29+
courseId: string;
30+
title: string;
31+
subtitle?: string;
32+
org: string;
33+
description?: string;
34+
}
35+
2736
export interface CourseOutlineState {
2837
loadingStatus: {
2938
outlineIndexLoadingStatus: string;

src/index.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ initialize({
173173
ENABLE_ASSETS_PAGE: process.env.ENABLE_ASSETS_PAGE || 'false',
174174
ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN: process.env.ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN || 'false',
175175
ENABLE_CERTIFICATE_PAGE: process.env.ENABLE_CERTIFICATE_PAGE || 'false',
176+
ENABLE_COURSE_IMPORT_IN_LIBRARY: process.env.ENABLE_COURSE_IMPORT_IN_LIBRARY || 'false',
176177
ENABLE_TAGGING_TAXONOMY_PAGES: process.env.ENABLE_TAGGING_TAXONOMY_PAGES || 'false',
177178
ENABLE_CHECKLIST_QUALITY: process.env.ENABLE_CHECKLIST_QUALITY || 'true',
178179
ENABLE_GRADING_METHOD_IN_PROBLEMS: process.env.ENABLE_GRADING_METHOD_IN_PROBLEMS === 'true',

src/legacy-libraries-migration/index.scss

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@
1313

1414
.card-item {
1515
margin: 0 0 16px !important;
16-
17-
&.selected {
18-
box-shadow: 0 0 0 2px var(--pgn-color-primary-700);
19-
}
2016
}
2117
}
2218

src/library-authoring/LibraryLayout.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { ROUTES } from './routes';
2020
import { LibrarySectionPage, LibrarySubsectionPage } from './section-subsections';
2121
import { LibraryUnitPage } from './units';
2222
import { LibraryTeamModal } from './library-team';
23+
import { ImportStepperPage } from './import-course/stepper/ImportStepperPage';
2324

2425
const LibraryLayoutWrapper: React.FC<React.PropsWithChildren> = ({ children }) => {
2526
const {
@@ -97,6 +98,10 @@ const LibraryLayout = () => (
9798
path={ROUTES.IMPORT}
9899
Component={CourseImportHomePage}
99100
/>
101+
<Route
102+
path={ROUTES.IMPORT_COURSE}
103+
Component={ImportStepperPage}
104+
/>
100105
</Route>
101106
</Routes>
102107
);

src/library-authoring/data/api.mocks.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,3 +1133,17 @@ mockGetCourseImports.applyMock = () => jest.spyOn(
11331133
api,
11341134
'getCourseImports',
11351135
).mockImplementation(mockGetCourseImports);
1136+
1137+
export const mockGetMigrationInfo = {
1138+
applyMock: () => jest.spyOn(api, 'getMigrationInfo').mockResolvedValue(
1139+
camelCaseObject({
1140+
'course-v1:HarvardX+123+2023': [{
1141+
sourceKey: 'course-v1:HarvardX+123+2023',
1142+
targetCollectionKey: 'ltc:org:coll-1',
1143+
targetCollectionTitle: 'Collection 1',
1144+
targetKey: mockContentLibrary.libraryId,
1145+
targetTitle: 'Library 1',
1146+
}],
1147+
}),
1148+
),
1149+
};

0 commit comments

Comments
 (0)