diff --git a/app/components/ExternalIps.tsx b/app/components/ExternalIps.tsx
index eb9e03693..918d77706 100644
--- a/app/components/ExternalIps.tsx
+++ b/app/components/ExternalIps.tsx
@@ -6,11 +6,15 @@
* Copyright Oxide Computer Company
*/
+import { Link } from 'react-router-dom'
+
import { useApiQuery } from '@oxide/api'
import { EmptyCell, SkeletonCell } from '~/table/cells/EmptyCell'
import { CopyableIp } from '~/ui/lib/CopyableIp'
+import { Slash } from '~/ui/lib/Slash'
import { intersperse } from '~/util/array'
+import { pb } from '~/util/path-builder'
import type * as PP from '~/util/path-params'
export function ExternalIps({ project, instance }: PP.Instance) {
@@ -22,12 +26,29 @@ export function ExternalIps({ project, instance }: PP.Instance) {
const ips = data?.items
if (!ips || ips.length === 0) return
+ // create a copy of ips so we don't mutate the original; move ephemeral ip to the end
+ const orderedIps = [...ips].sort((a) => (a.kind === 'ephemeral' ? 1 : -1))
+ const ipsToShow = orderedIps.slice(0, 2)
+ const overflowCount = orderedIps.length - ipsToShow.length
+
+ // create a list of CopyableIp components
+ const links = ipsToShow.map((eip) => )
+
+ // if there are more than 2 ips, add a link to the instance networking page
+ if (overflowCount > 0) {
+ links.push(
+
+ +{overflowCount}
+
+ )
+ }
+
return (
-
- {intersperse(
- ips.map((eip) =>
),
-
/
- )}
+
+ {intersperse(links, )}
)
}
diff --git a/test/e2e/instance-networking.e2e.ts b/test/e2e/instance-networking.e2e.ts
index f74b1b91b..53f840d4e 100644
--- a/test/e2e/instance-networking.e2e.ts
+++ b/test/e2e/instance-networking.e2e.ts
@@ -122,6 +122,8 @@ test('Instance networking tab — floating IPs', async ({ page }) => {
await expectRowVisible(externalIpTable, { ip: '123.4.56.0', Kind: 'ephemeral' })
await expectRowVisible(externalIpTable, { ip: '123.4.56.5', Kind: 'floating' })
+ await expect(page.getByText('external IPs123.4.56.5/123.4.56.0')).toBeVisible()
+
// Attach a new external IP
await attachFloatingIpButton.click()
await expectVisible(page, ['role=heading[name="Attach floating IP"]'])
@@ -143,9 +145,14 @@ test('Instance networking tab — floating IPs', async ({ page }) => {
// Verify that the "Attach floating IP" button is disabled, since there shouldn't be any more IPs to attach
await expect(attachFloatingIpButton).toBeDisabled()
+ // Verify that the External IPs table row has a +1 in it
+ await expect(page.getByText('external IPs123.4.56.5/123.4.56.4/+1')).toBeVisible()
+
// Detach one of the external IPs
await clickRowAction(page, 'cola-float', 'Detach')
await page.getByRole('button', { name: 'Confirm' }).click()
+ await expect(page.getByText('external IPs123.4.56.5/123.4.56.4/+1')).toBeHidden()
+ await expect(page.getByText('external IPs123.4.56.4/123.4.56.0')).toBeVisible()
// Since we detached it, we don't expect to see the row any longer
await expect(externalIpTable.getByRole('cell', { name: 'cola-float' })).toBeHidden()