Skip to content
Merged
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
@@ -0,0 +1,5 @@
---
"@linode/api-v4": Tech Stories
---

Clean up unused VPC IPv6 Large Prefixes tag ([#13245](https://github.com/linode/manager/pull/13245))
1 change: 0 additions & 1 deletion packages/api-v4/src/account/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ export const accountCapabilities = [
'Vlans',
'VPCs',
'VPC Dual Stack',
'VPC IPv6 Large Prefixes',
] as const;

export type AccountCapability = (typeof accountCapabilities)[number];
Expand Down
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-13245-fixed-1767723908908.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Fixed
---

Hide dual stack option if no IPv6 prefixes available in create VPC flow ([#13245](https://github.com/linode/manager/pull/13245))
1 change: 1 addition & 0 deletions packages/manager/src/factories/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const accountFactory = Factory.Sync.makeFactory<Account>({
'Placement Group',
'Vlans',
'Kubernetes Enterprise',
'VPC Dual Stack',
],
city: 'Philadelphia',
company: Factory.each((i) => `company-${i}`),
Expand Down
1 change: 1 addition & 0 deletions packages/manager/src/factories/userAccountPermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import type { PermissionType } from '@linode/api-v4';
export const userAccountPermissionsFactory: PermissionType[] = [
'create_linode',
'create_firewall',
'create_vpc',
];
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,11 @@ describe('VPC Top Section form content', () => {

const NetworkingIPStackRadios = screen.getAllByRole('radio');
expect(NetworkingIPStackRadios[0]).toBeChecked(); // IPv4
expect(NetworkingIPStackRadios[1]).not.toBeChecked(); // Dual Stack
});

it('renders VPC IPv6 Prefix Length options with /52 selected if the selected region has multiple prefix lengths available', async () => {
const account = accountFactory.build({
capabilities: ['VPC Dual Stack', 'VPC IPv6 Large Prefixes'],
capabilities: ['VPC Dual Stack'],
});

server.use(http.get('*/account', () => HttpResponse.json(account)));
Expand Down Expand Up @@ -148,7 +147,7 @@ describe('VPC Top Section form content', () => {
expect(IPv6CIDRRadios[3]).toBeChecked(); // /52
});

it('does not render VPC IPv6 Prefix Length options if there are none available or only /52 available', async () => {
it('does not show dual stack option and does not render VPC IPv6 Prefix Length options if there are none available', async () => {
const account = accountFactory.build({
capabilities: ['VPC Dual Stack'],
});
Expand All @@ -160,7 +159,7 @@ describe('VPC Top Section form content', () => {
makeResourcePage([
regionVPCAvailabilityFactory.build({
region: 'us-east',
available_ipv6_prefix_lengths: [52],
available_ipv6_prefix_lengths: [],
}),
])
)
Expand Down Expand Up @@ -189,10 +188,10 @@ describe('VPC Top Section form content', () => {
expect(screen.getByText('IP Stack')).toBeVisible();
});

const NetworkingIPStackRadios = screen.getAllByRole('radio');
await userEvent.click(NetworkingIPStackRadios[1]);
expect(NetworkingIPStackRadios[0]).not.toBeChecked(); // IPv4
expect(NetworkingIPStackRadios[1]).toBeChecked(); // Dual Stack
expect(screen.getByText('IPv4')).toBeVisible(); // IPv4
expect(
screen.queryByText('IPv4 + IPv6 (Dual Stack)')
).not.toBeInTheDocument(); // Dual Stack

expect(
screen.queryByText('VPC IPv6 Prefix Length')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,61 +205,64 @@ export const VPCTopSectionContent = (props: Props) => {
sxCardBase={{ gap: 0 }}
sxCardBaseIcon={{ svg: { fontSize: '20px' } }}
/>
<SelectionCard
checked={isDualStackSelected}
disabled={!permissions?.create_vpc}
gridSize={{
md: isDrawer ? 12 : 3,
sm: 12,
xs: 12,
}}
heading="IPv4 + IPv6 (Dual Stack)"
onClick={() => {
field.onChange([
{
range: '/52',
},
]);
subnets?.forEach((subnet, idx) =>
update(idx, {
...subnet,
ipv6: subnet.ipv6 ?? [{ range: '/56' }],
})
);
}}
renderIcon={() => (
<Radio
{availableRegionIPv6PrefixLengths &&
availableRegionIPv6PrefixLengths.length > 0 && (
<SelectionCard
checked={isDualStackSelected}
disabled={!permissions?.create_vpc}
/>
)}
renderVariant={() => (
<TooltipIcon
status="info"
sxTooltipIcon={{
padding: '8px',
gridSize={{
md: isDrawer ? 12 : 3,
sm: 12,
xs: 12,
}}
text={
<Stack spacing={2}>
<Typography>
The VPC supports both IPv4 and IPv6 addresses.
</Typography>
<Typography>
For IPv4, {RFC1918HelperText}
</Typography>
<Typography>
For IPv6, the VPC is assigned an IPv6 prefix
length of <Code>/52</Code> by default.
</Typography>
</Stack>
}
width={250}
heading="IPv4 + IPv6 (Dual Stack)"
onClick={() => {
field.onChange([
{
range: '/52',
},
]);
subnets?.forEach((subnet, idx) =>
update(idx, {
...subnet,
ipv6: subnet.ipv6 ?? [{ range: '/56' }],
})
);
}}
renderIcon={() => (
<Radio
checked={isDualStackSelected}
disabled={!permissions?.create_vpc}
/>
)}
renderVariant={() => (
<TooltipIcon
status="info"
sxTooltipIcon={{
padding: '8px',
}}
text={
<Stack spacing={2}>
<Typography>
The VPC supports both IPv4 and IPv6 addresses.
</Typography>
<Typography>
For IPv4, {RFC1918HelperText}
</Typography>
<Typography>
For IPv6, the VPC is assigned an IPv6 prefix
length of <Code>/52</Code> by default.
</Typography>
</Stack>
}
width={250}
/>
)}
subheadings={[]}
sxCardBase={{ gap: 0 }}
sxCardBaseIcon={{ svg: { fontSize: '20px' } }}
/>
)}
subheadings={[]}
sxCardBase={{ gap: 0 }}
sxCardBaseIcon={{ svg: { fontSize: '20px' } }}
/>
</Grid>
</RadioGroup>
)}
Expand Down
7 changes: 0 additions & 7 deletions packages/manager/src/hooks/useVPCDualStack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ export const useVPCDualStack = (ipv6?: VPCIPv6[]) => {
account?.capabilities ?? []
);

const isEnterpriseCustomer = isFeatureEnabledV2(
'VPC IPv6 Large Prefixes',
Boolean(flags.vpcIpv6),
account?.capabilities ?? []
);

const shouldDisplayIPv6 = isDualStackEnabled && isDualStackSelected;
const recommendedIPv6 = shouldDisplayIPv6
? [
Expand All @@ -35,7 +29,6 @@ export const useVPCDualStack = (ipv6?: VPCIPv6[]) => {
return {
isDualStackEnabled,
isDualStackSelected,
isEnterpriseCustomer,
shouldDisplayIPv6,
recommendedIPv6,
};
Expand Down
24 changes: 24 additions & 0 deletions packages/manager/src/mocks/serverHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,30 @@
const subnet = subnetFactory.build({ ...(body as any) });
return HttpResponse.json(subnet);
}),
http.get('*/v4beta/regions/vpc-availability', () => {

Check warning on line 524 in packages/manager/src/mocks/serverHandlers.ts

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Unexpected any. Specify a different type. Raw Output: {"ruleId":"@typescript-eslint/no-explicit-any","severity":1,"message":"Unexpected any. Specify a different type.","line":524,"column":54,"nodeType":"TSAnyKeyword","messageId":"unexpectedAny","endLine":524,"endColumn":57,"suggestions":[{"messageId":"suggestUnknown","fix":{"range":[15547,15550],"text":"unknown"},"desc":"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct."},{"messageId":"suggestNever","fix":{"range":[15547,15550],"text":"never"},"desc":"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of."}]}
return HttpResponse.json({
data: [
{
region: 'ap-west',
available: true,
available_ipv6_prefix_lengths: [],
},
{
region: 'in-maa',
available: true,
available_ipv6_prefix_lengths: [52],
},
{
region: 'us-southeast',
available: true,
available_ipv6_prefix_lengths: [48, 52],
},

Check warning on line 541 in packages/manager/src/mocks/serverHandlers.ts

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 Define a constant instead of duplicating this literal 4 times. Raw Output: {"ruleId":"sonarjs/no-duplicate-string","severity":1,"message":"Define a constant instead of duplicating this literal 4 times.","line":541,"column":19,"nodeType":"Literal","endLine":541,"endColumn":33}
],
page: 1,
pages: 1,
results: 3,
});
}),
];

const iam = [
Expand Down