Skip to content

Commit 9a97f25

Browse files
committed
refactor: renaming migration > import
1 parent 868084d commit 9a97f25

8 files changed

Lines changed: 153 additions & 153 deletions

File tree

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

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,33 +1073,33 @@ mockGetEntityLinks.applyMock = () => jest.spyOn(
10731073
'getEntityLinks',
10741074
).mockImplementation(mockGetEntityLinks);
10751075

1076-
export async function mockGetCourseMigrations(libraryId: string): ReturnType<typeof api.getCourseMigrations> {
1076+
export async function mockGetCourseImports(libraryId: string): ReturnType<typeof api.getCourseImports> {
10771077
switch (libraryId) {
10781078
case mockContentLibrary.libraryId:
10791079
return [
1080-
mockGetCourseMigrations.succeedMigration,
1081-
mockGetCourseMigrations.succeedMigrationWithCollection,
1082-
mockGetCourseMigrations.failMigration,
1083-
mockGetCourseMigrations.inProgressMigration,
1080+
mockGetCourseImports.succeedImport,
1081+
mockGetCourseImports.succeedImportWithCollection,
1082+
mockGetCourseImports.failImport,
1083+
mockGetCourseImports.inProgressImport,
10841084
];
1085-
case mockGetCourseMigrations.emptyLibraryId:
1085+
case mockGetCourseImports.emptyLibraryId:
10861086
return [];
10871087
default:
1088-
throw new Error(`mockGetCourseMigrations doesn't know how to mock ${JSON.stringify(libraryId)}`);
1088+
throw new Error(`mockGetCourseImports doesn't know how to mock ${JSON.stringify(libraryId)}`);
10891089
}
10901090
}
1091-
mockGetCourseMigrations.libraryId = mockContentLibrary.libraryId;
1092-
mockGetCourseMigrations.emptyLibraryId = mockContentLibrary.libraryId2;
1093-
mockGetCourseMigrations.succeedMigration = {
1091+
mockGetCourseImports.libraryId = mockContentLibrary.libraryId;
1092+
mockGetCourseImports.emptyLibraryId = mockContentLibrary.libraryId2;
1093+
mockGetCourseImports.succeedImport = {
10941094
source: {
10951095
key: 'course-v1:edX+DemoX+2025_T1',
10961096
displayName: 'DemoX 2025 T1',
10971097
},
10981098
targetCollection: null,
10991099
state: 'Succeeded',
11001100
progress: 1,
1101-
} satisfies api.CourseMigration;
1102-
mockGetCourseMigrations.succeedMigrationWithCollection = {
1101+
} satisfies api.CourseImport;
1102+
mockGetCourseImports.succeedImportWithCollection = {
11031103
source: {
11041104
key: 'course-v1:edX+DemoX+2025_T2',
11051105
displayName: 'DemoX 2025 T2',
@@ -1110,26 +1110,26 @@ mockGetCourseMigrations.succeedMigrationWithCollection = {
11101110
},
11111111
state: 'Succeeded',
11121112
progress: 1,
1113-
} satisfies api.CourseMigration;
1114-
mockGetCourseMigrations.failMigration = {
1113+
} satisfies api.CourseImport;
1114+
mockGetCourseImports.failImport = {
11151115
source: {
11161116
key: 'course-v1:edX+DemoX+2025_T3',
11171117
displayName: 'DemoX 2025 T3',
11181118
},
11191119
targetCollection: null,
11201120
state: 'Failed',
11211121
progress: 0.30,
1122-
} satisfies api.CourseMigration;
1123-
mockGetCourseMigrations.inProgressMigration = {
1122+
} satisfies api.CourseImport;
1123+
mockGetCourseImports.inProgressImport = {
11241124
source: {
11251125
key: 'course-v1:edX+DemoX+2025_T4',
11261126
displayName: 'DemoX 2025 T4',
11271127
},
11281128
targetCollection: null,
11291129
state: 'InProgress',
11301130
progress: 0.5012,
1131-
} satisfies api.CourseMigration;
1132-
mockGetCourseMigrations.applyMock = () => jest.spyOn(
1131+
} satisfies api.CourseImport;
1132+
mockGetCourseImports.applyMock = () => jest.spyOn(
11331133
api,
1134-
'getCourseMigrations',
1135-
).mockImplementation(mockGetCourseMigrations);
1134+
'getCourseImports',
1135+
).mockImplementation(mockGetCourseImports);

src/library-authoring/data/api.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ export const getLibraryRestoreStatusApiUrl = (taskId: string) => `${getApiBaseUr
158158
*/
159159
export const getLibraryContainerCopyApiUrl = (containerId: string) => `${getLibraryContainerApiUrl(containerId)}copy/`;
160160
/**
161-
* Get the url for the API endpoint to list library course migrations.
161+
* Get the url for the API endpoint to list library course imports.
162162
*/
163-
export const getCourseMigrationsApiUrl = (libraryId: string) => `${getApiBaseUrl()}/api/modulestore_migrator/v1/library/${libraryId}/migrations/courses/`;
163+
export const getCourseImportsApiUrl = (libraryId: string) => `${getApiBaseUrl()}/api/modulestore_migrator/v1/library/${libraryId}/migrations/courses/`;
164164

165165
export interface ContentLibrary {
166166
id: string;
@@ -789,7 +789,7 @@ export async function publishContainer(containerId: string) {
789789
await getAuthenticatedHttpClient().post(getLibraryContainerPublishApiUrl(containerId));
790790
}
791791

792-
export interface CourseMigration {
792+
export interface CourseImport {
793793
source: {
794794
key: string;
795795
displayName: string;
@@ -803,9 +803,9 @@ export interface CourseMigration {
803803
}
804804

805805
/**
806-
* Returns the course migrations which had this library as destination.
806+
* Returns the course imports which had this library as destination.
807807
*/
808-
export async function getCourseMigrations(libraryId: string): Promise<CourseMigration[]> {
809-
const { data } = await getAuthenticatedHttpClient().get(getCourseMigrationsApiUrl(libraryId));
808+
export async function getCourseImports(libraryId: string): Promise<CourseImport[]> {
809+
const { data } = await getAuthenticatedHttpClient().get(getCourseImportsApiUrl(libraryId));
810810
return camelCaseObject(data);
811811
}

src/library-authoring/data/apiHooks.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ export const libraryAuthoringQueryKeys = {
8989
}
9090
return ['hierarchy'];
9191
},
92-
migrations: (libraryId: string) => [
92+
courseImports: (libraryId: string) => [
9393
...libraryAuthoringQueryKeys.contentLibrary(libraryId),
94-
'migrations',
94+
'courseImports',
9595
],
9696
};
9797

@@ -957,11 +957,11 @@ export const useContentFromSearchIndex = (contentIds: string[]) => {
957957
};
958958

959959
/**
960-
* Returns the course migrations which had this library as destination.
960+
* Returns the course imports which had this library as destination.
961961
*/
962-
export const useCourseMigrations = (libraryId: string) => (
962+
export const useCourseImports = (libraryId: string) => (
963963
useQuery({
964-
queryKey: libraryAuthoringQueryKeys.migrations(libraryId),
965-
queryFn: () => api.getCourseMigrations(libraryId),
964+
queryKey: libraryAuthoringQueryKeys.courseImports(libraryId),
965+
queryFn: () => api.getCourseImports(libraryId),
966966
})
967967
);

src/library-authoring/import-course/CourseImportHomePage.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import {
77
import { LibraryProvider } from '../common/context/LibraryContext';
88
import {
99
mockContentLibrary,
10-
mockGetCourseMigrations,
10+
mockGetCourseImports,
1111
} from '../data/api.mocks';
1212
import { CourseImportHomePage } from './CourseImportHomePage';
1313

1414
initializeMocks();
1515
mockContentLibrary.applyMock();
16-
mockGetCourseMigrations.applyMock();
16+
mockGetCourseImports.applyMock();
1717

1818
const mockNavigate = jest.fn();
1919
jest.mock('react-router-dom', () => ({
@@ -38,14 +38,14 @@ const render = (libraryId: string) => (
3838

3939
describe('<CourseImportHomePage>', () => {
4040
it('should render the library course import home page', async () => {
41-
render(mockGetCourseMigrations.libraryId);
41+
render(mockGetCourseImports.libraryId);
4242
expect(await screen.findByRole('heading', { name: /Tools.*Import/ })).toBeInTheDocument(); // Header
4343
expect(screen.getByRole('heading', { name: 'Previous Imports' })).toBeInTheDocument();
4444
expect(screen.queryAllByRole('link', { name: /DemoX 2025 T[0-5]/ })).toHaveLength(4);
4545
});
4646

4747
it('should render the empty state', async () => {
48-
render(mockGetCourseMigrations.emptyLibraryId);
48+
render(mockGetCourseImports.emptyLibraryId);
4949
expect(await screen.findByRole('heading', { name: /Tools.*Import/ })).toBeInTheDocument(); // Header
5050
expect(screen.queryByRole('heading', { name: 'Previous Imports' })).not.toBeInTheDocument();
5151
expect(screen.queryByText('You have not imported any courses into this library.')).toBeInTheDocument();

src/library-authoring/import-course/CourseImportHomePage.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ import SubHeader from '@src/generic/sub-header/SubHeader';
1414
import Header from '@src/header';
1515

1616
import { useLibraryContext } from '../common/context/LibraryContext';
17-
import { useCourseMigrations } from '../data/apiHooks';
17+
import { useCourseImports } from '../data/apiHooks';
1818
import { HelpSidebar } from './HelpSidebar';
19-
import { MigratedCourseCard } from './MigratedCourseCard';
19+
import { ImportedCourseCard } from './ImportedCourseCard';
2020
import messages from './messages';
2121

2222
const EmptyState = () => (
@@ -35,9 +35,9 @@ const EmptyState = () => (
3535
export const CourseImportHomePage = () => {
3636
const intl = useIntl();
3737
const { libraryId, libraryData } = useLibraryContext();
38-
const { data: courseMigrations } = useCourseMigrations(libraryId);
38+
const { data: courseImports } = useCourseImports(libraryId);
3939

40-
if (!courseMigrations || !libraryData) {
40+
if (!courseImports || !libraryData) {
4141
return <Loading />;
4242
}
4343

@@ -67,13 +67,13 @@ export const CourseImportHomePage = () => {
6767
</div>
6868
<Layout xs={[{ span: 9 }, { span: 3 }]}>
6969
<Layout.Element>
70-
{courseMigrations.length ? (
70+
{courseImports.length ? (
7171
<Stack gap={3} className="pl-4 mt-4">
7272
<h3>Previous Imports</h3>
73-
{courseMigrations.map((courseMigration) => (
74-
<MigratedCourseCard
75-
key={courseMigration.source.key}
76-
courseMigration={courseMigration}
73+
{courseImports.map((courseImport) => (
74+
<ImportedCourseCard
75+
key={courseImport.source.key}
76+
courseImport={courseImport}
7777
/>
7878
))}
7979
</Stack>
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import userEvent from '@testing-library/user-event';
2+
3+
import {
4+
initializeMocks,
5+
render as testRender,
6+
screen,
7+
waitFor,
8+
} from '@src/testUtils';
9+
10+
import { LibraryProvider } from '../common/context/LibraryContext';
11+
import {
12+
mockContentLibrary,
13+
mockGetCourseImports,
14+
} from '../data/api.mocks';
15+
import { type CourseImport } from '../data/api';
16+
import { ImportedCourseCard } from './ImportedCourseCard';
17+
18+
initializeMocks();
19+
mockContentLibrary.applyMock();
20+
const { libraryId } = mockContentLibrary;
21+
22+
const mockNavigate = jest.fn();
23+
jest.mock('react-router-dom', () => ({
24+
...jest.requireActual('react-router-dom'),
25+
useNavigate: () => mockNavigate,
26+
}));
27+
28+
const render = (courseImport: CourseImport) => (
29+
testRender(
30+
<ImportedCourseCard courseImport={courseImport} />,
31+
{
32+
extraWrapper: ({ children }: { children: React.ReactNode }) => (
33+
<LibraryProvider libraryId={mockContentLibrary.libraryId}>
34+
{children}
35+
</LibraryProvider>
36+
),
37+
path: '/libraries/:libraryId/import-course',
38+
params: { libraryId },
39+
},
40+
)
41+
);
42+
43+
describe('<ImportedCourseCard>', () => {
44+
it('should render a card for a successful import', () => {
45+
const { succeedImport } = mockGetCourseImports;
46+
render(succeedImport);
47+
expect(screen.getByText(succeedImport.source.displayName)).toBeInTheDocument();
48+
expect(screen.getByText(/100% Imported/)).toBeInTheDocument();
49+
50+
const courseLink = screen.getByRole('link', { name: succeedImport.source.displayName });
51+
expect(courseLink).toHaveAttribute('href', `/course/${succeedImport.source.key}`);
52+
});
53+
54+
it('should render a card for a successful import with a collection', async () => {
55+
const { succeedImportWithCollection } = mockGetCourseImports;
56+
render(succeedImportWithCollection);
57+
expect(screen.getByText(succeedImportWithCollection.source.displayName)).toBeInTheDocument();
58+
expect(screen.getByText(/100% Imported/)).toBeInTheDocument();
59+
60+
const courseLink = screen.getByRole('link', { name: succeedImportWithCollection.source.displayName });
61+
expect(courseLink).toHaveAttribute('href', `/course/${succeedImportWithCollection.source.key}`);
62+
63+
const collectionLink = await screen.findByText(succeedImportWithCollection.targetCollection.title);
64+
userEvent.click(collectionLink);
65+
await waitFor(() => {
66+
expect(mockNavigate).toHaveBeenCalledWith(
67+
{
68+
pathname: `/library/${libraryId}/collection/${succeedImportWithCollection.targetCollection.key}`,
69+
search: '',
70+
},
71+
);
72+
});
73+
});
74+
75+
it('should render a card for a failed import', () => {
76+
const { failImport } = mockGetCourseImports;
77+
render(failImport);
78+
expect(screen.getByText(failImport.source.displayName)).toBeInTheDocument();
79+
expect(screen.getByText('Import Failed')).toBeInTheDocument();
80+
81+
const courseLink = screen.getByRole('link', { name: failImport.source.displayName });
82+
expect(courseLink).toHaveAttribute('href', `/course/${failImport.source.key}`);
83+
});
84+
85+
it('should render a card for an in-progress import', () => {
86+
const { inProgressImport } = mockGetCourseImports;
87+
render(inProgressImport);
88+
expect(screen.getByText(inProgressImport.source.displayName)).toBeInTheDocument();
89+
expect(screen.getByText(/50% Imported/)).toBeInTheDocument();
90+
91+
const courseLink = screen.getByRole('link', { name: inProgressImport.source.displayName });
92+
expect(courseLink).toHaveAttribute('href', `/course/${inProgressImport.source.key}`);
93+
});
94+
});

src/library-authoring/import-course/MigratedCourseCard.tsx renamed to src/library-authoring/import-course/ImportedCourseCard.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import {
1010
import classNames from 'classnames';
1111
import { Link } from 'react-router-dom';
1212

13-
import { type CourseMigration } from '../data/api';
13+
import { type CourseImport } from '../data/api';
1414
import { useLibraryRoutes } from '../routes';
1515
import messages from './messages';
1616

17-
interface MigratedCourseCardProps {
18-
courseMigration: CourseMigration;
17+
interface ImportedCourseCardProps {
18+
courseImport: CourseImport;
1919
}
2020

2121
const BORDER_CLASS = {
@@ -39,41 +39,41 @@ const STATE_ICON_COLOR_CLASS = {
3939
InProgress: undefined,
4040
};
4141

42-
const StateIcon = ({ state }: { state: CourseMigration['state'] }) => (
42+
const StateIcon = ({ state }: { state: CourseImport['state'] }) => (
4343
<Icon
4444
src={STATE_ICON[state]}
4545
size="sm"
4646
className={classNames('mr-2', STATE_ICON_COLOR_CLASS[state])}
4747
/>
4848
);
4949

50-
export const MigratedCourseCard = ({ courseMigration }: MigratedCourseCardProps) => {
50+
export const ImportedCourseCard = ({ courseImport }: ImportedCourseCardProps) => {
5151
const { navigateTo } = useLibraryRoutes();
5252

5353
return (
54-
<Card className={BORDER_CLASS[courseMigration.state]}>
54+
<Card className={BORDER_CLASS[courseImport.state]}>
5555
<Card.Section>
56-
<Link to={`/course/${courseMigration.source.key}`}>
57-
<h4>{courseMigration.source.displayName}</h4>
56+
<Link to={`/course/${courseImport.source.key}`}>
57+
<h4>{courseImport.source.displayName}</h4>
5858
</Link>
5959
<div className="d-inline-flex small align-items-center">
60-
<StateIcon state={courseMigration.state} />
61-
{courseMigration.state === 'Failed' ? (
60+
<StateIcon state={courseImport.state} />
61+
{courseImport.state === 'Failed' ? (
6262
<FormattedMessage {...messages.courseImportTextFailed} />
6363
) : (
6464
<>
65-
{Math.round(courseMigration.progress * 100)}
65+
{Math.round(courseImport.progress * 100)}
6666
<FormattedMessage {...messages.courseImportTextProgress} />
6767
</>
6868
)}
69-
{courseMigration.targetCollection && (
69+
{courseImport.targetCollection && (
7070
<Button
7171
iconBefore={Folder}
7272
variant="link"
7373
className="ml-4"
74-
onClick={() => navigateTo({ collectionId: courseMigration.targetCollection!.key })}
74+
onClick={() => navigateTo({ collectionId: courseImport.targetCollection!.key })}
7575
>
76-
{courseMigration.targetCollection.title}
76+
{courseImport.targetCollection.title}
7777
</Button>
7878
)}
7979
</div>

0 commit comments

Comments
 (0)