-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
feat: add eol page #7990
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: add eol page #7990
Changes from all commits
02db91b
113334f
6bc1393
967676d
5cd1b33
d2b7826
b294b44
4204159
2cadb0c
55abd69
1a4a53a
51c5fb0
ea43096
d94d5ce
1dccbd5
21014bd
ff6ddec
9c68dd0
f8cab5e
2fbd30a
7babcc8
07befbb
594531f
c4abb0e
e471cb0
6b7bde7
2a748fd
e0f7c44
5ab2cbb
26f5b81
16f5992
ccbba0f
40df1ab
f424d53
7724afb
669d21d
04e4f5c
89e5c92
748e116
9fe21cc
4836bef
c147efc
847897b
d61bd30
1a522c8
dd10604
fb31b90
6957f21
1c499dd
1a7a80a
029ee7d
54fe024
9a8c6c7
92cdd9a
f579c6f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,21 @@ | ||
import AlertBox from '@node-core/ui-components/Common/AlertBox'; | ||
import { Modal, Title, Content } from '@node-core/ui-components/Common/Modal'; | ||
import { useTranslations } from 'next-intl'; | ||
import type { FC } from 'react'; | ||
import type { ComponentProps, FC } from 'react'; | ||
|
||
import { MinorReleasesTable } from '#site/components/Downloads/MinorReleasesTable'; | ||
import { ReleaseOverview } from '#site/components/Downloads/ReleaseOverview'; | ||
import Link from '#site/components/Link'; | ||
import type { NodeRelease } from '#site/types'; | ||
|
||
type ReleaseModalProps = { | ||
isOpen: boolean; | ||
closeModal: () => void; | ||
type ReleaseModalProps = ComponentProps<typeof Modal> & { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We still can have a shared prop for |
||
release: NodeRelease; | ||
}; | ||
|
||
const ReleaseModal: FC<ReleaseModalProps> = ({ | ||
isOpen, | ||
closeModal, | ||
release, | ||
onOpenChange, | ||
...props | ||
}) => { | ||
const t = useTranslations(); | ||
|
||
|
@@ -31,7 +29,7 @@ const ReleaseModal: FC<ReleaseModalProps> = ({ | |
}); | ||
|
||
return ( | ||
<Modal open={isOpen} onOpenChange={closeModal}> | ||
<Modal onOpenChange={onOpenChange} {...props}> | ||
{release.status === 'End-of-life' && ( | ||
<div className="mb-4"> | ||
<AlertBox | ||
|
@@ -40,14 +38,7 @@ const ReleaseModal: FC<ReleaseModalProps> = ({ | |
size="small" | ||
> | ||
{t.rich('components.releaseModal.unsupportedVersionWarning', { | ||
link: text => ( | ||
<Link | ||
onClick={closeModal} | ||
href="/about/previous-releases#release-schedule" | ||
> | ||
{text} | ||
</Link> | ||
), | ||
link: text => <Link href="/eol">{text}</Link>, | ||
})} | ||
</AlertBox> | ||
</div> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import AlertBox from '@node-core/ui-components/Common/AlertBox'; | ||
import { useTranslations } from 'next-intl'; | ||
|
||
import Link from '#site/components/Link'; | ||
|
||
const EOLAlert = () => { | ||
const t = useTranslations(); | ||
return ( | ||
<AlertBox level="warning"> | ||
{t('components.eolAlert.intro')}{' '} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually this whole thing could be an i18n string. And you pass the |
||
<Link href="/eol"> | ||
OpenJS Ecosystem Sustainability Program{' '} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This whole thing should be an i18n string. Even more due to RTL languages. |
||
{t('components.eolAlert.partner')} HeroDevs | ||
</Link> | ||
</AlertBox> | ||
); | ||
}; | ||
|
||
export default EOLAlert; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,66 @@ | ||||||
import { Modal, Title, Content } from '@node-core/ui-components/Common/Modal'; | ||||||
import { useTranslations } from 'next-intl'; | ||||||
import { useMemo } from 'react'; | ||||||
import type { FC, ComponentProps } from 'react'; | ||||||
|
||||||
import KnownSeveritySection from '#site/components/EOL/KnownSeveritySection'; | ||||||
import UnknownSeveritySection from '#site/components/EOL/UnknownSeveritySection'; | ||||||
import { SEVERITY_ORDER } from '#site/next.constants.mjs'; | ||||||
import type { NodeRelease } from '#site/types/releases'; | ||||||
import type { Vulnerability } from '#site/types/vulnerabilities'; | ||||||
|
||||||
type EOLModalProps = ComponentProps<typeof Modal> & { | ||||||
release: NodeRelease; | ||||||
vulnerabilities: Array<Vulnerability>; | ||||||
}; | ||||||
|
||||||
const EOLModal: FC<EOLModalProps> = ({ | ||||||
release, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we destruct this to:
Suggested change
|
||||||
vulnerabilities, | ||||||
...props | ||||||
}) => { | ||||||
const t = useTranslations(); | ||||||
|
||||||
const modalHeading = release.codename | ||||||
? t('components.eolModal.title', { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which would allow us to do: t('components.eolModal.title', { major, codename }) |
||||||
version: release.major, | ||||||
codename: release.codename, | ||||||
}) | ||||||
: t('components.eolModal.titleWithoutCodename', { version: release.major }); | ||||||
|
||||||
useMemo( | ||||||
() => | ||||||
vulnerabilities.sort( | ||||||
(a, b) => | ||||||
SEVERITY_ORDER.indexOf(a.severity) - | ||||||
SEVERITY_ORDER.indexOf(b.severity) | ||||||
), | ||||||
[vulnerabilities] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Should be enough and less expensive |
||||||
); | ||||||
|
||||||
return ( | ||||||
<Modal {...props}> | ||||||
<Title>{modalHeading}</Title> | ||||||
<Content> | ||||||
{vulnerabilities.length > 0 && ( | ||||||
<p className="m-1"> | ||||||
{t('components.eolModal.vulnerabilitiesMessage', { | ||||||
count: vulnerabilities.length, | ||||||
})} | ||||||
</p> | ||||||
)} | ||||||
|
||||||
<KnownSeveritySection vulnerabilities={vulnerabilities} /> | ||||||
<UnknownSeveritySection vulnerabilities={vulnerabilities} /> | ||||||
|
||||||
{!vulnerabilities.length && ( | ||||||
<p className="m-1"> | ||||||
{t('components.eolModal.noVulnerabilitiesMessage')} | ||||||
</p> | ||||||
)} | ||||||
</Content> | ||||||
</Modal> | ||||||
); | ||||||
}; | ||||||
|
||||||
export default EOLModal; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
'use client'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This shouldn't be a client component, does it really need to be? It forces the provdeVulnerabilities and provideReleaseData to run on client-side too. + Even if EOLModal is a client component, that's completely fine, as it will just slot in, afaik. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, that's due to useState.... 🤔 In this case, I wonder how this will behave. It will probably run these fetch() requests on the client-side, which we want to avoid. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we move'em to another sub-component, we'll have the same situation as of: React splitting the prop data into the client-side. At the very least Next.js will do an initial hydration, so there won't be load times for users to see this. But these requests will definitely run every time they open this page.... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ![]() Yeah it is requesting on every load, although it does then cache and load from disk cache. My wonder is:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only thought here is, do we have other pages that are also running these fetch requests on client-side? During the development of this website, we made a conscious effort for all these requests to only be server-side, should we be fine with them being client-side? Instead of having mixed JSONs within the bundle? |
||
|
||
import { useTranslations } from 'next-intl'; | ||
import { useState } from 'react'; | ||
import type { FC } from 'react'; | ||
|
||
import FormattedTime from '#site/components/Common/FormattedTime'; | ||
import VulnerabilityChips from '#site/components/EOL/VulnerabilityChips'; | ||
import LinkWithArrow from '#site/components/LinkWithArrow'; | ||
import provideReleaseData from '#site/next-data/providers/releaseData'; | ||
import provideVulnerabilities from '#site/next-data/providers/vulnerabilities'; | ||
import { EOL_VERSION_IDENTIFIER } from '#site/next.constants.mjs'; | ||
|
||
import EOLModal from '../EOLModal'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Full import descriptors please 🙇 |
||
|
||
const EOLReleaseTable: FC = () => { | ||
const releaseData = provideReleaseData(); | ||
const vulnerabilities = provideVulnerabilities(); | ||
const eolReleases = releaseData.filter( | ||
release => release.status === EOL_VERSION_IDENTIFIER | ||
); | ||
|
||
const t = useTranslations(); | ||
|
||
const [currentModal, setCurrentModal] = useState<string | undefined>(); | ||
|
||
return ( | ||
<table id="tbVulnerabilities"> | ||
<thead> | ||
<tr> | ||
<th> | ||
{t('components.eolTable.version')} ( | ||
{t('components.eolTable.codename')}) | ||
</th> | ||
<th>{t('components.eolTable.lastUpdated')}</th> | ||
<th>{t('components.eolTable.vulnerabilities')}</th> | ||
<th>{t('components.eolTable.details')}</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{eolReleases.map(release => ( | ||
<> | ||
<tr key={release.major}> | ||
<td data-label="Version"> | ||
v{release.major}{' '} | ||
{release.codename ? `(${release.codename})` : ''} | ||
</td> | ||
<td data-label="Date"> | ||
<FormattedTime date={release.releaseDate} /> | ||
</td> | ||
<td> | ||
<VulnerabilityChips | ||
vulnerabilities={vulnerabilities[release.major]} | ||
/> | ||
</td> | ||
<td> | ||
<LinkWithArrow | ||
className="cursor-pointer" | ||
onClick={() => setCurrentModal(release.version)} | ||
> | ||
{t('components.downloadReleasesTable.details')} | ||
</LinkWithArrow> | ||
</td> | ||
</tr> | ||
<EOLModal | ||
release={release} | ||
vulnerabilities={vulnerabilities[release.major]} | ||
open={currentModal === release.version} | ||
onOpenChange={open => open || setCurrentModal(undefined)} | ||
/> | ||
</> | ||
))} | ||
</tbody> | ||
</table> | ||
); | ||
}; | ||
|
||
export default EOLReleaseTable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the modalProps could just be
onClose
since we know when it is open or not ;)So tha
onClose
becomes just afn