Skip to content

Commit

Permalink
Add internet gateway combobox to router route target field
Browse files Browse the repository at this point in the history
  • Loading branch information
charliepark committed Dec 2, 2024
1 parent b5b7eb6 commit fdc2995
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 24 deletions.
57 changes: 37 additions & 20 deletions app/forms/vpc-router-route-common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,14 @@ 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<RouterRouteUpdate>

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
Expand Down Expand Up @@ -75,7 +74,7 @@ const destinationValueDescription: Record<RouteDestination['type'], string | und
const targetValuePlaceholder: Record<RouteTarget['type'], string | undefined> = {
ip: 'Enter an IP',
instance: 'Select an instance',
internet_gateway: undefined,
internet_gateway: 'Select an internet gateway',
drop: undefined,
subnet: undefined,
vpc: undefined,
Expand All @@ -84,7 +83,7 @@ const targetValuePlaceholder: Record<RouteTarget['type'], string | undefined> =
const targetValueDescription: Record<RouteTarget['type'], string | undefined> = {
ip: 'An IP address, like 10.0.1.5',
instance: undefined,
internet_gateway: routeFormMessage.internetGatewayTargetValue,
internet_gateway: undefined,
drop: undefined,
subnet: undefined,
vpc: undefined,
Expand All @@ -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')
Expand All @@ -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 <ComboboxField {...targetValueProps} items={toComboboxItems(instances)} />
}
if (targetType === 'internet_gateway') {
return (
<ComboboxField {...targetValueProps} items={toComboboxItems(internetGateways)} />
)
}
return (
<TextField
{...targetValueProps}
validate={(value, { target }) =>
(target.type === 'ip' && validateIp(value)) || undefined
}
/>
)
}

return (
<>
{disabled && (
Expand Down Expand Up @@ -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' ? (
<ComboboxField {...targetValueProps} items={toComboboxItems(instances)} />
) : (
<TextField
{...targetValueProps}
validate={(value, { target }) =>
(target.type === 'ip' && validateIp(value)) || undefined
}
/>
)}
{targetTypeField()}
</>
)
}
8 changes: 6 additions & 2 deletions app/forms/vpc-router-route-create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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
Expand Down
8 changes: 6 additions & 2 deletions app/forms/vpc-router-route-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions app/pages/project/vpcs/VpcPage/tabs/VpcGatewaysTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down

0 comments on commit fdc2995

Please sign in to comment.