Skip to content

Commit de26501

Browse files
committed
feat: code review and iteration on logic
1 parent 5b76dc5 commit de26501

35 files changed

+492
-492
lines changed

apps/site/components/Common/Select/index.stories.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { Meta as MetaObj, StoryObj } from '@storybook/react';
22

33
import Select from '@/components/Common/Select';
4-
import AIX from '@/components/Icons/Platform/AIX';
5-
import Apple from '@/components/Icons/Platform/Apple';
6-
import Linux from '@/components/Icons/Platform/Linux';
7-
import Microsoft from '@/components/Icons/Platform/Microsoft';
4+
import AIX from '@/components/Icons/OperationalSystem/AIX';
5+
import Apple from '@/components/Icons/OperationalSystem/Apple';
6+
import Linux from '@/components/Icons/OperationalSystem/Linux';
7+
import Microsoft from '@/components/Icons/OperationalSystem/Microsoft';
88

99
type Story = StoryObj<typeof Select>;
1010
type Meta = MetaObj<typeof Select>;

apps/site/components/Common/Select/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as ScrollPrimitive from '@radix-ui/react-scroll-area';
55
import * as SelectPrimitive from '@radix-ui/react-select';
66
import classNames from 'classnames';
77
import { useEffect, useId, useMemo, useState } from 'react';
8-
import type { FC } from 'react';
8+
import type { FC, ReactElement } from 'react';
99

1010
import Skeleton from '@/components/Common/Skeleton';
1111
import type { FormattedMessage } from '@/types';
@@ -15,7 +15,7 @@ import styles from './index.module.css';
1515
type SelectValue = {
1616
label: FormattedMessage;
1717
value: string;
18-
iconImage?: React.ReactNode;
18+
iconImage?: ReactElement;
1919
disabled?: boolean;
2020
};
2121

apps/site/components/Common/Skeleton/index.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@ import { isValidElement } from 'react';
33

44
import styles from './index.module.css';
55

6-
type SkeletonProps = { loading?: boolean };
6+
type SkeletonProps = { hide?: boolean; loading?: boolean };
77

88
const Skeleton: FC<PropsWithChildren<SkeletonProps>> = ({
99
children,
10+
hide = false,
1011
loading = true,
1112
}) => {
13+
if (!loading && hide) {
14+
return null;
15+
}
16+
1217
if (!loading) {
1318
return children;
1419
}

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

Lines changed: 29 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,106 +3,70 @@
33
import { useTranslations } from 'next-intl';
44
import type { FC } from 'react';
55
import { useEffect, useContext, useMemo } from 'react';
6-
import semVer from 'semver';
76

87
import Select from '@/components/Common/Select';
98
import { useClientContext } from '@/hooks';
109
import { ReleaseContext } from '@/providers/releaseProvider';
11-
import { bitnessItems, formatDropdownItems } from '@/util/downloadUtils';
10+
import { ARCHITECTURES, parseCompatibility } from '@/util/downloadUtils';
1211
import { getUserBitnessByArchitecture } from '@/util/getUserBitnessByArchitecture';
1312

1413
const parseNumericBitness = (bitness: string) =>
1514
/^\d+$/.test(bitness) ? Number(bitness) : bitness;
1615

1716
const BitnessDropdown: FC = () => {
18-
const { bitness: userBitness, architecture: userArchitecture } =
19-
useClientContext();
20-
const { bitness, os, release, setBitness } = useContext(ReleaseContext);
17+
const { architecture, bitness } = useClientContext();
18+
19+
const release = useContext(ReleaseContext);
2120
const t = useTranslations();
2221

2322
useEffect(() => {
24-
setBitness(getUserBitnessByArchitecture(userArchitecture, userBitness));
25-
// we shouldn't update the effect on setter state change
23+
release.setBitness(getUserBitnessByArchitecture(architecture, bitness));
24+
// Only react on the change of the Client Context Architecture and Bitness
2625
// eslint-disable-next-line react-hooks/exhaustive-deps
27-
}, [userArchitecture, userBitness]);
28-
29-
// @TODO: We should have a proper utility that gives
30-
// disabled OSs, Platforms, based on specific criteria
31-
// this can be an optimisation for the future
32-
// to remove this logic from this component
33-
const disabledItems = useMemo(() => {
34-
const disabledItems = [];
26+
}, [architecture, bitness]);
3527

36-
if (os === 'WIN' && semVer.satisfies(release.version, '< 19.9.0')) {
37-
disabledItems.push('arm64');
38-
}
39-
40-
if (os === 'WIN' && semVer.satisfies(release.version, '>= 23.0.0')) {
41-
disabledItems.push('86');
42-
}
43-
44-
if (os === 'LINUX' && semVer.satisfies(release.version, '< 4.0.0')) {
45-
disabledItems.push('arm64', 'armv7l');
46-
}
47-
48-
if (os === 'LINUX' && semVer.satisfies(release.version, '< 4.4.0')) {
49-
disabledItems.push('ppc64le');
50-
}
51-
52-
if (os === 'LINUX' && semVer.satisfies(release.version, '< 6.6.0')) {
53-
disabledItems.push('s390x');
54-
}
55-
56-
if (os === 'AIX' && semVer.satisfies(release.version, '< 6.7.0')) {
57-
disabledItems.push('ppc64');
58-
}
59-
60-
return disabledItems;
61-
}, [os, release.version]);
28+
// We parse the compatibility of the dropdown items
29+
const parsedArchitectures = useMemo(
30+
() => parseCompatibility(ARCHITECTURES[release.os], release),
31+
// We only want to react on the change of the OS, Bitness, and Version
32+
// eslint-disable-next-line react-hooks/exhaustive-deps
33+
[release.os, release.bitness, release.version]
34+
);
6235

63-
// @TODO: We should have a proper utility that gives
64-
// disabled OSs, Platforms, based on specific criteria
65-
// this can be an optimisation for the future
66-
// to remove this logic from this component
6736
useEffect(() => {
68-
const mappedBitnessValues = bitnessItems[os].map(({ value }) => value);
37+
const currentBitnessItem = parsedArchitectures.find(
38+
({ value }) => value === String(release.bitness)
39+
);
6940

7041
const currentBitnessExcluded =
71-
// Different OSs support different Bitnessess, hence we should also check
72-
// if besides the current bitness not being supported for a given release version
73-
// we also should check if it is not supported by the OS
74-
disabledItems.includes(String(bitness)) ||
75-
!mappedBitnessValues.includes(String(bitness));
42+
!currentBitnessItem || currentBitnessItem.disabled;
7643

77-
const nonExcludedBitness = mappedBitnessValues.find(
78-
bitness => !disabledItems.includes(bitness)
44+
const nonExcludedBitness = parsedArchitectures.find(
45+
({ disabled }) => !disabled
7946
);
8047

8148
if (currentBitnessExcluded && nonExcludedBitness) {
8249
// We set it as a Number for cases where it is 64 or 86 otherwise we are
8350
// setting it as a string (ARMv7, ARMv6, etc.)
8451
const numericBitness = Number(nonExcludedBitness);
8552

86-
setBitness(
87-
numericBitness.toString() === nonExcludedBitness
53+
release.setBitness(
54+
numericBitness.toString() === nonExcludedBitness.value
8855
? numericBitness
89-
: nonExcludedBitness
56+
: nonExcludedBitness.value
9057
);
9158
}
92-
// we shouldn't react when "actions" change
59+
// Only react on the change of the current OS and Version
9360
// eslint-disable-next-line react-hooks/exhaustive-deps
94-
}, [os, disabledItems]);
61+
}, [release.os, release.version]);
9562

9663
return (
9764
<Select
98-
values={formatDropdownItems({
99-
items: bitnessItems[os],
100-
disabledItems,
101-
})}
102-
loading={os === 'LOADING'}
65+
values={parsedArchitectures}
66+
loading={release.os === 'LOADING'}
10367
ariaLabel={t('layouts.download.dropdown.bitness')}
104-
defaultValue={String(bitness)}
105-
onChange={bitness => setBitness(parseNumericBitness(bitness))}
68+
defaultValue={String(release.bitness)}
69+
onChange={bitness => release.setBitness(parseNumericBitness(bitness))}
10670
className="min-w-28"
10771
inline={true}
10872
/>

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

Lines changed: 32 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,60 @@
11
'use client';
22

33
import { useTranslations } from 'next-intl';
4-
import { useContext, useEffect } from 'react';
4+
import { useContext, useEffect, useMemo } from 'react';
55
import type { FC } from 'react';
66

77
import Select from '@/components/Common/Select';
8-
import AIX from '@/components/Icons/Platform/AIX';
9-
import Apple from '@/components/Icons/Platform/Apple';
10-
import Linux from '@/components/Icons/Platform/Linux';
11-
import Microsoft from '@/components/Icons/Platform/Microsoft';
128
import { useClientContext } from '@/hooks';
139
import { ReleaseContext } from '@/providers/releaseProvider';
1410
import type { UserOS } from '@/types/userOS';
15-
import {
16-
formatDropdownItems,
17-
operatingSystemItems,
18-
} from '@/util/downloadUtils';
11+
import { OPERATING_SYSTEMS, parseCompatibility } from '@/util/downloadUtils';
1912

2013
type OperatingSystemDropdownProps = { exclude?: Array<UserOS> };
2114

22-
const OperatingSystemDropdown: FC<OperatingSystemDropdownProps> = ({
23-
exclude = [],
24-
}) => {
25-
const { os: userOS } = useClientContext();
26-
const { os, setOS } = useContext(ReleaseContext);
15+
const OperatingSystemDropdown: FC<OperatingSystemDropdownProps> = () => {
16+
const { os } = useClientContext();
17+
const release = useContext(ReleaseContext);
2718
const t = useTranslations();
2819

20+
// Reacts on Client Context change of OS
2921
// eslint-disable-next-line react-hooks/exhaustive-deps
30-
useEffect(() => setOS(userOS), [userOS]);
22+
useEffect(() => release.setOS(os), [os]);
23+
24+
// We parse the compatibility of the dropdown items
25+
const parsedOperatingSystems = useMemo(
26+
() => parseCompatibility(OPERATING_SYSTEMS, release),
27+
// We only want to react on the change of the OS, Bitness, and Version
28+
// eslint-disable-next-line react-hooks/exhaustive-deps
29+
[release.os, release.bitness, release.version]
30+
);
3131

32-
// @TODO: We should have a proper utility that gives
33-
// disabled OSs, Platforms, based on specific criteria
34-
// this can be an optimisation for the future
35-
// to remove this logic from this component
3632
useEffect(() => {
37-
const currentOSExcluded = exclude.includes(os);
33+
const currentOperatingSystem = parsedOperatingSystems.find(
34+
({ value }) => value === release.os
35+
);
36+
37+
const currentPlatformExcluded =
38+
!currentOperatingSystem || currentOperatingSystem.disabled;
3839

39-
const nonExcludedOS = operatingSystemItems
40-
.map(({ value }) => value)
41-
.find(os => !exclude.includes(os));
40+
const nonExcludedOperatingSystem = parsedOperatingSystems.find(
41+
({ disabled }) => !disabled
42+
);
4243

43-
if (currentOSExcluded && nonExcludedOS) {
44-
setOS(nonExcludedOS);
44+
if (currentPlatformExcluded && nonExcludedOperatingSystem) {
45+
release.setOS(nonExcludedOperatingSystem.value);
4546
}
46-
// we shouldn't react when "actions" change
47+
// Only react on the change of the current Platform
4748
// eslint-disable-next-line react-hooks/exhaustive-deps
48-
}, [os, exclude]);
49+
}, [release.platform]);
4950

5051
return (
5152
<Select
52-
values={formatDropdownItems({
53-
items: operatingSystemItems,
54-
disabledItems: exclude,
55-
icons: {
56-
WIN: <Microsoft width={16} height={16} />,
57-
MAC: <Apple width={16} height={16} />,
58-
LINUX: <Linux width={16} height={16} />,
59-
AIX: <AIX width={16} height={16} />,
60-
},
61-
})}
62-
defaultValue={os}
63-
loading={os === 'LOADING'}
53+
values={parsedOperatingSystems}
54+
defaultValue={release.os}
55+
loading={release.os === 'LOADING'}
6456
ariaLabel={t('layouts.download.dropdown.os')}
65-
onChange={value => setOS(value as UserOS)}
57+
onChange={value => release.setOS(value as UserOS)}
6658
className="min-w-[8.5rem]"
6759
inline={true}
6860
/>

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

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,21 @@ import { useContext } from 'react';
55
import type { FC } from 'react';
66

77
import Select from '@/components/Common/Select';
8-
import NPM from '@/components/Icons/PackageManager/Npm';
9-
import PNPM from '@/components/Icons/PackageManager/Pnpm';
10-
import YARN from '@/components/Icons/PackageManager/Yarn';
118
import { ReleaseContext } from '@/providers/releaseProvider';
129
import type { PackageManager } from '@/types/release';
13-
import { formatDropdownItems, packageManagerItems } from '@/util/downloadUtils';
10+
import { PACKAGE_MANAGERS } from '@/util/downloadUtils';
1411

1512
const PackageManagerDropdown: FC = () => {
16-
const { os, packageManager, setPackageManager } = useContext(ReleaseContext);
13+
const release = useContext(ReleaseContext);
1714
const t = useTranslations();
1815

1916
return (
2017
<Select
21-
values={formatDropdownItems({
22-
items: packageManagerItems,
23-
icons: {
24-
NPM: <NPM width={16} height={16} />,
25-
YARN: <YARN width={16} height={16} />,
26-
PNPM: <PNPM width={16} height={16} />,
27-
},
28-
})}
29-
defaultValue={packageManager}
30-
loading={os === 'LOADING'}
18+
values={PACKAGE_MANAGERS}
19+
defaultValue={release.packageManager}
20+
loading={release.os === 'LOADING' || release.platform === ''}
3121
ariaLabel={t('layouts.download.dropdown.packageManager')}
32-
onChange={manager => setPackageManager(manager as PackageManager)}
22+
onChange={manager => release.setPackageManager(manager as PackageManager)}
3323
className="min-w-28"
3424
inline={true}
3525
/>

0 commit comments

Comments
 (0)