diff --git a/app/forms/vpc-router-route-common.tsx b/app/forms/vpc-router-route-common.tsx index 186667bef..5d07639ff 100644 --- a/app/forms/vpc-router-route-common.tsx +++ b/app/forms/vpc-router-route-common.tsx @@ -23,6 +23,7 @@ import { TextField } from '~/components/form/fields/TextField' import { useVpcRouterSelector } from '~/hooks/use-params' import { toComboboxItems } from '~/ui/lib/Combobox' import { Message } from '~/ui/lib/Message' +import { ALL_ISH } from '~/util/consts' import { validateIp, validateIpNet } from '~/util/ip' export type RouteFormValues = RouterRouteCreate | Required @@ -30,8 +31,6 @@ export type RouteFormValues = RouterRouteCreate | Required export const routeFormMessage = { vpcSubnetNotModifiable: 'Routes of type VPC Subnet within the system router are not modifiable', - internetGatewayTargetValue: - 'For ‘Internet gateway’ targets, the value must be ‘outbound’', // https://github.com/oxidecomputer/omicron/blob/914f5fd7d51f9b060dcc0382a30b607e25df49b2/nexus/src/app/vpc_router.rs#L201-L204 noNewRoutesOnSystemRouter: 'User-provided routes cannot be added to a system router', // https://github.com/oxidecomputer/omicron/blob/914f5fd7d51f9b060dcc0382a30b607e25df49b2/nexus/src/app/vpc_router.rs#L300-L304 @@ -75,7 +74,7 @@ const destinationValueDescription: Record = { ip: 'Enter an IP', instance: 'Select an instance', - internet_gateway: undefined, + internet_gateway: 'Select an internet gateway', drop: undefined, subnet: undefined, vpc: undefined, @@ -84,7 +83,7 @@ const targetValuePlaceholder: Record = const targetValueDescription: Record = { ip: 'An IP address, like 10.0.1.5', instance: undefined, - internet_gateway: routeFormMessage.internetGatewayTargetValue, + internet_gateway: undefined, drop: undefined, subnet: undefined, vpc: undefined, @@ -103,10 +102,15 @@ export const RouteFormFields = ({ form, disabled }: RouteFormFieldsProps) => { // usePrefetchedApiQuery items below are initially fetched in the loaders in vpc-router-route-create and -edit const { data: { items: vpcSubnets }, - } = usePrefetchedApiQuery('vpcSubnetList', { query: { project, vpc, limit: 1000 } }) + } = usePrefetchedApiQuery('vpcSubnetList', { query: { project, vpc, limit: ALL_ISH } }) const { data: { items: instances }, - } = usePrefetchedApiQuery('instanceList', { query: { project, limit: 1000 } }) + } = usePrefetchedApiQuery('instanceList', { query: { project, limit: ALL_ISH } }) + const { + data: { items: internetGateways }, + } = usePrefetchedApiQuery('internetGatewayList', { + query: { project, vpc, limit: ALL_ISH }, + }) const { control } = form const destinationType = form.watch('destination.type') @@ -129,13 +133,35 @@ export const RouteFormFields = ({ form, disabled }: RouteFormFieldsProps) => { control, placeholder: targetValuePlaceholder[targetType], required: true, - // 'internet_gateway' targetTypes can only have the value 'outbound', so we disable the field - disabled: disabled || targetType === 'internet_gateway', + disabled, description: targetValueDescription[targetType], // need a default to prevent the text field validation function from // sticking around when we switch to the combobox validate: () => undefined, } + + const targetTypeField = () => { + if (targetType === 'drop') { + return null + } + if (targetType === 'instance') { + return + } + if (targetType === 'internet_gateway') { + return ( + + ) + } + return ( + + (target.type === 'ip' && validateIp(value)) || undefined + } + /> + ) + } + return ( <> {disabled && ( @@ -176,22 +202,13 @@ export const RouteFormFields = ({ form, disabled }: RouteFormFieldsProps) => { items={toListboxItems(targetTypes)} placeholder="Select a target type" required - onChange={(value) => { - form.setValue('target.value', value === 'internet_gateway' ? 'outbound' : '') + onChange={() => { + form.setValue('target.value', '') form.clearErrors('target.value') }} disabled={disabled} /> - {targetType === 'drop' ? null : targetType === 'instance' ? ( - - ) : ( - - (target.type === 'ip' && validateIp(value)) || undefined - } - /> - )} + {targetTypeField()} ) } diff --git a/app/forms/vpc-router-route-create.tsx b/app/forms/vpc-router-route-create.tsx index 8030b55dc..3f89dc8f7 100644 --- a/app/forms/vpc-router-route-create.tsx +++ b/app/forms/vpc-router-route-create.tsx @@ -15,6 +15,7 @@ import { HL } from '~/components/HL' import { RouteFormFields, type RouteFormValues } from '~/forms/vpc-router-route-common' import { getVpcRouterSelector, useVpcRouterSelector } from '~/hooks/use-params' import { addToast } from '~/stores/toast' +import { ALL_ISH } from '~/util/consts' import { pb } from '~/util/path-builder' const defaultValues: RouteFormValues = { @@ -28,10 +29,13 @@ CreateRouterRouteSideModalForm.loader = async ({ params }: LoaderFunctionArgs) = const { project, vpc } = getVpcRouterSelector(params) await Promise.all([ apiQueryClient.prefetchQuery('vpcSubnetList', { - query: { project, vpc, limit: 1000 }, + query: { project, vpc, limit: ALL_ISH }, }), apiQueryClient.prefetchQuery('instanceList', { - query: { project, limit: 1000 }, + query: { project, limit: ALL_ISH }, + }), + apiQueryClient.prefetchQuery('internetGatewayList', { + query: { project, vpc, limit: ALL_ISH }, }), ]) return null diff --git a/app/forms/vpc-router-route-edit.tsx b/app/forms/vpc-router-route-edit.tsx index da1c06338..d54fba40d 100644 --- a/app/forms/vpc-router-route-edit.tsx +++ b/app/forms/vpc-router-route-edit.tsx @@ -25,6 +25,7 @@ import { } from '~/forms/vpc-router-route-common' import { getVpcRouterRouteSelector, useVpcRouterRouteSelector } from '~/hooks/use-params' import { addToast } from '~/stores/toast' +import { ALL_ISH } from '~/util/consts' import { pb } from '~/util/path-builder' EditRouterRouteSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => { @@ -35,10 +36,13 @@ EditRouterRouteSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => query: { project, vpc, router }, }), apiQueryClient.prefetchQuery('vpcSubnetList', { - query: { project, vpc, limit: 1000 }, + query: { project, vpc, limit: ALL_ISH }, }), apiQueryClient.prefetchQuery('instanceList', { - query: { project, limit: 1000 }, + query: { project, limit: ALL_ISH }, + }), + apiQueryClient.prefetchQuery('internetGatewayList', { + query: { project, vpc, limit: ALL_ISH }, }), ]) return null diff --git a/app/pages/project/vpcs/VpcPage/tabs/VpcGatewaysTab.tsx b/app/pages/project/vpcs/VpcPage/tabs/VpcGatewaysTab.tsx index b6ac97ec4..67499baf1 100644 --- a/app/pages/project/vpcs/VpcPage/tabs/VpcGatewaysTab.tsx +++ b/app/pages/project/vpcs/VpcPage/tabs/VpcGatewaysTab.tsx @@ -48,6 +48,8 @@ export function VpcInternetGatewaysTab() { cell: makeLinkCell((gateway) => pb.vpcInternetGateway({ ...vpcSelector, gateway })), }), colHelper.accessor('description', Columns.description), + // add a column for the IP Pool associated with this Internet Gateway + colHelper.accessor('timeCreated', Columns.timeCreated), ], [vpcSelector]