}
loader={NetworkingTab.loader}
- handle={{ crumb: 'Network interfaces' }}
+ handle={{ crumb: 'Networking' }}
/>
from RT, but in these
@@ -31,11 +32,14 @@ function sizeCell(info: Info) {
)
}
+export const DescriptionCell = ({ text }: { text?: string }) =>
+ text ? :
+
/** Columns used in a bunch of tables */
export const Columns = {
/** Truncates text if too long, full text in tooltip */
description: {
- cell: (info: Info) => ,
+ cell: (info: Info) => ,
},
size: { cell: sizeCell },
timeCreated: { header: 'created', cell: dateCell },
diff --git a/app/ui/lib/Table.tsx b/app/ui/lib/Table.tsx
index 08c88239e..22511ad85 100644
--- a/app/ui/lib/Table.tsx
+++ b/app/ui/lib/Table.tsx
@@ -140,3 +140,5 @@ export const TableControlsButton = (props: ButtonProps) => (
export const TableControlsLink = (props: LinkProps) => (
)
+
+export const TableTitle = classed.div`text-sans-lg text-default`
diff --git a/mock-api/msw/handlers.ts b/mock-api/msw/handlers.ts
index 9cc079591..b52c297c3 100644
--- a/mock-api/msw/handlers.ts
+++ b/mock-api/msw/handlers.ts
@@ -261,9 +261,7 @@ export const handlers = makeHandlers({
}
floatingIp.name = body.name
}
- if (body.description) {
- floatingIp.description = body.description
- }
+ floatingIp.description = body.description || ''
return floatingIp
},
floatingIpDelete({ path, query }) {
diff --git a/test/e2e/click-everything.e2e.ts b/test/e2e/click-everything.e2e.ts
index 8db2064c0..95db0babe 100644
--- a/test/e2e/click-everything.e2e.ts
+++ b/test/e2e/click-everything.e2e.ts
@@ -19,7 +19,7 @@ test('Click through instance page', async ({ page }) => {
'role=heading[name*=db1]',
'role=tab[name="Storage"]',
'role=tab[name="Metrics"]',
- 'role=tab[name="Network Interfaces"]',
+ 'role=tab[name="Networking"]',
'role=cell[name="disk-1"]',
'role=cell[name="disk-2"]',
// buttons disabled while instance is running
diff --git a/test/e2e/instance-create.e2e.ts b/test/e2e/instance-create.e2e.ts
index d17b86cab..13b82d208 100644
--- a/test/e2e/instance-create.e2e.ts
+++ b/test/e2e/instance-create.e2e.ts
@@ -70,8 +70,8 @@ test('can create an instance', async ({ page }) => {
])
// network tab works
- await page.getByRole('tab', { name: 'Network Interfaces' }).click()
- const table = page.getByRole('table')
+ await page.getByRole('tab', { name: 'Networking' }).click()
+ const table = page.getByRole('table', { name: 'Network interfaces' })
await expectRowVisible(table, {
name: 'defaultprimary',
vpc: 'mock-vpc',
@@ -239,7 +239,7 @@ test('create instance with existing disk', async ({ page }) => {
await page.getByRole('button', { name: 'Create instance' }).click()
await expect(page).toHaveURL(`/projects/mock-project/instances/${instanceName}/storage`)
await expectVisible(page, [`h1:has-text("${instanceName}")`, 'text=8 GiB'])
- await expectRowVisible(page.getByRole('table'), { name: 'disk-3' })
+ await expectRowVisible(page.getByRole('table'), { Disk: 'disk-3' })
})
test('create instance with a different existing disk', async ({ page }) => {
@@ -252,7 +252,7 @@ test('create instance with a different existing disk', async ({ page }) => {
await page.getByRole('button', { name: 'Create instance' }).click()
await expect(page).toHaveURL(`/projects/mock-project/instances/${instanceName}/storage`)
await expectVisible(page, [`h1:has-text("${instanceName}")`, 'text=8 GiB'])
- await expectRowVisible(page.getByRole('table'), { name: 'disk-4' })
+ await expectRowVisible(page.getByRole('table'), { Disk: 'disk-4' })
})
test('start with an existing disk, but then switch to a silo image', async ({ page }) => {
diff --git a/test/e2e/instance/networking.e2e.ts b/test/e2e/instance/networking.e2e.ts
index 43ef5064d..1a75d5ebf 100644
--- a/test/e2e/instance/networking.e2e.ts
+++ b/test/e2e/instance/networking.e2e.ts
@@ -15,7 +15,7 @@ import {
stopInstance,
} from '../utils'
-test('Instance networking tab', async ({ page }) => {
+test('Instance networking tab — NIC table', async ({ page }) => {
await page.goto('/projects/mock-project/instances/db1')
// links to VPC and external IPs appear in table
@@ -23,10 +23,11 @@ test('Instance networking tab', async ({ page }) => {
await expect(page.getByRole('link', { name: '123.4.56.0' })).toBeVisible()
// Instance networking tab
- await page.click('role=tab[name="Network Interfaces"]')
+ await page.click('role=tab[name="Networking"]')
- const table = page.locator('table')
- await expectRowVisible(table, { name: 'my-nicprimary' })
+ const nicTable = page.getByRole('table', { name: 'Network interfaces' })
+
+ await expectRowVisible(nicTable, { name: 'my-nicprimary' })
// check VPC link in table points to the right page
await expect(page.locator('role=cell >> role=link[name="mock-vpc"]')).toHaveAttribute(
@@ -60,8 +61,8 @@ test('Instance networking tab', async ({ page }) => {
// Make this interface primary
await clickRowAction(page, 'nic-2', 'Make primary')
- await expectRowVisible(table, { name: 'my-nic' })
- await expectRowVisible(table, { name: 'nic-2primary' })
+ await expectRowVisible(nicTable, { name: 'my-nic' })
+ await expectRowVisible(nicTable, { name: 'nic-2primary' })
// Make an edit to the network interface
await clickRowAction(page, 'nic-2', 'Edit')
@@ -76,3 +77,43 @@ test('Instance networking tab', async ({ page }) => {
await page.getByRole('button', { name: 'Confirm' }).click()
await expect(nic3).toBeHidden()
})
+
+test('Instance networking tab — External IPs', async ({ page }) => {
+ await page.goto('/projects/mock-project/instances/db1/network-interfaces')
+ const externalIpTable = page.getByRole('table', { name: 'External IPs' })
+
+ // See list of external IPs
+ await expectRowVisible(externalIpTable, { ip: '123.4.56.0', Kind: 'ephemeral' })
+ await expectRowVisible(externalIpTable, { ip: '123.4.56.5', Kind: 'floating' })
+
+ // Attach a new external IP
+ await page.click('role=button[name="Attach floating IP"]')
+ await expectVisible(page, ['role=heading[name="Attach floating IP"]'])
+
+ // Select the 'rootbeer-float' option
+ const dialog = page.getByRole('dialog')
+ // TODO: this "select the option" syntax is awkward; it's working, but I suspect there's a better way
+ await dialog.getByRole('button', { name: 'Select floating IP' }).click()
+ await page.keyboard.press('ArrowDown')
+ await page.keyboard.press('Enter')
+ // await dialog.getByRole('button', { name: 'rootbeer-float' }).click()
+ // await dialog.getByRole('button', { name: 'rootbeer-float123.4.56.4/A classic.' }).click()
+ await dialog.getByRole('button', { name: 'Attach' }).click()
+
+ // Confirm the modal is gone and the new row is showing on the page
+ await expect(page.getByRole('dialog')).toBeHidden()
+ await expectRowVisible(externalIpTable, { name: 'rootbeer-float' })
+
+ // Verify that the "Attach floating IP" button is disabled, since there shouldn't be any more IPs to attach
+ await expect(page.getByRole('button', { name: 'Attach floating IP' })).toBeDisabled()
+
+ // Detach one of the external IPs
+ await clickRowAction(page, 'cola-float', 'Detach')
+ await page.getByRole('button', { name: 'Confirm' }).click()
+
+ // Since we detached it, we don't expect to see db1 any longer
+ await expect(externalIpTable.getByRole('cell', { name: 'cola-float' })).toBeHidden()
+
+ // And that button shouldbe enabled again
+ await expect(page.getByRole('button', { name: 'Attach floating IP' })).toBeEnabled()
+})
diff --git a/test/e2e/network-interface-create.e2e.ts b/test/e2e/network-interface-create.e2e.ts
index 21c01ae93..888806c0a 100644
--- a/test/e2e/network-interface-create.e2e.ts
+++ b/test/e2e/network-interface-create.e2e.ts
@@ -34,7 +34,8 @@ test('can create a NIC with a specified IP address', async ({ page }) => {
await sidebar.getByRole('button', { name: 'Add network interface' }).click()
await expect(sidebar).toBeHidden()
- await expectRowVisible(page.getByRole('table'), { name: 'nic-1', ip: '1.2.3.4' })
+ const table = page.getByRole('table', { name: 'Network interfaces' })
+ await expectRowVisible(table, { name: 'nic-1', 'Private IP': '1.2.3.4' })
})
test('can create a NIC with a blank IP address', async ({ page }) => {
@@ -74,5 +75,6 @@ test('can create a NIC with a blank IP address', async ({ page }) => {
await expect(sidebar).toBeHidden()
// ip address is auto-assigned
- await expectRowVisible(page.getByRole('table'), { name: 'nic-2', ip: '123.45.68.8' })
+ const table = page.getByRole('table', { name: 'Network interfaces' })
+ await expectRowVisible(table, { name: 'nic-2', 'Private IP': '123.45.68.8' })
})