Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import { useTranslations } from 'next-intl';
import { use, useEffect, useMemo } from 'react';

import { ReleaseContext } from '#site/providers/releaseProvider';
import { nextItem, INSTALL_METHODS, parseCompat } from '#site/util/download';
import {
availableItems,
nextItem,
INSTALL_METHODS,
parseCompat,
} from '#site/util/download';

import type { InstallationMethod } from '#site/types/release';
import type { FC } from 'react';
Expand All @@ -16,7 +21,7 @@ const InstallationMethodDropdown: FC = () => {

// We parse the compatibility of the dropdown items
const parsedInstallMethods = useMemo(
() => parseCompat(INSTALL_METHODS, release),
() => availableItems(parseCompat(INSTALL_METHODS, release)),
Comment thread
cursor[bot] marked this conversation as resolved.
// We only want to react on the change of the OS and Version
// eslint-disable-next-line @eslint-react/exhaustive-deps
[release.os, release.version]
Expand All @@ -25,16 +30,17 @@ const InstallationMethodDropdown: FC = () => {
// We group Platforms on the Platform Dropdown to provide the User
// understanding of what is recommended/official and what is not.
const grouppedMethods = useMemo(
() => [
{
label: t('layouts.download.dropdown.platformGroups.official'),
items: parsedInstallMethods.filter(({ recommended }) => recommended),
},
{
label: t('layouts.download.dropdown.platformGroups.unofficial'),
items: parsedInstallMethods.filter(({ recommended }) => !recommended),
},
],
() =>
[
{
label: t('layouts.download.dropdown.platformGroups.official'),
items: parsedInstallMethods.filter(({ recommended }) => recommended),
},
{
label: t('layouts.download.dropdown.platformGroups.unofficial'),
items: parsedInstallMethods.filter(({ recommended }) => !recommended),
},
].filter(({ items }) => items.length > 0),
// We only want to react on the change of the parsedPlatforms
// eslint-disable-next-line @eslint-react/exhaustive-deps
[parsedInstallMethods]
Expand All @@ -46,10 +52,11 @@ const InstallationMethodDropdown: FC = () => {
// `detectOS` has finished running and decided what platform we are running on.
if (release.os !== 'LOADING' && release.installMethod === '') {
const installationMethod =
// Sets either the utmost recommended platform or the first non-disabled one
// Note that the first item of groupped platforms is always the recommended one
nextItem<InstallationMethod | ''>('', grouppedMethods[0].items) ||
nextItem<InstallationMethod | ''>('', parsedInstallMethods);
// Sets either the utmost recommended method or the first available one
nextItem<InstallationMethod | ''>(
'',
grouppedMethods[0]?.items ?? []
) || nextItem<InstallationMethod | ''>('', parsedInstallMethods);

// This will never return an empty string as there should always be an item
// when the OS has finished loading for a given installation method
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import { use, useEffect, useMemo } from 'react';

import useClientContext from '#site/hooks/useClientContext';
import { ReleaseContext } from '#site/providers/releaseProvider';
import { nextItem, OPERATING_SYSTEMS, parseCompat } from '#site/util/download';
import {
availableItems,
nextItem,
OPERATING_SYSTEMS,
parseCompat,
} from '#site/util/download';

import type { OperatingSystem } from '#site/types/userAgent';
import type { FC } from 'react';
Expand All @@ -30,7 +35,7 @@ const OperatingSystemDropdown: FC<OperatingSystemDropdownProps> = () => {

// We parse the compatibility of the dropdown items
const parsedOperatingSystems = useMemo(
() => parseCompat(OPERATING_SYSTEMS, release),
() => availableItems(parseCompat(OPERATING_SYSTEMS, release)),
// We only want to react on the change of the Install Method and Version
// eslint-disable-next-line @eslint-react/exhaustive-deps
[release.installMethod, release.version]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import { useTranslations } from 'next-intl';
import { use, useEffect, useMemo } from 'react';

import { ReleaseContext } from '#site/providers/releaseProvider';
import { nextItem, PACKAGE_MANAGERS, parseCompat } from '#site/util/download';
import {
availableItems,
nextItem,
PACKAGE_MANAGERS,
parseCompat,
} from '#site/util/download';

import type { PackageManager } from '#site/types/release';
import type { FC } from 'react';
Expand All @@ -16,7 +21,7 @@ const PackageManagerDropdown: FC = () => {

// We parse the compatibility of the dropdown items
const parsedPackageManagers = useMemo(
() => parseCompat(PACKAGE_MANAGERS, release),
() => availableItems(parseCompat(PACKAGE_MANAGERS, release)),
// We only want to react on the change of the Version
// eslint-disable-next-line @eslint-react/exhaustive-deps
[release.version]
Expand Down
9 changes: 7 additions & 2 deletions apps/site/components/Downloads/Release/PlatformDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import { useEffect, use, useMemo, useState } from 'react';

import useClientContext from '#site/hooks/useClientContext';
import { ReleaseContext } from '#site/providers/releaseProvider';
import { PLATFORMS, nextItem, parseCompat } from '#site/util/download';
import {
availableItems,
PLATFORMS,
nextItem,
parseCompat,
} from '#site/util/download';
import { getUserPlatform } from '#site/util/userAgent';

import type { Platform } from '#site/types/userAgent';
Expand Down Expand Up @@ -48,7 +53,7 @@ const PlatformDropdown: FC = () => {
// We only want to parse the compatibility when the OS has finished loading
// Otherwise, we would be parsing the compatibility of an empty array
release.os !== 'LOADING'
? parseCompat(PLATFORMS[release.os], release)
? availableItems(parseCompat(PLATFORMS[release.os], release))
: [],
// We only want to react on the change of the OS, Platform, and Version
// eslint-disable-next-line @eslint-react/exhaustive-deps
Expand Down
28 changes: 28 additions & 0 deletions apps/site/util/__tests__/download.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { describe, it } from 'node:test';

import {
parseCompat,
availableItems,
nextItem,
OPERATING_SYSTEMS,
INSTALL_METHODS,
Expand Down Expand Up @@ -145,6 +146,19 @@ describe('nextItem', () => {
});
});

describe('availableItems', () => {
it('should filter disabled items out of dropdown options', () => {
const items = [
{ value: 'invalid', disabled: true },
{ value: 'valid', disabled: false },
];

assert.deepEqual(availableItems(items), [
{ value: 'valid', disabled: false },
]);
});
});

describe('INSTALL_METHODS', () => {
it('should create icons only when an icon is configured', () => {
const nvmMethod = INSTALL_METHODS.find(method => method.value === 'NVM');
Expand All @@ -153,4 +167,18 @@ describe('INSTALL_METHODS', () => {
assert.ok(nvmMethod?.iconImage);
assert.equal(asdfMethod?.iconImage, undefined);
});

it('should recommend nvm on AIX', () => {
const aixMethods = availableItems(
parseCompat(INSTALL_METHODS, {
os: 'AIX',
installMethod: '',
platform: 'ppc64',
version: 'v24.0.0',
release: { status: 'LTS' },
})
);

assert.ok(aixMethods.some(method => method.value === 'NVM'));
});
});
2 changes: 1 addition & 1 deletion apps/site/util/download/constants.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
"icon": "NVM",
"name": "nvm",
"compatibility": {
"os": ["MAC", "LINUX", "OTHER"]
"os": ["MAC", "LINUX", "AIX", "OTHER"]
},
"recommended": true,
"url": "https://github.com/nvm-sh/nvm",
Expand Down
7 changes: 7 additions & 0 deletions apps/site/util/download/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ export const parseCompat = <
}));
};

export const availableItems = <
K extends string,
T extends DownloadDropdownItem<K>,
>(
items: Array<T>
): Array<T> => items.filter(({ disabled }) => !disabled);

/**
* Creates an icon element for a component
*/
Expand Down