Skip to content

Commit d30a2f9

Browse files
authored
fix: match release status pill colors to the release schedule (#9246)
Use the same colors as the release schedule chart: EOL is red, Alpha is orange, Current is green, Active LTS is blue and Maintenance LTS is grey. Release data now flags LTS lines past their maintenance date so the table and the version dropdown can tell them apart. Also show the latest Alpha in the footer pills, which now wrap on narrow screens. Assisted-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 4c3ad03 commit d30a2f9

10 files changed

Lines changed: 95 additions & 16 deletions

File tree

‎.changeset/orange-pills-match.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@node-core/website-i18n': patch
3+
---
4+
5+
Add the Latest Alpha footer pill label.

‎apps/site/components/Downloads/Release/VersionDropdown.tsx‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,13 @@ const VersionDropdown: FC = () => {
6666
return (
6767
<WithNoScriptSelect
6868
ariaLabel={t('layouts.download.dropdown.version')}
69-
values={releases.map(({ status, versionWithPrefix }) => ({
69+
values={releases.map(({ status, isMaintenance, versionWithPrefix }) => ({
7070
value: versionWithPrefix,
7171
label: versionWithPrefix,
72-
badge: { label: status, kind: STATUS_KIND_MAP[status] },
72+
badge: {
73+
label: status,
74+
kind: isMaintenance ? 'neutral' : STATUS_KIND_MAP[status],
75+
},
7376
}))}
7477
defaultValue={release.versionWithPrefix}
7578
onChange={setVersionOrNavigate}

‎apps/site/components/Downloads/Release/__tests__/VersionDropdown.test.jsx‎

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const statuses = [
3131
{
3232
status: 'EOL',
3333
path: '/download',
34-
badgeKind: 'warning',
34+
badgeKind: 'error',
3535
versions: ['v18.0.0', 'v16.0.0'],
3636
},
3737
{
@@ -49,7 +49,7 @@ const statuses = [
4949
{
5050
status: 'Alpha',
5151
path: '/download/alpha',
52-
badgeKind: 'default',
52+
badgeKind: 'warning',
5353
versions: ['v26.0.0-alpha.1', 'v26.0.0-alpha.2'],
5454
},
5555
];
@@ -58,15 +58,15 @@ const releases = statuses.flatMap(({ status, versions }) =>
5858
versions.map(versionWithPrefix => ({ versionWithPrefix, status }))
5959
);
6060

61-
const renderDropdown = (release = releases[0]) => {
61+
const renderDropdown = (release = releases[0], allReleases = releases) => {
6262
const Dropdown = () => {
6363
const [version, updateVersion] = useState(release.versionWithPrefix);
6464
setVersion.mock.mockImplementation(updateVersion);
6565

6666
return (
6767
<ReleaseContext
6868
value={{
69-
release: releases.find(
69+
release: allReleases.find(
7070
candidate => candidate.versionWithPrefix === version
7171
),
7272
setVersion,
@@ -78,7 +78,7 @@ const renderDropdown = (release = releases[0]) => {
7878
};
7979

8080
render(
81-
<ReleasesContext value={{ releases, snippets: [] }}>
81+
<ReleasesContext value={{ releases: allReleases, snippets: [] }}>
8282
<Dropdown />
8383
</ReleasesContext>
8484
);
@@ -180,4 +180,22 @@ describe('VersionDropdown', () => {
180180
}
181181
});
182182
}
183+
184+
it('provides the neutral badge for LTS versions in maintenance', () => {
185+
const release = {
186+
versionWithPrefix: 'v22.0.0',
187+
status: 'LTS',
188+
isMaintenance: true,
189+
};
190+
191+
const { values } = renderDropdown(release, [release]);
192+
193+
assert.deepEqual(values, [
194+
{
195+
value: 'v22.0.0',
196+
label: 'v22.0.0',
197+
badge: { label: 'LTS', kind: 'neutral' },
198+
},
199+
]);
200+
});
183201
});

‎apps/site/components/Footer.tsx‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const Footer: FC = () => {
2626
};
2727

2828
const primary = (
29-
<div className="flex flex-row gap-2">
29+
<div className="flex flex-row flex-wrap justify-center gap-2">
3030
<WithNodeRelease status="LTS">
3131
{({ release }) => (
3232
<BadgeGroup
@@ -51,6 +51,19 @@ const Footer: FC = () => {
5151
</BadgeGroup>
5252
)}
5353
</WithNodeRelease>
54+
55+
<WithNodeRelease status="Alpha">
56+
{({ release }) => (
57+
<BadgeGroup
58+
size="small"
59+
kind="warning"
60+
badgeText={release.versionWithPrefix}
61+
href={`/blog/release/${release.versionWithPrefix}`}
62+
>
63+
{t('components.containers.footer.releasePills.latestAlpha')}
64+
</BadgeGroup>
65+
)}
66+
</WithNodeRelease>
5467
</div>
5568
);
5669

‎apps/site/components/Releases/PreviousReleasesTable/TableBody.tsx‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,14 @@ const PreviousReleasesTableBody: FC<PreviousReleasesTableBodyProps> = ({
5151
</td>
5252

5353
<td data-label={t('components.downloadReleasesTable.status')}>
54-
<Badge kind={STATUS_KIND_MAP[release.status]} size="small">
54+
<Badge
55+
kind={
56+
release.isMaintenance
57+
? 'neutral'
58+
: STATUS_KIND_MAP[release.status]
59+
}
60+
size="small"
61+
>
5562
{release.status}
5663
</Badge>
5764
</td>

‎apps/site/next-data/generators/__tests__/releaseData.test.mjs‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,37 @@ describe('generateReleaseData', () => {
102102
});
103103

104104
assert.equal(result[0]?.status, 'LTS');
105+
assert.equal(result[0]?.isMaintenance, false);
106+
});
107+
108+
it('flags LTS releases on or past their maintenance date', async t => {
109+
const result = await runWithNodevuData(t, '2026-10-20', {
110+
24: {
111+
releases: {
112+
'24.11.0': {
113+
semver: { major: 24, raw: '24.11.0' },
114+
dependencies: { npm: '11.6.1', v8: '13.6.233.10' },
115+
lts: { isLts: true },
116+
alpha: { isAlpha: false },
117+
releaseDate: '2026-10-14',
118+
modules: { version: '137' },
119+
},
120+
},
121+
support: {
122+
phases: {
123+
dates: {
124+
start: '2025-05-06',
125+
lts: '2025-10-28',
126+
maintenance: '2026-10-20',
127+
end: '2028-04-30',
128+
},
129+
},
130+
},
131+
},
132+
});
133+
134+
assert.equal(result[0]?.status, 'LTS');
135+
assert.equal(result[0]?.isMaintenance, true);
105136
});
106137

107138
it('returns Current when release is not EOL and LTS date has passed but latest is not LTS', async t => {

‎apps/site/next-data/generators/releaseData.mjs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,10 @@ const generateReleaseData = async () => {
3535
const latestVersion = versions[0];
3636
const initialVersion = versions[versions.length - 1];
3737

38+
const { maintenance, end } = major.support.phases.dates;
39+
3840
// Get the major release status based on our Release Schedule
39-
const status = getNodeReleaseStatus(
40-
latestVersion,
41-
major.support.phases.dates.end
42-
);
41+
const status = getNodeReleaseStatus(latestVersion, end);
4342

4443
const minorVersions = Object.entries(major.releases).map(([, release]) => ({
4544
modules: release.modules.version || '',
@@ -52,6 +51,7 @@ const generateReleaseData = async () => {
5251

5352
return {
5453
status,
54+
isMaintenance: status === 'LTS' && new Date() >= new Date(maintenance),
5555
major: latestVersion.semver.major,
5656
version: latestVersion.semver.raw,
5757
versionWithPrefix: `v${latestVersion.semver.raw}`,

‎apps/site/next.constants.mjs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,10 @@ export const SEVERITY_KIND_MAP = {
142142
* @type {Record<import('./types/releases').NodeReleaseStatus, import('@node-core/ui-components/Common/Badge').BadgeKind>}
143143
*/
144144
export const STATUS_KIND_MAP = {
145-
EOL: 'warning',
145+
EOL: 'error',
146146
LTS: 'info',
147147
Current: 'default',
148-
Alpha: 'default',
148+
Alpha: 'warning',
149149
};
150150

151151
/**

‎apps/site/types/releases.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ export type MinorVersion = {
2323
export type NodeRelease = {
2424
versionWithPrefix: string;
2525
status: NodeReleaseStatus;
26+
isMaintenance: boolean;
2627
minorVersions: Array<MinorVersion>;
2728
} & NodeReleaseSource;

‎packages/i18n/src/locales/en.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
},
2626
"releasePills": {
2727
"latestLTS": "Latest LTS",
28-
"latestRelease": "Latest Release"
28+
"latestRelease": "Latest Release",
29+
"latestAlpha": "Latest Alpha"
2930
}
3031
},
3132
"navBar": {

0 commit comments

Comments
 (0)