refactor: update placeholder block and import details page (#2761)

* Updates placeholder block color and icon.
* Moves `View Imported Content` & `Retry import` buttons in import details page inside alert at the top.
* Updates page title to include Import status in import details page.
This commit is contained in:
Navin Karkera
2025-12-17 22:13:12 +05:30
committed by GitHub
parent 41a326f7b4
commit 6f37118960
5 changed files with 76 additions and 70 deletions

View File

@@ -198,28 +198,3 @@
}
}
}
.component-style-import-placeholder {
background-color: #AB0E01;
.pgn__icon:not(.btn-icon-before) {
color: white;
}
.btn-icon {
&:hover, &:active, &:focus {
background-color: darken(#AB0E01, 15%);
}
}
.btn {
background-color: lighten(#AB0E01, 10%);
border: 0;
&:hover, &:active, &:focus {
background-color: lighten(#AB0E01, 20%);
border: 1px solid var(--pgn-color-primary-base);
margin: -1px;
}
}
}

View File

@@ -12,7 +12,7 @@ import ComponentCount from '@src/generic/component-count';
import TagCount from '@src/generic/tag-count';
import { BlockTypeLabel, type ContentHitTags, Highlight } from '@src/search-manager';
import { skipIfUnwantedTarget } from '@src/utils';
import { Report } from '@openedx/paragon/icons';
import { ExtensionOff } from '@openedx/paragon/icons';
import messages from './messages';
type BaseCardProps = {
@@ -48,9 +48,9 @@ const BaseCard = ({
+ (tags.level2?.length || 0) + (tags.level3?.length || 0);
}, [tags]);
const itemIcon = getItemIcon(itemType);
const itemIcon = !props.isPlaceholder ? getItemIcon(itemType) : ExtensionOff;
const intl = useIntl();
const itemComponentStyle = !props.isPlaceholder ? getComponentStyleColor(itemType) : 'component-style-import-placeholder';
const itemComponentStyle = !props.isPlaceholder ? getComponentStyleColor(itemType) : 'component-style-other';
return (
<Container className="library-item-card selected">
@@ -67,7 +67,7 @@ const BaseCard = ({
<Card.Header
className={`library-item-header ${itemComponentStyle}`}
title={
<Icon src={props.isPlaceholder ? Report : itemIcon} className="library-item-header-icon my-2" />
<Icon src={itemIcon} className="library-item-header-icon my-2" />
}
actions={(
<div

View File

@@ -30,7 +30,7 @@ const ImportDetailsContent = () => {
const intl = useIntl();
const navigate = useNavigate();
const [enableRefeshState, setEnableRefreshState] = useState(true);
const { libraryId } = useLibraryContext();
const { libraryId, libraryData } = useLibraryContext();
const { courseId, migrationTaskId } = useParams();
const { showToast } = useContext(ToastContext);
const [disableReimport, setDisableReimport] = useState(false);
@@ -228,7 +228,25 @@ const ImportDetailsContent = () => {
if (migrationStatus === 'Succeeded') {
return (
<Stack gap={3}>
<Alert variant="success" icon={CheckCircle}>
<Helmet>
<title>
{libraryData?.title || ''} | {intl.formatMessage(messages.importSuccessfulAlertTitle)} | {process.env.SITE_NAME}
</title>
</Helmet>
<Alert
variant="success"
icon={CheckCircle}
stacked
actions={[
<Button
variant="outline-primary"
iconAfter={ArrowForward}
onClick={() => navigate(collectionLink())}
>
<FormattedMessage {...messages.viewImportedContentButton} />
</Button>,
]}
>
<Alert.Heading>
<FormattedMessage {...messages.importSuccessfulAlertTitle} />
</Alert.Heading>
@@ -260,21 +278,31 @@ const ImportDetailsContent = () => {
}}
/>
</p>
<div className="w-100 d-flex justify-content-end">
<Button
variant="outline-primary"
iconAfter={ArrowForward}
onClick={() => navigate(collectionLink())}
>
<FormattedMessage {...messages.viewImportedContentButton} />
</Button>
</div>
</Stack>
);
} if (migrationStatus === 'Failed') {
return (
<Stack gap={3}>
<Alert variant="danger" icon={Info}>
<Helmet>
<title>
{libraryData?.title || ''} | {intl.formatMessage(messages.importFailedAlertTitle)} | {process.env.SITE_NAME}
</title>
</Helmet>
<Alert
variant="danger"
icon={Info}
stacked
actions={[
<Button
variant="outline-primary"
iconAfter={ArrowForward}
onClick={handleImportCourse}
disabled={disableReimport}
>
<FormattedMessage {...messages.importFailedRetryImportButton} />
</Button>,
]}
>
<Alert.Heading>
<FormattedMessage {...messages.importFailedAlertTitle} />
</Alert.Heading>
@@ -291,22 +319,30 @@ const ImportDetailsContent = () => {
<p>
<FormattedMessage {...messages.importFailedDetailsSectionBody} />
</p>
<div className="w-100 d-flex justify-content-end">
<Button
variant="outline-primary"
iconAfter={ArrowForward}
onClick={handleImportCourse}
disabled={disableReimport}
>
<FormattedMessage {...messages.importFailedRetryImportButton} />
</Button>
</div>
</Stack>
);
} if (migrationStatus === 'Partial Succeeded') {
return (
<Stack gap={3}>
<Alert variant="warning" icon={WarningFilled}>
<Helmet>
<title>
{libraryData?.title || ''} | {intl.formatMessage(messages.importPartialAlertTitle)} | {process.env.SITE_NAME}
</title>
</Helmet>
<Alert
variant="warning"
icon={WarningFilled}
stacked
actions={[
<Button
variant="outline-primary"
iconAfter={ArrowForward}
onClick={() => navigate(collectionLink())}
>
<FormattedMessage {...messages.viewImportedContentButton} />
</Button>,
]}
>
<Alert.Heading>
<FormattedMessage {...messages.importPartialAlertTitle} />
</Alert.Heading>
@@ -370,16 +406,6 @@ const ImportDetailsContent = () => {
<DataTable.TableFooter />
</DataTable>
)}
<div className="w-100 d-flex justify-content-end">
<Button
variant="outline-primary"
iconAfter={ArrowForward}
onClick={() => navigate(collectionLink())}
>
<FormattedMessage {...messages.viewImportedContentButton} />
</Button>
</div>
</Stack>
);
}
@@ -423,17 +449,13 @@ export interface MigrationSummary {
export const ImportDetailsPage = () => {
const intl = useIntl();
const { libraryId, libraryData, readOnly } = useLibraryContext();
const { courseId } = useParams();
const {
data: courseDetails,
} = useCourseDetails(courseId);
return (
<div className="d-flex">
<Helmet>
<title>{libraryData?.title || ''} | {process.env.SITE_NAME}</title>
</Helmet>
<div className="flex-grow-1">
<Helmet>
<title>{courseDetails?.title ?? ''} | {process.env.SITE_NAME}</title>
</Helmet>
<Header
number={libraryData?.slug}
title={libraryData?.title}

View File

@@ -1,4 +1,6 @@
import { useIntl } from '@edx/frontend-platform/i18n';
import BaseCard from '../components/BaseCard';
import messages from './messages';
interface PlaceHolderCardProps {
blockType: string;
@@ -7,7 +9,9 @@ interface PlaceHolderCardProps {
}
const PlaceholderCard = ({ blockType, displayName, description }: PlaceHolderCardProps) => {
const truncatedDescription = description ? `${description.substring(0, 40) }...` : undefined;
const intl = useIntl();
const defaultDescription = intl.formatMessage(messages.placeholderCardDescription);
const truncatedDescription = description ? `${description.substring(0, 40) }...` : defaultDescription;
/* istanbul ignore next */
return (
<BaseCard

View File

@@ -313,6 +313,11 @@ const messages = defineMessages({
defaultMessage: 'Reason For Failed import',
description: 'Label for the Reason For Failed import field in the Reasons table in the import details',
},
placeholderCardDescription: {
id: 'library-authoring.import-course.import-failed.placeholder.description',
defaultMessage: 'This content type is not currently supported',
description: 'Description text for placeholder card in library for blocks that failed to import',
},
});
export default messages;