Skip to content

Commit

Permalink
upcoming: [M3-7978] - RegionSelect disabled option API updates (linod…
Browse files Browse the repository at this point in the history
…e#10373)

* save progress

* save progress

* save progress

* Save progress

* fix tests

* code cleanup

* Improve coverage

* moar cleanup

* Added changeset: RegionSelect disabled option API updates

* Address feedback

* Address feedback 2

* fix test
  • Loading branch information
abailly-akamai authored and mjac0bs committed Apr 18, 2024
1 parent a4f1d78 commit 233a134
Show file tree
Hide file tree
Showing 12 changed files with 192 additions and 100 deletions.
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-10373-changed-1712939610447.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Changed
---

RegionSelect disabled option API updates ([#10373](https://github.com/linode/manager/pull/10373))
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ export const RegionMultiSelect = React.memo((props: RegionMultiSelectProps) => {
<>
<StyledAutocompleteContainer sx={{ width }}>
<Autocomplete
getOptionDisabled={(option: RegionSelectOption) =>
Boolean(option.disabledProps?.disabled)
}
groupBy={(option: RegionSelectOption) => {
return option?.data?.region;
}}
Expand Down Expand Up @@ -134,7 +137,6 @@ export const RegionMultiSelect = React.memo((props: RegionMultiSelectProps) => {
disableClearable={!isClearable}
disabled={disabled}
errorText={errorText}
getOptionDisabled={(option: RegionSelectOption) => option.unavailable}
label={label ?? 'Regions'}
loading={accountAvailabilityLoading}
multiple
Expand Down
60 changes: 22 additions & 38 deletions packages/manager/src/components/RegionSelect/RegionOption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import React from 'react';
import EdgeServer from 'src/assets/icons/entityIcons/edge-server.svg';
import { Box } from 'src/components/Box';
import { Flag } from 'src/components/Flag';
import { Link } from 'src/components/Link';
import { Tooltip } from 'src/components/Tooltip';
import { TooltipIcon } from 'src/components/TooltipIcon';

Expand All @@ -31,73 +30,58 @@ export const RegionOption = ({
props,
selected,
}: Props) => {
const isDisabledMenuItem = option.unavailable;
const { className, onClick } = props;
const { data, disabledProps, label, value } = option;
const isRegionDisabled = Boolean(disabledProps?.disabled);
const isRegionDisabledReason = disabledProps?.reason;

return (
<Tooltip
PopperProps={{
sx: { '& .MuiTooltip-tooltip': { minWidth: 215 } },
sx: {
'& .MuiTooltip-tooltip': {
minWidth: disabledProps?.tooltipWidth ?? 215,
},
},
}}
title={
isDisabledMenuItem ? (
<>
There may be limited capacity in this region.{' '}
<Link to="https://www.linode.com/global-infrastructure/availability">
Learn more
</Link>
.
</>
) : (
''
)
isRegionDisabled && isRegionDisabledReason ? isRegionDisabledReason : ''
}
disableFocusListener={!isDisabledMenuItem}
disableHoverListener={!isDisabledMenuItem}
disableTouchListener={!isDisabledMenuItem}
disableFocusListener={!isRegionDisabled}
disableHoverListener={!isRegionDisabled}
disableTouchListener={!isRegionDisabled}
enterDelay={200}
enterNextDelay={200}
enterTouchDelay={200}
key={option.value}
key={value}
>
<StyledListItem
{...props}
className={
isDisabledMenuItem
? `${props.className} Mui-disabled`
: props.className
}
componentsProps={{
root: {
'data-qa-option': option.value,
'data-testid': option.value,
'data-qa-option': value,
'data-testid': value,
} as ListItemComponentsPropsOverrides,
}}
onClick={(e) =>
isDisabledMenuItem
? e.preventDefault()
: props.onClick
? props.onClick(e)
: null
isRegionDisabled ? e.preventDefault() : onClick ? onClick(e) : null
}
aria-disabled={undefined}
className={isRegionDisabled ? `${className} Mui-disabled` : className}
>
<>
<Box alignItems="center" display="flex" flexGrow={1}>
<StyledFlagContainer>
<Flag country={option.data.country} />
<Flag country={data.country} />
</StyledFlagContainer>
{option.label}
{label}
{displayEdgeServerIcon && (
<Box sx={visuallyHidden}>
&nbsp;(This region is an Edge site.)
</Box>
)}
{isDisabledMenuItem && (
<Box sx={visuallyHidden}>
Disabled option - There may be limited capacity in this region.
Learn more at
https://www.linode.com/global-infrastructure/availability.
</Box>
{isRegionDisabled && isRegionDisabledReason && (
<Box sx={visuallyHidden}>{isRegionDisabledReason}</Box>
)}
</Box>
{selected && <SelectedIcon visible={selected} />}
Expand Down
14 changes: 12 additions & 2 deletions packages/manager/src/components/RegionSelect/RegionSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const RegionSelect = React.memo((props: RegionSelectProps) => {
currentCapability,
disabled,
errorText,
handleDisabledRegion,
handleSelection,
helperText,
isClearable,
Expand Down Expand Up @@ -85,15 +86,25 @@ export const RegionSelect = React.memo((props: RegionSelectProps) => {
getRegionOptions({
accountAvailabilityData: accountAvailability,
currentCapability,
handleDisabledRegion,
regionFilter,
regions,
}),
[accountAvailability, currentCapability, regions, regionFilter]
[
accountAvailability,
currentCapability,
handleDisabledRegion,
regions,
regionFilter,
]
);

return (
<StyledAutocompleteContainer sx={{ width }}>
<Autocomplete
getOptionDisabled={(option: RegionSelectOption) =>
Boolean(option.disabledProps?.disabled)
}
isOptionEqualToValue={(
option: RegionSelectOption,
{ value }: RegionSelectOption
Expand Down Expand Up @@ -151,7 +162,6 @@ export const RegionSelect = React.memo((props: RegionSelectProps) => {
disableClearable={!isClearable}
disabled={disabled}
errorText={errorText}
getOptionDisabled={(option: RegionSelectOption) => option.unavailable}
groupBy={(option: RegionSelectOption) => option.data.region}
helperText={helperText}
label={label ?? 'Region'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ export interface RegionSelectOption {
country: Country;
region: string;
};
disabledProps?: {
disabled: boolean;
reason?: JSX.Element | string;
tooltipWidth?: number;
};
label: string;
site_type: RegionSite;
unavailable: boolean;
value: string;
}

Expand All @@ -33,6 +37,9 @@ export interface RegionSelectProps
* See `ImageUpload.tsx` for an example of a RegionSelect with an undefined `currentCapability` - there is no capability associated with Images yet.
*/
currentCapability: Capabilities | undefined;
handleDisabledRegion?: (
region: Region
) => RegionSelectOption['disabledProps'];
handleSelection: (id: string) => void;
helperText?: string;
isClearable?: boolean;
Expand Down Expand Up @@ -71,6 +78,9 @@ export interface RegionMultiSelectProps
export interface RegionOptionAvailability {
accountAvailabilityData: AccountAvailability[] | undefined;
currentCapability: Capabilities | undefined;
handleDisabledRegion?: (
region: Region
) => RegionSelectOption['disabledProps'];
}

export interface GetRegionOptions extends RegionOptionAvailability {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { accountAvailabilityFactory, regionFactory } from 'src/factories';

import {
getRegionOptionAvailability,
getRegionOptions,
getSelectedRegionById,
getSelectedRegionsByIds,
isRegionOptionUnavailable,
} from './RegionSelect.utils';

import type { RegionSelectOption } from './RegionSelect.types';
Expand Down Expand Up @@ -62,40 +62,50 @@ const expectedRegions: RegionSelectOption[] = [
country: 'us',
region: 'North America',
},
disabledProps: {
disabled: false,
},
label: 'US Location (us-1)',
site_type: 'core',
unavailable: false,
value: 'us-1',
},
{
data: { country: 'ca', region: 'North America' },
disabledProps: {
disabled: false,
},
label: 'CA Location (ca-1)',
site_type: 'core',
unavailable: false,
value: 'ca-1',
},
{
data: { country: 'jp', region: 'Asia' },
disabledProps: {
disabled: false,
},
label: 'JP Location (jp-1)',
site_type: 'core',
unavailable: false,
value: 'jp-1',
},
];

const expectedEdgeRegions = [
{
data: { country: 'us', region: 'North America' },
disabledProps: {
disabled: false,
},
label: 'Gecko Edge Test (us-edge-1)',
site_type: 'edge',
unavailable: false,
value: 'us-edge-1',
},
{
data: { country: 'us', region: 'North America' },
disabledProps: {
disabled: false,
},
label: 'Gecko Edge Test 2 (us-edge-2)',
site_type: 'edge',
unavailable: false,
value: 'us-edge-2',
},
];
Expand Down Expand Up @@ -179,6 +189,46 @@ describe('getRegionOptions', () => {

expect(result).toEqual(expectedRegionsWithEdge);
});

it('should have its option disabled if the region is unavailable', () => {
const _regions = [
...regions,
regionFactory.build({
capabilities: ['Linodes'],
country: 'us',
id: 'ap-south',
label: 'US Location 2',
}),
];

const result: RegionSelectOption[] = getRegionOptions({
accountAvailabilityData,
currentCapability: 'Linodes',
regions: _regions,
});

const unavailableRegion = result.find(
(region) => region.value === 'ap-south'
);

expect(unavailableRegion?.disabledProps?.disabled).toBe(true);
});

it('should have its option disabled if `handleDisabledRegion` is passed', () => {
const result: RegionSelectOption[] = getRegionOptions({
accountAvailabilityData,
currentCapability: 'Linodes',
handleDisabledRegion: (region) => ({
...region,
disabled: true,
}),
regions,
});

const unavailableRegion = result.find((region) => region.value === 'us-1');

expect(unavailableRegion?.disabledProps?.disabled).toBe(true);
});
});

describe('getSelectedRegionById', () => {
Expand All @@ -200,7 +250,6 @@ describe('getSelectedRegionById', () => {
},
label: 'US Location (us-1)',
site_type: 'core',
unavailable: false,
value: 'us-1',
};

Expand All @@ -223,7 +272,7 @@ describe('getSelectedRegionById', () => {

describe('getRegionOptionAvailability', () => {
it('should return true if the region is not available', () => {
const result = getRegionOptionAvailability({
const result = isRegionOptionUnavailable({
accountAvailabilityData,
currentCapability: 'Linodes',
region: regionFactory.build({
Expand All @@ -235,7 +284,7 @@ describe('getRegionOptionAvailability', () => {
});

it('should return false if the region is available', () => {
const result = getRegionOptionAvailability({
const result = isRegionOptionUnavailable({
accountAvailabilityData,
currentCapability: 'Linodes',
region: regionFactory.build({
Expand Down Expand Up @@ -266,7 +315,6 @@ describe('getSelectedRegionsByIds', () => {
},
label: 'US Location (us-1)',
site_type: 'core',
unavailable: false,
value: 'us-1',
},
{
Expand All @@ -276,7 +324,6 @@ describe('getSelectedRegionsByIds', () => {
},
label: 'CA Location (ca-1)',
site_type: 'core',
unavailable: false,
value: 'ca-1',
},
];
Expand All @@ -302,7 +349,6 @@ describe('getSelectedRegionsByIds', () => {
},
label: 'US Location (us-1)',
site_type: 'core',
unavailable: false,
value: 'us-1',
},
];
Expand Down
Loading

0 comments on commit 233a134

Please sign in to comment.