Skip to content

Commit 5909a0b

Browse files
bmuenzenmeyeravivkellerovflowdjoyeecheungRaisinTen
authored
feat: add eol page (#7990)
* feat: add eol page Co-Authored-By: Aviv Keller <[email protected]> * Update Modal.tsx Signed-off-by: Claudio Wunder <[email protected]> * expand and do not reuse i18n keys this helps our features be more portable * add one more i18n key * add footer to article layout * Update apps/site/components/EOL/Table.tsx Signed-off-by: Brian Muenzenmeyer <[email protected]> * cleanup unused classnames * simplify Table * normalize endOfLife vs eol * Apply suggestions from code review Co-authored-by: Joyee Cheung <[email protected]> Signed-off-by: Brian Muenzenmeyer <[email protected]> * add back in the release schedule link i think it is important to give people breadcrumbs like this * small grammar / tense / capitalization changes * Update apps/site/pages/en/eol.mdx Co-authored-by: Darshan Sen <[email protected]> Signed-off-by: Claudio Wunder <[email protected]> * increase gap between vulnerability chips * make all translation strings long-form per feedback, this helps with static analysis. this scope included code not introduced in this PR * document translation key retrieval * rename variable * move CTAs up * chore: button variants, and updated eol page; removed translated previous-releases (outdated pages) * rename EOLModal/index per standard * rename components per docs and patterns * chore: design improvements * chore: tiny mobile improvement * chore: apply suggestions * chore: apply text suggestions * chore: balance the buttons * fix a11y issue on mdx rendering * chore: make it rain tm * Update vulnerabilities.mjs Co-authored-by: Copilot <[email protected]> Signed-off-by: Aviv Keller <[email protected]> * apply aviv"s suggestions - manually added as the redirect also needed a locale AFAIK * types and constants cleanup * fix import * more types cleanup * one final type lint actually ran locally. this instance is still suffering from some wonky husky problems * move link below buttons * move URL to constants * rename variable * tighten up UnknownSeverity types * format after refactor * memoize calls * simplify translation call * apply suggestion * apply linter * refator vulnerability grouping, add unit tests * avoid passing modal via frontmatter * generify modal props * move checks into children components * pass all vulns to children * fixup! * no modal provider * rename ref to url * fix type * use proper import specifier * tweak memo per review * destructure and cleanup. net, more lines of code, shrug * move key after fragment introduced fixes warning * change herodevs link to be a direct anchor, with no event listener from next * use rich translation for EOLAlertBox * chore: recommendation under Signed-off-by: Claudio Wunder <[email protected]> * Update apps/site/components/EOL/VulnerabilityChips/Chip/index.tsx Co-authored-by: Claudio Wunder <[email protected]> Signed-off-by: Brian Muenzenmeyer <[email protected]> * use filtered vulnerabilities * add space * use consistent modern looping * chore: cleanup, refactor + fixes * fix: tests --------- Signed-off-by: Claudio Wunder <[email protected]> Signed-off-by: Brian Muenzenmeyer <[email protected]> Signed-off-by: Aviv Keller <[email protected]> Co-authored-by: Aviv Keller <[email protected]> Co-authored-by: Claudio Wunder <[email protected]> Co-authored-by: Joyee Cheung <[email protected]> Co-authored-by: Darshan Sen <[email protected]> Co-authored-by: Claudio Wunder <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 5e81a17 commit 5909a0b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+1039
-732
lines changed

apps/site/components/Common/Button.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import BaseButton, {
2-
type ButtonProps,
3-
} from '@node-core/ui-components/Common/BaseButton';
1+
import BaseButton from '@node-core/ui-components/Common/BaseButton';
2+
import type { ButtonProps } from '@node-core/ui-components/Common/BaseButton';
43
import type { FC, ComponentProps } from 'react';
54

65
import Link from '#site/components/Link';

apps/site/components/Downloads/DownloadReleasesTable/DetailsButton.tsx

Lines changed: 0 additions & 30 deletions
This file was deleted.

apps/site/components/Downloads/DownloadReleasesTable/index.tsx

Lines changed: 0 additions & 60 deletions
This file was deleted.

apps/site/components/Downloads/Release/ReleaseCodeBox.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ const ReleaseCodeBox: FC = () => {
122122
size="small"
123123
>
124124
{t.rich('layouts.download.codeBox.unsupportedVersionWarning', {
125-
link: text => <Link href="/about/previous-releases/">{text}</Link>,
125+
link: text => <Link href="/eol">{text}</Link>,
126126
})}
127127
</AlertBox>
128128
)}

apps/site/components/EOL/EOLAlert.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import AlertBox from '@node-core/ui-components/Common/AlertBox';
2+
import { useTranslations } from 'next-intl';
3+
4+
import Link from '#site/components/Link';
5+
6+
const EOLAlert = () => {
7+
const t = useTranslations();
8+
return (
9+
<AlertBox level="warning">
10+
{t.rich('components.eolAlert.message', {
11+
link: text => <Link href="/eol">{text}</Link>,
12+
})}
13+
</AlertBox>
14+
);
15+
};
16+
17+
export default EOLAlert;

apps/site/components/EOL/EOLModal.tsx

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { Modal, Title, Content } from '@node-core/ui-components/Common/Modal';
2+
import { useTranslations } from 'next-intl';
3+
import { useMemo } from 'react';
4+
import type { FC, ComponentProps } from 'react';
5+
6+
import KnownSeveritySection from '#site/components/EOL/KnownSeveritySection';
7+
import UnknownSeveritySection from '#site/components/EOL/UnknownSeveritySection';
8+
import { SEVERITY_ORDER } from '#site/next.constants.mjs';
9+
import type { NodeRelease } from '#site/types/releases';
10+
import type { Vulnerability } from '#site/types/vulnerabilities';
11+
12+
type EOLModalProps = ComponentProps<typeof Modal> & {
13+
release: NodeRelease;
14+
vulnerabilities: Array<Vulnerability>;
15+
};
16+
17+
const EOLModal: FC<EOLModalProps> = ({
18+
release: { codename, major: version },
19+
vulnerabilities,
20+
...props
21+
}) => {
22+
const t = useTranslations();
23+
24+
const modalHeading = codename
25+
? t('components.eolModal.title', { version, codename })
26+
: t('components.eolModal.titleWithoutCodename', { version });
27+
28+
useMemo(
29+
() =>
30+
vulnerabilities.sort(
31+
(a, b) =>
32+
SEVERITY_ORDER.indexOf(a.severity) -
33+
SEVERITY_ORDER.indexOf(b.severity)
34+
),
35+
// Only change when the vulnerabilities change
36+
// eslint-disable-next-line react-hooks/exhaustive-deps
37+
[vulnerabilities.length]
38+
);
39+
40+
return (
41+
<Modal {...props}>
42+
<Title>{modalHeading}</Title>
43+
<Content>
44+
{vulnerabilities.length > 0 && (
45+
<p className="m-1">
46+
{t('components.eolModal.vulnerabilitiesMessage', {
47+
count: vulnerabilities.length,
48+
})}
49+
</p>
50+
)}
51+
52+
<KnownSeveritySection vulnerabilities={vulnerabilities} />
53+
<UnknownSeveritySection vulnerabilities={vulnerabilities} />
54+
55+
{!vulnerabilities.length && (
56+
<p className="m-1">
57+
{t('components.eolModal.noVulnerabilitiesMessage')}
58+
</p>
59+
)}
60+
</Content>
61+
</Modal>
62+
);
63+
};
64+
65+
export default EOLModal;
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
'use client';
2+
3+
import { useTranslations } from 'next-intl';
4+
import { Fragment, useState } from 'react';
5+
import type { FC } from 'react';
6+
7+
import FormattedTime from '#site/components/Common/FormattedTime';
8+
import EOLModal from '#site/components/EOL/EOLModal';
9+
import VulnerabilityChips from '#site/components/EOL/VulnerabilityChips';
10+
import LinkWithArrow from '#site/components/LinkWithArrow';
11+
import provideReleaseData from '#site/next-data/providers/releaseData';
12+
import provideVulnerabilities from '#site/next-data/providers/vulnerabilities';
13+
import { EOL_VERSION_IDENTIFIER } from '#site/next.constants.mjs';
14+
15+
const EOLReleaseTable: FC = () => {
16+
const releaseData = provideReleaseData();
17+
const vulnerabilities = provideVulnerabilities();
18+
19+
const eolReleases = releaseData.filter(
20+
release => release.status === EOL_VERSION_IDENTIFIER
21+
);
22+
23+
const t = useTranslations();
24+
25+
const [currentModal, setCurrentModal] = useState<string | undefined>();
26+
27+
return (
28+
<table id="tbVulnerabilities">
29+
<thead>
30+
<tr>
31+
<th>
32+
{t('components.eolTable.version')} (
33+
{t('components.eolTable.codename')})
34+
</th>
35+
<th>{t('components.eolTable.lastUpdated')}</th>
36+
<th>{t('components.eolTable.vulnerabilities')}</th>
37+
<th>{t('components.eolTable.details')}</th>
38+
</tr>
39+
</thead>
40+
41+
<tbody>
42+
{eolReleases.map(release => (
43+
<Fragment key={release.major}>
44+
<tr>
45+
<td data-label="Version">
46+
v{release.major}{' '}
47+
{release.codename ? `(${release.codename})` : ''}
48+
</td>
49+
50+
<td data-label="Date">
51+
<FormattedTime date={release.releaseDate} />
52+
</td>
53+
54+
<td>
55+
<VulnerabilityChips
56+
vulnerabilities={vulnerabilities[release.major]}
57+
/>
58+
</td>
59+
60+
<td>
61+
<LinkWithArrow
62+
className="cursor-pointer"
63+
onClick={() => setCurrentModal(release.version)}
64+
>
65+
{t('components.downloadReleasesTable.details')}
66+
</LinkWithArrow>
67+
</td>
68+
</tr>
69+
70+
<EOLModal
71+
release={release}
72+
vulnerabilities={vulnerabilities[release.major]}
73+
open={currentModal === release.version}
74+
onOpenChange={open => open || setCurrentModal(undefined)}
75+
/>
76+
</Fragment>
77+
))}
78+
</tbody>
79+
</table>
80+
);
81+
};
82+
83+
export default EOLReleaseTable;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type { FC } from 'react';
2+
3+
import VulnerabilitiesTable from '#site/components/EOL/VulnerabilitiesTable';
4+
import type { Vulnerability } from '#site/types/vulnerabilities';
5+
6+
type KnownSeveritySectionProps = {
7+
vulnerabilities: Array<Vulnerability>;
8+
};
9+
10+
const KnownSeveritySection: FC<KnownSeveritySectionProps> = ({
11+
vulnerabilities,
12+
}) => {
13+
const knownVulnerabilities = vulnerabilities.filter(
14+
v => v.severity !== 'unknown'
15+
);
16+
17+
if (!knownVulnerabilities.length) {
18+
return null;
19+
}
20+
21+
return <VulnerabilitiesTable vulnerabilities={knownVulnerabilities} />;
22+
};
23+
24+
export default KnownSeveritySection;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { useTranslations } from 'next-intl';
2+
import type { FC } from 'react';
3+
4+
import VulnerabilitiesTable from '#site/components/EOL/VulnerabilitiesTable';
5+
import type { Vulnerability } from '#site/types/vulnerabilities';
6+
7+
type UnknownSeveritySectionProps = {
8+
vulnerabilities: Array<Vulnerability>;
9+
};
10+
11+
const UnknownSeveritySection: FC<UnknownSeveritySectionProps> = ({
12+
vulnerabilities,
13+
}) => {
14+
const t = useTranslations();
15+
16+
const unknownVulnerabilities = vulnerabilities.filter(
17+
v => v.severity === 'unknown'
18+
);
19+
20+
if (!unknownVulnerabilities.length) {
21+
return null;
22+
}
23+
24+
return (
25+
<details open={unknownVulnerabilities.length === vulnerabilities.length}>
26+
<summary className="cursor-pointer font-semibold">
27+
{t('components.eolModal.showUnknownSeverities')} (
28+
{unknownVulnerabilities.length})
29+
</summary>
30+
<div className="mt-4">
31+
<VulnerabilitiesTable
32+
vulnerabilities={unknownVulnerabilities}
33+
maxWidth={'max-w-3xs'}
34+
/>
35+
</div>
36+
</details>
37+
);
38+
};
39+
40+
export default UnknownSeveritySection;

0 commit comments

Comments
 (0)