Skip to content
Draft
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
63 changes: 63 additions & 0 deletions app/forms/internet-gateway-create.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* Copyright Oxide Computer Company
*/
import { useForm } from 'react-hook-form'
import { useNavigate } from 'react-router'

import { api, queryClient, useApiMutation, type InternetGatewayCreate } from '@oxide/api'

import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { titleCrumb } from '~/hooks/use-crumbs'
import { useVpcSelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { SideModalFormDocs } from '~/ui/lib/ModalLinks'
import { docLinks } from '~/util/links'
import { pb } from '~/util/path-builder'

const defaultValues: InternetGatewayCreate = {
name: '',
description: '',
}

export const handle = titleCrumb('New Internet Gateway')

export default function InternetGatewayCreateForm() {
const vpcSelector = useVpcSelector()
const navigate = useNavigate()

const onDismiss = () => navigate(pb.vpcInternetGateways(vpcSelector))

const createGateway = useApiMutation(api.internetGatewayCreate, {
onSuccess(gateway) {
queryClient.invalidateEndpoint('internetGatewayList')
// prettier-ignore
addToast(<>Internet gateway <HL>{gateway.name}</HL> created</>)
onDismiss()
},
})

const form = useForm({ defaultValues })

return (
<SideModalForm
form={form}
formType="create"
resourceName="internet gateway"
onDismiss={onDismiss}
onSubmit={(body) => createGateway.mutate({ query: vpcSelector, body })}
loading={createGateway.isPending}
submitError={createGateway.error}
>
<NameField name="name" control={form.control} />
<DescriptionField name="description" control={form.control} />
<SideModalFormDocs docs={[docLinks.gateways]} />
</SideModalForm>
)
}
85 changes: 85 additions & 0 deletions app/forms/internet-gateway-ip-address-create.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* Copyright Oxide Computer Company
*/
import { useForm } from 'react-hook-form'
import { useNavigate } from 'react-router'

import {
api,
queryClient,
useApiMutation,
type InternetGatewayIpAddressCreate,
} from '@oxide/api'

import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { NameField } from '~/components/form/fields/NameField'
import { noPasswordManager, TextField } from '~/components/form/fields/TextField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { titleCrumb } from '~/hooks/use-crumbs'
import { useInternetGatewaySelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { SideModalFormDocs } from '~/ui/lib/ModalLinks'
import { validateIp } from '~/util/ip'
import { docLinks } from '~/util/links'
import { pb } from '~/util/path-builder'

export const handle = titleCrumb('Attach IP Address')

const defaultValues: InternetGatewayIpAddressCreate = {
name: '',
description: '',
address: '',
}

export default function InternetGatewayIpAddressCreateForm() {
const { project, vpc, gateway } = useInternetGatewaySelector()
const navigate = useNavigate()

const onDismiss = () => navigate(pb.vpcInternetGateway({ project, vpc, gateway }))

const attachAddress = useApiMutation(api.internetGatewayIpAddressCreate, {
onSuccess(address) {
queryClient.invalidateEndpoint('internetGatewayIpAddressList')
// prettier-ignore
addToast(<>IP address <HL>{address.name}</HL> attached</>)
onDismiss()
},
})

const form = useForm({ defaultValues })

return (
<SideModalForm
form={form}
formType="create"
resourceName="IP address"
title="Attach IP address"
onDismiss={onDismiss}
onSubmit={(body) => attachAddress.mutate({ query: { project, vpc, gateway }, body })}
loading={attachAddress.isPending}
submitError={attachAddress.error}
>
<NameField
name="name"
control={form.control}
description="A name for this attachment"
/>
<DescriptionField name="description" control={form.control} />
<TextField
name="address"
label="IP address"
description="An address from an IP pool attached to this gateway"
control={form.control}
required
validate={validateIp}
{...noPasswordManager}
/>
<SideModalFormDocs docs={[docLinks.gateways]} />
</SideModalForm>
)
}
98 changes: 98 additions & 0 deletions app/forms/internet-gateway-ip-pool-create.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* Copyright Oxide Computer Company
*/
import { useForm } from 'react-hook-form'
import { useNavigate } from 'react-router'

import {
api,
q,
queryClient,
sortPools,
useApiMutation,
usePrefetchedQuery,
type InternetGatewayIpPoolCreate,
} from '@oxide/api'

import { DescriptionField } from '~/components/form/fields/DescriptionField'
import { ListboxField } from '~/components/form/fields/ListboxField'
import { NameField } from '~/components/form/fields/NameField'
import { SideModalForm } from '~/components/form/SideModalForm'
import { HL } from '~/components/HL'
import { toPoolItem } from '~/components/PoolListboxItem'
import { titleCrumb } from '~/hooks/use-crumbs'
import { useInternetGatewaySelector } from '~/hooks/use-params'
import { addToast } from '~/stores/toast'
import { SideModalFormDocs } from '~/ui/lib/ModalLinks'
import { ALL_ISH } from '~/util/consts'
import { docLinks } from '~/util/links'
import { pb } from '~/util/path-builder'

const poolList = q(api.ipPoolList, { query: { limit: ALL_ISH } })

export async function clientLoader() {
await queryClient.prefetchQuery(poolList)
return null
}

export const handle = titleCrumb('Attach IP Pool')

const defaultValues: InternetGatewayIpPoolCreate = {
name: '',
description: '',
ipPool: '',
}

export default function InternetGatewayIpPoolCreateForm() {
const { project, vpc, gateway } = useInternetGatewaySelector()
const navigate = useNavigate()

const { data: pools } = usePrefetchedQuery(poolList)

const onDismiss = () => navigate(pb.vpcInternetGateway({ project, vpc, gateway }))

const attachPool = useApiMutation(api.internetGatewayIpPoolCreate, {
onSuccess(pool) {
queryClient.invalidateEndpoint('internetGatewayIpPoolList')
// prettier-ignore
addToast(<>IP pool <HL>{pool.name}</HL> attached</>)
onDismiss()
},
})

const form = useForm({ defaultValues })

return (
<SideModalForm
form={form}
formType="create"
resourceName="IP pool"
title="Attach IP pool"
onDismiss={onDismiss}
onSubmit={(body) => attachPool.mutate({ query: { project, vpc, gateway }, body })}
loading={attachPool.isPending}
submitError={attachPool.error}
>
<NameField
name="name"
control={form.control}
description="A name for this attachment"
/>
<DescriptionField name="description" control={form.control} />
<ListboxField
name="ipPool"
label="IP pool"
control={form.control}
items={sortPools(pools.items).map(toPoolItem)}
required
placeholder="Select a pool"
noItemsPlaceholder="No pools available"
/>
<SideModalFormDocs docs={[docLinks.gateways]} />
</SideModalForm>
)
}
Loading
Loading