From 38dfb68286aa13eb50dbcf45604e86813396c301 Mon Sep 17 00:00:00 2001
From: Navin Karkera
Date: Wed, 31 Dec 2025 21:06:44 +0530
Subject: [PATCH] refactor: course import analysis and details page in
libraries (#2774)
* Updates analysis details body text
* Updates partial banner text
* Rounds percentage of supported blocks
* Removes unsupported children blocks from total counts and percentages.
* Updates spacing in analysis page.
---
.../import-course/ImportDetailsPage.test.tsx | 9 ++---
.../import-course/ImportDetailsPage.tsx | 6 ----
.../import-course/messages.ts | 4 +--
.../stepper/ReviewImportDetails.test.tsx | 12 +++----
.../stepper/ReviewImportDetails.tsx | 35 ++++++++++---------
5 files changed, 32 insertions(+), 34 deletions(-)
diff --git a/src/library-authoring/import-course/ImportDetailsPage.test.tsx b/src/library-authoring/import-course/ImportDetailsPage.test.tsx
index 2795cf09b..757d71a7a 100644
--- a/src/library-authoring/import-course/ImportDetailsPage.test.tsx
+++ b/src/library-authoring/import-course/ImportDetailsPage.test.tsx
@@ -109,6 +109,7 @@ describe('', () => {
});
it('should render Partial Succeeded state', async () => {
+ const user = userEvent.setup();
mockGetModulestoreMigratedBlocksInfo.applyMockPartial();
(useGetContentHits as jest.Mock).mockReturnValue({
isPending: false,
@@ -143,12 +144,12 @@ describe('', () => {
expect(await screen.findByText(/partial import successful/i)).toBeInTheDocument();
expect(await screen.findByText(/Total Blocks/i)).toBeInTheDocument();
- expect(await screen.findByText('2/5')).toBeInTheDocument();
+ expect(await screen.findByText('2/3')).toBeInTheDocument();
expect(await screen.findByText(/Components/i)).toBeInTheDocument();
- expect(await screen.findByText('1/4')).toBeInTheDocument();
+ expect(await screen.findByText('1/2')).toBeInTheDocument();
expect(await screen.findByText(
- /40% of course test course has been imported successfully/i,
+ /66% of course test course has been imported successfully/i,
)).toBeInTheDocument();
expect(await screen.findByRole('cell', {
@@ -165,7 +166,7 @@ describe('', () => {
name: /view imported content/i,
});
- await viewImportedContentBtn.click();
+ await user.click(viewImportedContentBtn);
await waitFor(() => expect(mockNavigate).toHaveBeenCalledWith('/library/lib:Axim:TEST/collection/coll'));
});
});
diff --git a/src/library-authoring/import-course/ImportDetailsPage.tsx b/src/library-authoring/import-course/ImportDetailsPage.tsx
index 276e6fc6a..770b56862 100644
--- a/src/library-authoring/import-course/ImportDetailsPage.tsx
+++ b/src/library-authoring/import-course/ImportDetailsPage.tsx
@@ -100,12 +100,6 @@ const ImportDetailsContent = () => {
// The migrations of this block is failed
counts.unsupported += 1;
resultUnsupportedIds.push(block.sourceKey);
-
- if (block.unsupportedReason) {
- // Verify if the unsupported block has children
- const match = block.unsupportedReason.match(/It has (\d+) children/);
- counts.unsupported += match ? Number(match[1]) : 0;
- }
} else {
counts.totalBlocks += 1;
const blockType = getBlockType(block.sourceKey);
diff --git a/src/library-authoring/import-course/messages.ts b/src/library-authoring/import-course/messages.ts
index 9462f514e..5f4d51a4c 100644
--- a/src/library-authoring/import-course/messages.ts
+++ b/src/library-authoring/import-course/messages.ts
@@ -181,12 +181,12 @@ const messages = defineMessages({
},
importCourseAnalysisCompleteSomeContentBody: {
id: 'library-authoring.import-course.review-details.analysis-complete.100.body',
- defaultMessage: '{unsupportedBlockPercentage}% of content cannot be imported. For details see below.',
+ defaultMessage: '{supportedBlockPercentage}% of course content will be imported into a collection in your library called {courseName}. Some content will not be imported. For details see below.',
description: 'Body of the info card when course import analysis is complete and some data can be imported.',
},
importCourseAnalysisDetailsUnsupportedBlocksBody: {
id: 'library-authoring.import-course.review-details.analysis-details.unsupportedBlocks.body',
- defaultMessage: 'The following block types cannot be imported into your library because they\'re are not yet supported. These block types will be replaced with a placeholder block in the library. For more information, reference the Help & Support sidebar.',
+ defaultMessage: 'Some block types cannot be imported into your library because they’re not yet supported. These blocks will be replaced with a placeholder block in the library. For more information, reference the Help & Support sidebar.',
description: 'Body of analysis details when some unsupported blocks are present',
},
importCourseComponentsUnsupportedInfo: {
diff --git a/src/library-authoring/import-course/stepper/ReviewImportDetails.test.tsx b/src/library-authoring/import-course/stepper/ReviewImportDetails.test.tsx
index b84af7b45..6739444cf 100644
--- a/src/library-authoring/import-course/stepper/ReviewImportDetails.test.tsx
+++ b/src/library-authoring/import-course/stepper/ReviewImportDetails.test.tsx
@@ -120,7 +120,7 @@ describe('ReviewImportDetails', () => {
expect(await screen.findByRole('alert')).toBeInTheDocument();
expect(await screen.findByText(/Import Analysis Complete/i)).toBeInTheDocument();
expect(await screen.findByText(
- /12.50% of content cannot be imported. For details see below./i,
+ /88% of course content will be imported into a collection in your library called Test Course. Some content will not be imported. For details see below./i,
)).toBeInTheDocument();
expect(await screen.findByText(/Total Blocks/i)).toBeInTheDocument();
expect(await screen.findByText('7/8')).toBeInTheDocument();
@@ -135,7 +135,7 @@ describe('ReviewImportDetails', () => {
expect(markAnalysisComplete).toHaveBeenCalledWith(true);
});
- it('considers children blocks of unsupportedBlocks', async () => {
+ it('skips children blocks from total counts', async () => {
(useCourseDetails as jest.Mock).mockReturnValue({ isPending: false, data: { title: 'Test Course' } });
(useMigrationInfo as jest.Mock).mockReturnValue({
isPending: false,
@@ -161,7 +161,7 @@ describe('ReviewImportDetails', () => {
}).mockReturnValueOnce({
isPending: false,
data: {
- problem: 2,
+ problem: 2, // should be ignored from total count.
},
});
@@ -170,10 +170,10 @@ describe('ReviewImportDetails', () => {
expect(await screen.findByRole('alert')).toBeInTheDocument();
expect(await screen.findByText(/Import Analysis Complete/i)).toBeInTheDocument();
expect(await screen.findByText(
- /25.00% of content cannot be imported. For details see below./i,
+ /90% of course content will be imported into a collection in your library called Test Course. Some content will not be imported. For details see below./i,
)).toBeInTheDocument();
expect(await screen.findByText(/Total Blocks/i)).toBeInTheDocument();
- expect(await screen.findByText('9/12')).toBeInTheDocument();
+ expect(await screen.findByText('9/10')).toBeInTheDocument();
expect(await screen.findByText('Sections')).toBeInTheDocument();
expect(await screen.findByText('1')).toBeInTheDocument();
expect(await screen.findByText('Subsections')).toBeInTheDocument();
@@ -181,7 +181,7 @@ describe('ReviewImportDetails', () => {
expect(await screen.findByText('Units')).toBeInTheDocument();
expect(await screen.findByText('3')).toBeInTheDocument();
expect(await screen.findByText('Components')).toBeInTheDocument();
- expect(await screen.findByText('3/6')).toBeInTheDocument();
+ expect(await screen.findByText('3/4')).toBeInTheDocument();
expect(markAnalysisComplete).toHaveBeenCalledWith(true);
});
diff --git a/src/library-authoring/import-course/stepper/ReviewImportDetails.tsx b/src/library-authoring/import-course/stepper/ReviewImportDetails.tsx
index 75ddebbbb..0bd23b9f5 100644
--- a/src/library-authoring/import-course/stepper/ReviewImportDetails.tsx
+++ b/src/library-authoring/import-course/stepper/ReviewImportDetails.tsx
@@ -91,7 +91,8 @@ const Banner = ({ courseId, isBlockDataPending, unsupportedBlockPercentage }: Ba
@@ -207,8 +208,8 @@ export const ReviewImportDetails = ({ courseId, markAnalysisComplete }: Props) =
if (!blockTypes || !totalBlocks) {
return 0;
}
- return (finalUnssupportedBlocks / (totalBlocks + finalUnssupportedBlocks)) * 100;
- }, [blockTypes, finalUnssupportedBlocks]);
+ return (totalUnsupportedBlocks / (totalBlocks + totalUnsupportedBlocks)) * 100;
+ }, [blockTypes, totalUnsupportedBlocks]);
return (
@@ -217,24 +218,26 @@ export const ReviewImportDetails = ({ courseId, markAnalysisComplete }: Props) =
isBlockDataPending={isBlockDataPending}
unsupportedBlockPercentage={unsupportedBlockPercentage}
/>
-
-
- {!isBlockDataPending && finalUnssupportedBlocks > 0
+
+
+
+
+ {!isBlockDataPending && totalUnsupportedBlocks > 0
&& (
- <>
+
- >
+
)}
);