Skip to content

Commit f20a5bc

Browse files
authored
Add IP Pool to table of floating IPs (#2245)
* Add IP Pool to list of floating IPs * Update IP column to IP Address
1 parent b815dd8 commit f20a5bc

File tree

4 files changed

+42
-6
lines changed

4 files changed

+42
-6
lines changed

app/pages/project/floating-ips/FloatingIpsPage.tsx

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { Outlet, useNavigate, type LoaderFunctionArgs } from 'react-router-dom'
1313
import {
1414
apiQueryClient,
1515
useApiMutation,
16+
useApiQuery,
1617
useApiQueryClient,
1718
usePrefetchedApiQuery,
1819
type FloatingIp,
@@ -26,17 +27,20 @@ import { getProjectSelector, useProjectSelector } from '~/hooks'
2627
import { confirmAction } from '~/stores/confirm-action'
2728
import { confirmDelete } from '~/stores/confirm-delete'
2829
import { addToast } from '~/stores/toast'
30+
import { EmptyCell } from '~/table/cells/EmptyCell'
2931
import { InstanceLinkCell } from '~/table/cells/InstanceLinkCell'
3032
import { useColsWithActions, type MenuAction } from '~/table/columns/action-col'
3133
import { Columns } from '~/table/columns/common'
3234
import { PAGE_SIZE, useQueryTable } from '~/table/QueryTable'
35+
import { Badge } from '~/ui/lib/Badge'
3336
import { CreateLink } from '~/ui/lib/CreateButton'
3437
import { EmptyMessage } from '~/ui/lib/EmptyMessage'
3538
import { Listbox } from '~/ui/lib/Listbox'
3639
import { Message } from '~/ui/lib/Message'
3740
import { Modal } from '~/ui/lib/Modal'
3841
import { PageHeader, PageTitle } from '~/ui/lib/PageHeader'
3942
import { TableActions } from '~/ui/lib/Table'
43+
import { Tooltip } from '~/ui/lib/Tooltip'
4044
import { docLinks } from '~/util/links'
4145
import { pb } from '~/util/path-builder'
4246

@@ -59,15 +63,45 @@ FloatingIpsPage.loader = async ({ params }: LoaderFunctionArgs) => {
5963
apiQueryClient.prefetchQuery('instanceList', {
6064
query: { project },
6165
}),
66+
apiQueryClient
67+
.fetchQuery('projectIpPoolList', { query: { limit: 1000 } })
68+
.then((pools) => {
69+
for (const pool of pools.items) {
70+
apiQueryClient.setQueryData(
71+
'projectIpPoolView',
72+
{ path: { pool: pool.id } },
73+
pool
74+
)
75+
}
76+
}),
6277
])
6378
return null
6479
}
6580

81+
const IpPoolCell = ({ ipPoolId }: { ipPoolId: string }) => {
82+
const pool = useApiQuery('projectIpPoolView', { path: { pool: ipPoolId } }).data
83+
if (!pool) return <EmptyCell />
84+
const badge = <Badge color="neutral">{pool.name}</Badge>
85+
return pool.description ? (
86+
<Tooltip content={pool.description} placement="right">
87+
<span>{badge}</span>
88+
</Tooltip>
89+
) : (
90+
badge
91+
)
92+
}
93+
6694
const colHelper = createColumnHelper<FloatingIp>()
6795
const staticCols = [
6896
colHelper.accessor('name', {}),
6997
colHelper.accessor('description', Columns.description),
70-
colHelper.accessor('ip', {}),
98+
colHelper.accessor('ip', {
99+
header: 'IP address',
100+
}),
101+
colHelper.accessor('ipPoolId', {
102+
cell: (info) => <IpPoolCell ipPoolId={info.getValue()} />,
103+
header: 'IP pool',
104+
}),
71105
colHelper.accessor('instanceId', {
72106
cell: (info) => <InstanceLinkCell instanceId={info.getValue()} />,
73107
header: 'Attached to instance',

app/ui/lib/Tooltip.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ import { usePopoverZIndex } from './SideModal'
3636

3737
export interface TooltipProps {
3838
delay?: number
39-
children?: React.ReactNode
39+
/** The target the tooltip hovers near; can not be a raw string. */
40+
children?: ReactElement
4041
/** The text to appear on hover/focus */
4142
content: string | React.ReactNode
4243
/**

mock-api/ip-pool.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ import { defaultSilo } from './silo'
1414
export const ipPool1: Json<IpPool> = {
1515
id: '69b5c583-74a9-451a-823d-0741c1ec66e2',
1616
name: 'ip-pool-1',
17-
description: '',
17+
description: 'public IPs',
1818
time_created: new Date().toISOString(),
1919
time_modified: new Date().toISOString(),
2020
}
2121

2222
const ipPool2: Json<IpPool> = {
2323
id: 'af2fbe06-b21d-4364-96b7-a58220bc3242',
2424
name: 'ip-pool-2',
25-
description: '',
25+
description: 'VPN IPs',
2626
time_created: new Date().toISOString(),
2727
time_modified: new Date().toISOString(),
2828
}

test/e2e/floating-ip-create.e2e.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ test('can create a floating IP', async ({ page }) => {
4949
await expectRowVisible(page.getByRole('table'), {
5050
name: floatingIpName,
5151
description: 'A description for this Floating IP',
52+
'IP pool': 'ip-pool-1',
5253
})
5354
})
5455

@@ -62,7 +63,7 @@ test('can detach and attach a floating IP', async ({ page }) => {
6263

6364
await expectRowVisible(page.getByRole('table'), {
6465
name: 'cola-float',
65-
ip: '123.4.56.5',
66+
'IP address': '123.4.56.5',
6667
'Attached to instance': 'db1',
6768
})
6869
await clickRowAction(page, 'cola-float', 'Detach')
@@ -91,7 +92,7 @@ test('can detach and attach a floating IP', async ({ page }) => {
9192
await expect(page.getByRole('dialog')).toBeHidden()
9293
await expectRowVisible(page.getByRole('table'), {
9394
name: 'cola-float',
94-
ip: '123.4.56.5',
95+
'IP address': '123.4.56.5',
9596
'Attached to instance': 'db1',
9697
})
9798
})

0 commit comments

Comments
 (0)