diff --git a/app/pages/project/vpcs/VpcPage/VpcPage.tsx b/app/pages/project/vpcs/VpcPage/VpcPage.tsx
index 514401bc25..5bed62c366 100644
--- a/app/pages/project/vpcs/VpcPage/VpcPage.tsx
+++ b/app/pages/project/vpcs/VpcPage/VpcPage.tsx
@@ -59,6 +59,7 @@ export function VpcPage() {
Firewall Rules
Subnets
+ Routers
>
)
diff --git a/app/pages/project/vpcs/VpcPage/tabs/VpcRoutersTab.tsx b/app/pages/project/vpcs/VpcPage/tabs/VpcRoutersTab.tsx
new file mode 100644
index 0000000000..479290d95a
--- /dev/null
+++ b/app/pages/project/vpcs/VpcPage/tabs/VpcRoutersTab.tsx
@@ -0,0 +1,54 @@
+/*
+ * 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 { createColumnHelper } from '@tanstack/react-table'
+import type { LoaderFunctionArgs } from 'react-router-dom'
+
+import { type VpcRouter } from '~/api'
+import { apiQueryClient } from '~/api/client'
+import { getVpcSelector, useVpcSelector } from '~/hooks/use-params'
+import { Columns } from '~/table/columns/common'
+import { PAGE_SIZE, useQueryTable } from '~/table/QueryTable'
+import { Badge } from '~/ui/lib/Badge'
+import { EmptyMessage } from '~/ui/lib/EmptyMessage'
+
+// import { pb } from '~/util/path-builder'
+
+VpcRoutersTab.loader = async ({ params }: LoaderFunctionArgs) => {
+ const { project, vpc } = getVpcSelector(params)
+ await apiQueryClient.prefetchQuery('vpcRouterList', {
+ query: { project, vpc, limit: PAGE_SIZE },
+ })
+ return null
+}
+
+const colHelper = createColumnHelper()
+
+const columns = [
+ colHelper.accessor('name', {}),
+ colHelper.accessor('kind', {
+ cell: (info) => {info.getValue()},
+ }),
+ colHelper.accessor('description', Columns.description),
+ colHelper.accessor('timeCreated', Columns.timeCreated),
+]
+
+export function VpcRoutersTab() {
+ const vpcSelector = useVpcSelector()
+ const { Table } = useQueryTable('vpcRouterList', { query: vpcSelector })
+
+ const emptyState = (
+
+ )
+
+ return
+}
diff --git a/app/routes.tsx b/app/routes.tsx
index 6cdbd3c64f..a864f56fa9 100644
--- a/app/routes.tsx
+++ b/app/routes.tsx
@@ -63,6 +63,7 @@ import { StorageTab } from './pages/project/instances/instance/tabs/StorageTab'
import { InstancesPage } from './pages/project/instances/InstancesPage'
import { SnapshotsPage } from './pages/project/snapshots/SnapshotsPage'
import { VpcFirewallRulesTab } from './pages/project/vpcs/VpcPage/tabs/VpcFirewallRulesTab'
+import { VpcRoutersTab } from './pages/project/vpcs/VpcPage/tabs/VpcRoutersTab'
import { VpcSubnetsTab } from './pages/project/vpcs/VpcPage/tabs/VpcSubnetsTab'
import { VpcPage } from './pages/project/vpcs/VpcPage/VpcPage'
import { VpcsPage } from './pages/project/vpcs/VpcsPage'
@@ -390,6 +391,9 @@ export const routes = createRoutesFromElements(
handle={{ crumb: 'Edit Subnet' }}
/>
+ } loader={VpcRoutersTab.loader}>
+
+
diff --git a/app/util/path-builder.spec.ts b/app/util/path-builder.spec.ts
index eb42d38935..6a37c8d060 100644
--- a/app/util/path-builder.spec.ts
+++ b/app/util/path-builder.spec.ts
@@ -91,6 +91,7 @@ test('path builder', () => {
"vpcFirewallRuleEdit": "/projects/p/vpcs/v/firewall-rules/fr/edit",
"vpcFirewallRules": "/projects/p/vpcs/v/firewall-rules",
"vpcFirewallRulesNew": "/projects/p/vpcs/v/firewall-rules-new",
+ "vpcRouters": "/projects/p/vpcs/v/routers",
"vpcSubnets": "/projects/p/vpcs/v/subnets",
"vpcSubnetsEdit": "/projects/p/vpcs/v/subnets/su/edit",
"vpcSubnetsNew": "/projects/p/vpcs/v/subnets-new",
diff --git a/app/util/path-builder.ts b/app/util/path-builder.ts
index 12e172018c..fcffd30253 100644
--- a/app/util/path-builder.ts
+++ b/app/util/path-builder.ts
@@ -83,6 +83,7 @@ export const pb = {
vpcFirewallRuleEdit: (params: FirewallRule) =>
`${pb.vpcFirewallRules(params)}/${params.rule}/edit`,
vpcSubnets: (params: Vpc) => `${vpcBase(params)}/subnets`,
+ vpcRouters: (params: Vpc) => `${vpcBase(params)}/routers`,
vpcSubnetsNew: (params: Vpc) => `${vpcBase(params)}/subnets-new`,
vpcSubnetsEdit: (params: VpcSubnet) => `${pb.vpcSubnets(params)}/${params.subnet}/edit`,
diff --git a/mock-api/msw/db.ts b/mock-api/msw/db.ts
index fa8d5b6c42..e0cc633ac3 100644
--- a/mock-api/msw/db.ts
+++ b/mock-api/msw/db.ts
@@ -327,6 +327,7 @@ const initDb = {
users: [...mock.users],
vpcFirewallRules: [...mock.firewallRules],
vpcs: [...mock.vpcs],
+ vpcRouters: [...mock.vpcRouters],
vpcSubnets: [mock.vpcSubnet],
}
diff --git a/mock-api/msw/handlers.ts b/mock-api/msw/handlers.ts
index d88e250ad6..61df58218c 100644
--- a/mock-api/msw/handlers.ts
+++ b/mock-api/msw/handlers.ts
@@ -1301,6 +1301,15 @@ export const handlers = makeHandlers({
},
siloMetric: handleMetrics,
+ vpcRouterList({ query }) {
+ const vpc = lookup.vpc(query)
+ const routers = db.vpcRouters.filter((r) => r.vpc_id === vpc.id)
+ return paginated(query, routers)
+ },
+ vpcRouterRouteList() {
+ return { items: [] }
+ },
+
// Misc endpoints we're not using yet in the console
certificateCreate: NotImplemented,
certificateDelete: NotImplemented,
@@ -1373,10 +1382,8 @@ export const handlers = makeHandlers({
userBuiltinView: NotImplemented,
vpcRouterCreate: NotImplemented,
vpcRouterDelete: NotImplemented,
- vpcRouterList: NotImplemented,
vpcRouterRouteCreate: NotImplemented,
vpcRouterRouteDelete: NotImplemented,
- vpcRouterRouteList: NotImplemented,
vpcRouterRouteUpdate: NotImplemented,
vpcRouterRouteView: NotImplemented,
vpcRouterUpdate: NotImplemented,
diff --git a/mock-api/vpc.ts b/mock-api/vpc.ts
index 4d180daa97..3ee2b97a54 100644
--- a/mock-api/vpc.ts
+++ b/mock-api/vpc.ts
@@ -6,7 +6,7 @@
* Copyright Oxide Computer Company
*/
-import type { Vpc, VpcFirewallRule, VpcSubnet } from '@oxide/api'
+import type { Vpc, VpcFirewallRule, VpcRouter, VpcSubnet } from '@oxide/api'
import type { Json } from './json-type'
import { project, project2 } from './project'
@@ -174,3 +174,15 @@ export const firewallRules: Json = [
vpc_id: vpc2.id,
},
]
+
+export const vpcRouters: Json = [
+ {
+ id: '9715d7cf-0e29-4c66-92dc-642961f9a3cb',
+ name: 'default',
+ kind: 'system',
+ description: '',
+ time_created,
+ time_modified,
+ vpc_id: vpc.id,
+ },
+]