feat: add manual check links section separately for 403 links (#1751)

This commit is contained in:
Hina Khadim
2025-03-24 19:55:56 +05:00
committed by GitHub
parent 9e65424ca6
commit 545bb4a8a6
6 changed files with 84 additions and 20 deletions

View File

@@ -143,6 +143,7 @@ describe('CourseOptimizerPage', () => {
await waitFor(() => {
expect(getAllByText(scanResultsMessages.brokenLinkStatus.defaultMessage)[0]).toBeInTheDocument();
expect(queryAllByText(scanResultsMessages.lockedLinkStatus.defaultMessage)[0]).toBeInTheDocument();
expect(queryAllByText(scanResultsMessages.recommendedManualCheckText.defaultMessage)[0]).toBeInTheDocument();
});
});

View File

@@ -26,6 +26,7 @@ const mockApiResponse = {
url: 'https://example.com/intro-guide',
brokenLinks: ['https://example.com/broken-link-algo'],
lockedLinks: ['https://example.com/locked-link-algo'],
externalForbiddenLinks: ['https://outsider.com/forbidden-link-algo'],
},
],
},
@@ -92,6 +93,7 @@ const mockApiResponse = {
url: 'https://example.com/broken-link-algo',
brokenLinks: ['https://example.com/broken-link-algo'],
lockedLinks: ['https://example.com/locked-link-algo'],
externalForbiddenLinks: ['https://outsider.com/forbidden-link-algo'],
},
],
},

View File

@@ -1,5 +1,9 @@
import { Icon, Table } from '@openedx/paragon';
import { OpenInNew, Lock, LinkOff } from '@openedx/paragon/icons';
import {
Card, Icon, OverlayTrigger, Table, Tooltip,
} from '@openedx/paragon';
import {
OpenInNew, Lock, LinkOff, InfoOutline,
} from '@openedx/paragon/icons';
import { useIntl } from '@edx/frontend-platform/i18n';
import { FC } from 'react';
import { Unit } from '../types';
@@ -23,6 +27,26 @@ const GoToBlock: FC<{ block: { url: string } }> = ({ block }) => (
</span>
);
const RecommendedManualCheckHeading = () => {
const intl = useIntl();
return (
<span className="d-flex align-items-center font-weight-bold py-2">
{intl.formatMessage(messages.recommendedManualCheckText)}
<OverlayTrigger
key="top"
placement="top"
overlay={(
<Tooltip id="tooltip-top">
{intl.formatMessage(messages.recommendedManualCheckTooltip)}
</Tooltip>
)}
>
<Icon className="ml-1 pl-1" src={InfoOutline} />
</OverlayTrigger>
</span>
);
};
interface BrokenLinkTableProps {
unit: Unit;
showLockedLinks: boolean;
@@ -40,7 +64,7 @@ const BrokenLinkTable: FC<BrokenLinkTableProps> = ({
}) => {
const intl = useIntl();
return (
<>
<Card className="unit-card rounded-sm pt-2 pl-3 pr-4 mb-2.5">
<p className="unit-header">{unit.displayName}</p>
<Table
data={unit.blocks.reduce(
@@ -62,23 +86,42 @@ const BrokenLinkTable: FC<BrokenLinkTableProps> = ({
),
}));
acc.push(...blockBrokenLinks);
if (!showLockedLinks) {
return acc;
if (showLockedLinks) {
const blockLockedLinks = block.lockedLinks.map((link) => ({
blockLink: <GoToBlock block={block} />,
blockDisplayName: block.displayName || '',
brokenLink: <BrokenLinkHref href={link} />,
status: (
<span className="link-status-text">
<Icon src={Lock} className="lock-icon" />
{intl.formatMessage(messages.lockedLinkStatus)}{' '}
<LockedInfoIcon />
</span>
),
}));
acc.push(...blockLockedLinks);
}
if (block.externalForbiddenLinks?.length > 0) {
const recommendedManualCheckHeading = {
blockLink: <div />,
blockDisplayName: <RecommendedManualCheckHeading />,
brokenLink: <div />,
status: <div />,
};
const externalForbiddenLinks = block.externalForbiddenLinks.map((link) => ({
blockLink: <GoToBlock block={block} />,
blockDisplayName: block.displayName || '',
brokenLink: <BrokenLinkHref href={link} />,
status: <div />,
}));
acc.push(recommendedManualCheckHeading);
acc.push(...externalForbiddenLinks);
}
const blockLockedLinks = block.lockedLinks.map((link) => ({
blockLink: <GoToBlock block={block} />,
blockDisplayName: block.displayName || '',
brokenLink: <BrokenLinkHref href={link} />,
status: (
<span className="link-status-text">
<Icon src={Lock} className="lock-icon" />
{intl.formatMessage(messages.lockedLinkStatus)}{' '}
<LockedInfoIcon />
</span>
),
}));
acc.push(...blockLockedLinks);
return acc;
},
[],
@@ -110,7 +153,7 @@ const BrokenLinkTable: FC<BrokenLinkTableProps> = ({
},
]}
/>
</>
</Card>
);
};

View File

@@ -41,6 +41,15 @@
background-color: $dark-100;
padding: 10px;
margin-bottom: 10px;
&:not(:first-child){
margin-top: 1rem;
}
}
.unit-card{
border: 1px solid #BCBCBC;
box-shadow: 0 1px 2px rgb(0 0 0 / .15);
}
/* Subsection Header */
@@ -49,7 +58,7 @@
margin-top: 10px;
font-size: 14px;
font-weight: 700;
margin-bottom: 5px;
margin-bottom: .75rem;
color: $primary-500;
}

View File

@@ -41,6 +41,14 @@ const messages = defineMessages({
id: 'course-authoring.course-optimizer.lockedLinkStatus',
defaultMessage: 'Status: Locked',
},
recommendedManualCheckText: {
id: 'course-authoring.course-optimizer.recommendedManualCheckText',
defaultMessage: 'Recommended Manual Check',
},
recommendedManualCheckTooltip: {
id: 'course-authoring.course-optimizer.recommendedManualCheckTooltip',
defaultMessage: 'For websites returning 403, websites often show 403 because they don\'t want bots accessing their content',
},
});
export default messages;

View File

@@ -7,6 +7,7 @@ export interface Unit {
url: string;
brokenLinks: string[];
lockedLinks: string[];
externalForbiddenLinks: string[];
}[];
}