Skip to content
Open
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
20 changes: 16 additions & 4 deletions app/pages/system/silos/SiloIpPoolsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { useQuery } from '@tanstack/react-query'
import { createColumnHelper } from '@tanstack/react-table'
import { useCallback, useMemo, useState } from 'react'
import { useForm } from 'react-hook-form'
import { useForm, useWatch } from 'react-hook-form'
import { type LoaderFunctionArgs } from 'react-router'

import {
Expand All @@ -24,6 +24,7 @@ import {
import { Networking24Icon } from '@oxide/design-system/icons/react'
import { Badge } from '@oxide/design-system/ui'

import { CheckboxField } from '~/components/form/fields/CheckboxField'
import { ComboboxField } from '~/components/form/fields/ComboboxField'
import { HL } from '~/components/HL'
import { IpVersionBadge } from '~/components/IpVersionBadge'
Expand Down Expand Up @@ -263,9 +264,10 @@ export const handle = makeCrumb('IP Pools')

type LinkPoolFormValues = {
pool: string | undefined
isDefault: boolean
}

const defaultValues: LinkPoolFormValues = { pool: undefined }
const defaultValues: LinkPoolFormValues = { pool: undefined, isDefault: false }

function LinkPoolModal({ onDismiss }: { onDismiss: () => void }) {
const { silo } = useSiloSelector()
Expand All @@ -282,14 +284,18 @@ function LinkPoolModal({ onDismiss }: { onDismiss: () => void }) {
},
})

function onSubmit({ pool }: LinkPoolFormValues) {
function onSubmit({ pool, isDefault }: LinkPoolFormValues) {
if (!pool) return // can't happen, silo is required
linkPool.mutate({ path: { pool }, body: { silo, isDefault: false } })
linkPool.mutate({ path: { pool }, body: { silo, isDefault } })
}

const allLinkedPools = useQuery(allSiloPoolsQuery(silo).optionsFn())
const allPools = useQuery(allPoolsQuery.optionsFn())

// Fetch the selected pool details so we can update the checkbox label.
const selectedPoolName = useWatch({ control, name: 'pool' })
const selectedPool = allPools.data?.items.find((p) => p.name === selectedPoolName)

// in order to get the list of remaining unlinked pools, we have to get the
// list of all pools and remove the already linked ones

Expand Down Expand Up @@ -334,6 +340,12 @@ function LinkPoolModal({ onDismiss }: { onDismiss: () => void }) {
required
control={control}
/>

<CheckboxField name="isDefault" control={control}>
{selectedPool
? `Make default IP${selectedPool.ipVersion} ${selectedPool.poolType} pool for silo`
: 'Make default pool for silo'}
</CheckboxField>
Comment thread
sudomateo marked this conversation as resolved.
</form>
</Modal.Section>
</Modal.Body>
Expand Down
20 changes: 16 additions & 4 deletions app/pages/system/silos/SiloSubnetPoolsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { useQuery } from '@tanstack/react-query'
import { createColumnHelper } from '@tanstack/react-table'
import { useCallback, useMemo, useState } from 'react'
import { useForm } from 'react-hook-form'
import { useForm, useWatch } from 'react-hook-form'
import { type LoaderFunctionArgs } from 'react-router'

import {
Expand All @@ -24,6 +24,7 @@ import {
import { Networking24Icon } from '@oxide/design-system/icons/react'
import { Badge } from '@oxide/design-system/ui'

import { CheckboxField } from '~/components/form/fields/CheckboxField'
import { ComboboxField } from '~/components/form/fields/ComboboxField'
import { HL } from '~/components/HL'
import { IpVersionBadge } from '~/components/IpVersionBadge'
Expand Down Expand Up @@ -252,9 +253,10 @@ export const handle = makeCrumb('Subnet Pools')

type LinkPoolFormValues = {
pool: string | undefined
isDefault: boolean
}

const defaultValues: LinkPoolFormValues = { pool: undefined }
const defaultValues: LinkPoolFormValues = { pool: undefined, isDefault: false }

function LinkPoolModal({ onDismiss }: { onDismiss: () => void }) {
const { silo } = useSiloSelector()
Expand All @@ -271,14 +273,18 @@ function LinkPoolModal({ onDismiss }: { onDismiss: () => void }) {
},
})

function onSubmit({ pool }: LinkPoolFormValues) {
function onSubmit({ pool, isDefault }: LinkPoolFormValues) {
if (!pool) return
linkPool.mutate({ path: { pool }, body: { silo, isDefault: false } })
linkPool.mutate({ path: { pool }, body: { silo, isDefault } })
}

const allLinkedPools = useQuery(allSiloPoolsQuery(silo).optionsFn())
const allPools = useQuery(allPoolsQuery.optionsFn())

// Fetch the selected pool details so we can update the checkbox label.
const selectedPoolName = useWatch({ control, name: 'pool' })
const selectedPool = allPools.data?.items.find((p) => p.name === selectedPoolName)

const linkedPoolIds = useMemo(
() =>
allLinkedPools.data ? new Set(allLinkedPools.data.items.map((p) => p.id)) : undefined,
Expand Down Expand Up @@ -320,6 +326,12 @@ function LinkPoolModal({ onDismiss }: { onDismiss: () => void }) {
required
control={control}
/>

<CheckboxField name="isDefault" control={control}>
{selectedPool
? `Make default IP${selectedPool.ipVersion} subnet pool for silo`
: 'Make default subnet pool for silo'}
</CheckboxField>
</form>
</Modal.Section>
</Modal.Body>
Expand Down
54 changes: 51 additions & 3 deletions test/e2e/silos.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,14 +370,62 @@ test('Silo IP pools link pool', async ({ page }) => {
await page.getByPlaceholder('Select a pool').fill('x')
await expect(page.getByText('No items match')).toBeVisible()

// select silo in combobox and click link
// before a pool is selected, the default checkbox label is generic
await expect(
page.getByRole('checkbox', { name: 'Make default pool for silo' })
).toBeVisible()

// select pool in combobox
await page.getByPlaceholder('Select a pool').fill('ip-pool')
await page.getByRole('option', { name: 'ip-pool-3' }).click()

// checkbox label now reflects the selected pool's version and type
const defaultCheckbox = page.getByRole('checkbox', {
name: 'Make default IPv4 unicast pool for silo',
})
await expect(defaultCheckbox).toBeVisible()
await defaultCheckbox.check()

await modal.getByRole('button', { name: 'Link' }).click()

// modal closes and we see the pool linked as default in the table
await expect(modal).toBeHidden()
await expectRowVisible(table, { name: 'ip-pool-3default', Version: 'v4' })
})

test('Silo subnet pools link pool', async ({ page }) => {
await page.goto('/system/silos/maze-war/subnet-pools')

const table = page.getByRole('table')
await expectRowVisible(table, { name: 'default-v4-subnet-pooldefault', Version: 'v4' })

const modal = page.getByRole('dialog', { name: 'Link pool' })
await expect(modal).toBeHidden()

await page.getByRole('button', { name: 'Link pool' }).click()
await expect(modal).toBeVisible()

// before a pool is selected, the default checkbox label is generic
await expect(
page.getByRole('checkbox', { name: 'Make default subnet pool for silo' })
).toBeVisible()

// select pool in combobox
await page.getByPlaceholder('Select a pool').fill('myriad')
await page.getByRole('option', { name: 'myriad-v4-subnet-pool' }).click()

// checkbox label now reflects the selected pool's version
const defaultCheckbox = page.getByRole('checkbox', {
name: 'Make default IPv4 subnet pool for silo',
})
await expect(defaultCheckbox).toBeVisible()
await defaultCheckbox.check()

await modal.getByRole('button', { name: 'Link' }).click()

// modal closes and we see the thing in the table
// modal closes and we see the pool linked as default in the table
await expect(modal).toBeHidden()
await expectRowVisible(table, { name: 'ip-pool-3', Version: 'v4' })
await expectRowVisible(table, { name: 'myriad-v4-subnet-pooldefault', Version: 'v4' })
})

// just a convenient form to test this with because it's tall
Expand Down
Loading