Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add VPC, Subnet to NIC table #1047

Merged
merged 11 commits into from
Jul 21, 2022
6 changes: 5 additions & 1 deletion app/pages/__tests__/instance/networking.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ test('Instance networking tab', async ({ page }) => {
'my-nic',
'a network interface',
'172.30.0.10',
'mock-vpc',
'mock-subnet',
'primary',
])

Expand Down Expand Up @@ -52,9 +54,11 @@ test('Instance networking tab', async ({ page }) => {
'my-nic',
'a network interface',
'172.30.0.10',
'mock-vpc',
'mock-subnet',
'',
])
await expectRowVisible(page, 'nic-2', ['', 'nic-2', null, null, 'primary'])
await expectRowVisible(page, 'nic-2', ['', 'nic-2', null, null, null, null, 'primary'])

// Make an edit to the network interface
await page
Expand Down
8 changes: 7 additions & 1 deletion app/pages/project/instances/instance/tabs/NetworkingTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useState } from 'react'
import type { NetworkInterface, NetworkInterfaceUpdate } from '@oxide/api'
import { useApiMutation, useApiQuery, useApiQueryClient } from '@oxide/api'
import type { MenuAction } from '@oxide/table'
import { useQueryTable } from '@oxide/table'
import { byIdCell, useQueryTable } from '@oxide/table'
import {
Badge,
Button,
Expand Down Expand Up @@ -98,6 +98,12 @@ export function NetworkingTab() {
<Column accessor="description" />
{/* TODO: mark v4 or v6 explicitly? */}
<Column accessor="ip" />
<Column header="vpc" accessor="vpcId" cell={byIdCell('vpcViewById', 'name')} />
<Column
header="subnet"
accessor="subnetId"
cell={byIdCell('vpcSubnetViewById', 'name')}
/>
<Column
accessor="primary"
cell={({ value }) =>
Expand Down
13 changes: 0 additions & 13 deletions libs/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import type * as ApiTypes from './__generated__/Api'
import { Api } from './__generated__/Api'
import { handleErrors } from './errors'
import type { ResultItem } from './hooks'
import { getUseApiMutation, getUseApiQuery, getUseApiQueryClient } from './hooks'

const api = new Api({
Expand All @@ -11,18 +10,6 @@ const api = new Api({

export type ApiMethods = typeof api.methods

/**
* API methods that return a list of items.
*/
export type ApiListMethods = {
// Only never extends never. If ResultItem extends never, that means we
// couldn't pull out an item, which means it's not a list endpoint. If we can
// infer an item, that means it's a list endpoint, so include its M.
[M in keyof ApiMethods as ResultItem<ApiMethods[M]> extends never
? never
: M]: ApiMethods[M]
}

export const useApiQuery = getUseApiQuery(api.methods, handleErrors)
export const useApiMutation = getUseApiMutation(api.methods, handleErrors)
export const useApiQueryClient = getUseApiQueryClient<ApiMethods>()
Expand Down
2 changes: 1 addition & 1 deletion libs/table/QueryTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const makeQueryTable = <Item,>(
manualPagination: true,
})

if (debug) console.table(data)
if (debug) console.table((data as { items?: any[] })?.items || data)

const paginationParams = useMemo(
() => ({
Expand Down
32 changes: 32 additions & 0 deletions libs/table/cells/IdLookupCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react'
import type { AsyncReturnType } from 'type-fest'

import type { ApiViewByIdMethods } from '@oxide/api'
import { useApiQuery } from '@oxide/api'

import type { Cell } from './Cell'

interface IdLookupCellProps<M extends keyof ApiViewByIdMethods> {
type: M
field: keyof NonNullable<AsyncReturnType<ApiViewByIdMethods[M]>['data']>
value: string
}
Copy link
Collaborator

@david-crespo david-crespo Jul 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spent some time trying to get the approach that works for useApiQuery to work here — no dice. So annoying.

-interface IdLookupCellProps<M extends keyof ApiViewByIdMethods> {
+interface IdLookupCellProps<A extends ApiViewByIdMethods, M extends keyof A> {
   type: M
-  field: keyof NonNullable<AsyncReturnType<ApiViewByIdMethods[M]>['data']>
+  field: keyof NonNullable<AsyncReturnType<A[M]>['data']>
   value: string
 }
-function IdLookupCell<M extends keyof ApiViewByIdMethods>({
+
+function IdLookupCell<A extends ApiViewByIdMethods, M extends keyof A>({
   type,
   field,
   value,
-}: IdLookupCellProps<M>) {
-  // @ts-expect-error TODO M isn't correctly narrowing the type down
-  const { data } = useApiQuery<M>(type, { id: value })
+}: IdLookupCellProps<A, M>) {
+  const { data } = useApiQuery<M>(type as M, { id: value })
   // @ts-expect-error TODO Because data isn't narrowed correctly above this is an error too
   return (data && <span className="text-default">{data[field]}</span>) || null
 }
 
-export const byIdCell =
-  <M extends keyof ApiViewByIdMethods>(
-    type: IdLookupCellProps<M>['type'],
-    field: IdLookupCellProps<M>['field']
+const getByIdCell =
+  <A extends ApiViewByIdMethods>() =>
+  <M extends keyof A>(
+    type: IdLookupCellProps<A, M>['type'],
+    field: IdLookupCellProps<A, M>['field']
   ) =>
   ({ value }: Cell<string>) => {
     return <IdLookupCell type={type} field={field} value={value} />
   }
+
+export const byIdCell = getByIdCell()

function IdLookupCell<M extends keyof ApiViewByIdMethods>({
type,
field,
value,
}: IdLookupCellProps<M>) {
// @ts-expect-error TODO M isn't correctly narrowing the type down
const { data } = useApiQuery<M>(type, { id: value })
// @ts-expect-error TODO Because data isn't narrowed correctly above this is an error too
return (data && <span className="text-default">{data[field]}</span>) || null
}

export const byIdCell =
<M extends keyof ApiViewByIdMethods>(
type: IdLookupCellProps<M>['type'],
field: IdLookupCellProps<M>['field']
) =>
({ value }: Cell<string>) => {
return <IdLookupCell type={type} field={field} value={value} />
}
1 change: 1 addition & 0 deletions libs/table/cells/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export * from './SizeCell'
export * from './TwoLineCell'
export * from './TypeValueCell'
export * from './TypeValueListCell'
export * from './IdLookupCell'