diff --git a/packages/manager/.changeset/pr-9943-upcoming-features-1701209599920.md b/packages/manager/.changeset/pr-9943-upcoming-features-1701209599920.md new file mode 100644 index 00000000000..20be155cf30 --- /dev/null +++ b/packages/manager/.changeset/pr-9943-upcoming-features-1701209599920.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Add logic to prevent new customers in regions to various user flows for DC Get Well initiative pt1 ([#9943](https://github.com/linode/manager/pull/9943)) diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode.spec.ts index 6d037eb7bff..315e40a73e5 100644 --- a/packages/manager/cypress/e2e/core/linodes/create-linode.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/create-linode.spec.ts @@ -33,20 +33,24 @@ import { makeFeatureFlagData } from 'support/util/feature-flags'; const mockRegions: Region[] = [ regionFactory.build({ + capabilities: ['Linodes'], country: 'uk', id: 'eu-west', label: 'London, UK', }), regionFactory.build({ + capabilities: ['Linodes'], country: 'sg', id: 'ap-south', label: 'Singapore, SG', }), regionFactory.build({ + capabilities: ['Linodes'], id: 'us-east', label: 'Newark, NJ', }), regionFactory.build({ + capabilities: ['Linodes'], id: 'us-central', label: 'Dallas, TX', }), diff --git a/packages/manager/cypress/e2e/core/objectStorage/enable-object-storage.spec.ts b/packages/manager/cypress/e2e/core/objectStorage/enable-object-storage.spec.ts index e8de3c04f94..8787747900f 100644 --- a/packages/manager/cypress/e2e/core/objectStorage/enable-object-storage.spec.ts +++ b/packages/manager/cypress/e2e/core/objectStorage/enable-object-storage.spec.ts @@ -72,9 +72,21 @@ describe('Object Storage enrollment', () => { }; const mockRegions: Region[] = [ - regionFactory.build({ label: 'Newark, NJ', id: 'us-east' }), - regionFactory.build({ label: 'Sao Paulo, BR', id: 'br-gru' }), - regionFactory.build({ label: 'Jakarta, ID', id: 'id-cgk' }), + regionFactory.build({ + capabilities: ['Object Storage'], + label: 'Newark, NJ', + id: 'us-east', + }), + regionFactory.build({ + capabilities: ['Object Storage'], + label: 'Sao Paulo, BR', + id: 'br-gru', + }), + regionFactory.build({ + capabilities: ['Object Storage'], + label: 'Jakarta, ID', + id: 'id-cgk', + }), ]; // Clusters with special pricing are currently hardcoded rather than diff --git a/packages/manager/src/components/RegionSelect/RegionSelect.tsx b/packages/manager/src/components/RegionSelect/RegionSelect.tsx index ff7d01d38ad..ed2e3d01b24 100644 --- a/packages/manager/src/components/RegionSelect/RegionSelect.tsx +++ b/packages/manager/src/components/RegionSelect/RegionSelect.tsx @@ -100,12 +100,17 @@ export const RegionSelect = React.memo((props: RegionSelectProps) => { Boolean(flags.dcGetWell) && Boolean(option.unavailable); return ( - For more information about regional availability, please see - our new status page. + There may be limited capacity in this region.{' '} + + Learn more + + . ) : ( '' @@ -133,7 +138,7 @@ export const RegionSelect = React.memo((props: RegionSelectProps) => { - {option.label} {isDisabledMenuItem && ' (Not available)'} + {option.label} {selected && } diff --git a/packages/manager/src/components/RegionSelect/RegionSelect.utils.test.tsx b/packages/manager/src/components/RegionSelect/RegionSelect.utils.test.tsx index 70f97abb9c4..cf2e8fdefe6 100644 --- a/packages/manager/src/components/RegionSelect/RegionSelect.utils.test.tsx +++ b/packages/manager/src/components/RegionSelect/RegionSelect.utils.test.tsx @@ -18,22 +18,49 @@ const accountAvailabilityData = [ const regions: Region[] = [ regionFactory.build({ + capabilities: ['Linodes'], country: 'us', id: 'us-1', label: 'US Location', }), regionFactory.build({ + capabilities: ['Linodes'], country: 'ca', id: 'ca-1', label: 'CA Location', }), regionFactory.build({ + capabilities: ['Linodes'], country: 'jp', id: 'jp-1', label: 'JP Location', }), ]; +const expectedRegions: RegionSelectOption[] = [ + { + data: { country: 'ca', region: 'North America' }, + label: 'CA Location (ca-1)', + unavailable: false, + value: 'ca-1', + }, + { + data: { + country: 'us', + region: 'North America', + }, + label: 'US Location (us-1)', + unavailable: false, + value: 'us-1', + }, + { + data: { country: 'jp', region: 'Asia' }, + label: 'JP Location (jp-1)', + unavailable: false, + value: 'jp-1', + }, +]; + describe('getRegionOptions', () => { it('should return an empty array if no regions are provided', () => { const regions: Region[] = []; @@ -53,33 +80,27 @@ describe('getRegionOptions', () => { regions, }); - // Expected result - const expected: RegionSelectOption[] = [ - { - data: { country: 'ca', region: 'North America' }, - label: 'CA Location (ca-1)', - unavailable: false, - value: 'ca-1', - }, - { - data: { - country: 'us', - region: 'North America', - }, - label: 'US Location (us-1)', - unavailable: false, - value: 'us-1', - }, + expect(result).toEqual(expectedRegions); + }); - { - data: { country: 'jp', region: 'Asia' }, - label: 'JP Location (jp-1)', - unavailable: false, - value: 'jp-1', - }, + it('should filter out regions that do not have the currentCapability if currentCapability is provided', () => { + const regionsToFilter: Region[] = [ + ...regions, + regionFactory.build({ + capabilities: ['Object Storage'], + country: 'pe', + id: 'peru-1', + label: 'Peru Location', + }), ]; - expect(result).toEqual(expected); + const result: RegionSelectOption[] = getRegionOptions({ + accountAvailabilityData, + currentCapability: 'Linodes', + regions: regionsToFilter, + }); + + expect(result).toEqual(expectedRegions); }); }); diff --git a/packages/manager/src/components/RegionSelect/RegionSelect.utils.ts b/packages/manager/src/components/RegionSelect/RegionSelect.utils.ts index 605213f1c22..a5fb1769f4a 100644 --- a/packages/manager/src/components/RegionSelect/RegionSelect.utils.ts +++ b/packages/manager/src/components/RegionSelect/RegionSelect.utils.ts @@ -26,7 +26,13 @@ export const getRegionOptions = ({ currentCapability, regions, }: GetRegionOptions): RegionSelectOption[] => { - return regions + const filteredRegions = currentCapability + ? regions.filter((region) => + region.capabilities.includes(currentCapability) + ) + : regions; + + return filteredRegions .map((region: Region) => { const group = getRegionCountryGroup(region); diff --git a/packages/manager/src/components/SelectRegionPanel/SelectRegionPanel.tsx b/packages/manager/src/components/SelectRegionPanel/SelectRegionPanel.tsx index 1389eb7b750..6e507165703 100644 --- a/packages/manager/src/components/SelectRegionPanel/SelectRegionPanel.tsx +++ b/packages/manager/src/components/SelectRegionPanel/SelectRegionPanel.tsx @@ -1,4 +1,4 @@ -import { Region } from '@linode/api-v4/lib/regions'; +import { Capabilities, Region } from '@linode/api-v4/lib/regions'; import { useTheme } from '@mui/material'; import * as React from 'react'; import { useLocation } from 'react-router-dom'; @@ -25,6 +25,7 @@ import { DynamicPriceNotice } from '../DynamicPriceNotice'; import { Link } from '../Link'; interface SelectRegionPanelProps { + currentCapability?: Capabilities | undefined; disabled?: boolean; error?: string; handleSelection: (id: string) => void; @@ -39,6 +40,7 @@ interface SelectRegionPanelProps { export const SelectRegionPanel = (props: SelectRegionPanelProps) => { const { + currentCapability, disabled, error, handleSelection, @@ -134,6 +136,7 @@ export const SelectRegionPanel = (props: SelectRegionPanelProps) => { ) : null} { isLoading: regionsLoading, } = useRegionsQuery(); - const regionsThatSupportDbaas = regionsWithFeature( - regionsData ?? [], - 'Managed Databases' - ); - const { data: engines, error: enginesError, @@ -507,8 +501,9 @@ const DatabaseCreate = () => { handleSelection={(selected: string) => setFieldValue('region', selected) } + currentCapability="Managed Databases" errorText={errors.region} - regions={regionsThatSupportDbaas} + regions={regionsData} selectedId={values.region} /> diff --git a/packages/manager/src/features/Linodes/LinodesCreate/LinodeCreate.tsx b/packages/manager/src/features/Linodes/LinodesCreate/LinodeCreate.tsx index c91612a0180..78c62a58cfa 100644 --- a/packages/manager/src/features/Linodes/LinodesCreate/LinodeCreate.tsx +++ b/packages/manager/src/features/Linodes/LinodesCreate/LinodeCreate.tsx @@ -545,6 +545,7 @@ export class LinodeCreate extends React.PureComponent< {this.props.createType !== 'fromBackup' && ( { textFieldProps={{ helperText, }} + currentCapability="Linodes" errorText={errorText} handleSelection={handleSelectRegion} label="New Region" diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancerCreate.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancerCreate.tsx index d888fc149fa..d0b02bc6a13 100644 --- a/packages/manager/src/features/NodeBalancers/NodeBalancerCreate.tsx +++ b/packages/manager/src/features/NodeBalancers/NodeBalancerCreate.tsx @@ -479,6 +479,7 @@ const NodeBalancerCreate = () => { /> = (props) => { return ( { setFieldValue('region', value); setFieldValue('linode_id', null); }} - regions={ - regions?.filter((eachRegion) => - eachRegion.capabilities.some((eachCape) => - eachCape.match(/block/i) - ) - ) ?? [] - } + currentCapability="Block Storage" disabled={doesNotHavePermission} errorText={touched.region ? errors.region : undefined} isClearable label="Region" onBlur={handleBlur} + regions={regions ?? []} selectedId={values.region} width={400} /> diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index fcc81753e6a..ef9ca6d7023 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -1020,11 +1020,11 @@ export const handlers = [ rest.get('*/account/availability', (req, res, ctx) => { const newarkStorage = accountAvailabilityFactory.build({ id: 'us-east-0', - unavailable: ['Block Storage'], + unavailable: ['Object Storage'], }); const atlanta = accountAvailabilityFactory.build({ id: 'us-southeast', - unavailable: ['Block Storage'], + unavailable: ['Block Storage', 'Managed Databases'], }); const singapore = accountAvailabilityFactory.build({ id: 'ap-south',