diff --git a/app/api/index.ts b/app/api/index.ts index bb79dc0a58..6952c0e57d 100644 --- a/app/api/index.ts +++ b/app/api/index.ts @@ -19,8 +19,6 @@ export * from './__generated__/Api' export type { ApiTypes } -export * as PathParams from './path-params' - export { ensurePrefetched, PAGE_SIZE, type PaginatedQuery, type ResultsPage } from './hooks' export type { ApiError } from './errors' export { navToLogin } from './nav-to-login' diff --git a/app/api/path-params.ts b/app/api/path-params.ts deleted file mode 100644 index eaeab465aa..0000000000 --- a/app/api/path-params.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 type { Merge } from 'type-fest' - -export type Project = { project?: string } -export type Instance = Merge -export type Disk = Merge -export type Image = Merge -export type SiloImage = { image?: string } -export type NetworkInterface = Merge -export type Snapshot = Merge -export type Vpc = Merge -export type VpcRouter = Merge -export type VpcRouterRoute = Merge -export type VpcSubnet = Merge -export type FirewallRule = Merge -export type Silo = { silo?: string } -export type IdentityProvider = Merge -export type SystemUpdate = { version: string } -export type SshKey = { sshKey: string } -export type Sled = { sledId?: string } -export type IpPool = { pool?: string } -export type FloatingIp = Merge - -export type Id = { id: string } diff --git a/app/api/selectors.ts b/app/api/selectors.ts new file mode 100644 index 0000000000..47275576bb --- /dev/null +++ b/app/api/selectors.ts @@ -0,0 +1,30 @@ +/* + * 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 type { Merge } from 'type-fest' + +export type Project = Readonly<{ project?: string }> +export type Instance = Readonly> +export type Disk = Readonly> +export type Image = Readonly> +export type SiloImage = Readonly<{ image?: string }> +export type NetworkInterface = Readonly> +export type Snapshot = Readonly> +export type Vpc = Readonly> +export type VpcRouter = Readonly> +export type VpcRouterRoute = Readonly> +export type VpcSubnet = Readonly> +export type FirewallRule = Readonly> +export type Silo = Readonly<{ silo?: string }> +export type IdentityProvider = Readonly> +export type SystemUpdate = Readonly<{ version: string }> +export type SshKey = Readonly<{ sshKey: string }> +export type Sled = Readonly<{ sledId?: string }> +export type IpPool = Readonly<{ pool?: string }> +export type FloatingIp = Readonly> + +export type Id = Readonly<{ id: string }> diff --git a/app/components/ExternalIps.tsx b/app/components/ExternalIps.tsx index c066c1727f..eb9e036932 100644 --- a/app/components/ExternalIps.tsx +++ b/app/components/ExternalIps.tsx @@ -11,10 +11,9 @@ import { useApiQuery } from '@oxide/api' import { EmptyCell, SkeletonCell } from '~/table/cells/EmptyCell' import { CopyableIp } from '~/ui/lib/CopyableIp' import { intersperse } from '~/util/array' +import type * as PP from '~/util/path-params' -type InstanceSelector = { project: string; instance: string } - -export function ExternalIps({ project, instance }: InstanceSelector) { +export function ExternalIps({ project, instance }: PP.Instance) { const { data, isPending } = useApiQuery('instanceExternalIpList', { path: { instance }, query: { project }, diff --git a/app/forms/snapshot-create.tsx b/app/forms/snapshot-create.tsx index 7424770a44..a886800709 100644 --- a/app/forms/snapshot-create.tsx +++ b/app/forms/snapshot-create.tsx @@ -14,7 +14,6 @@ import { useApiMutation, useApiQuery, useApiQueryClient, - type PathParams as PP, type SnapshotCreate, } from '@oxide/api' @@ -28,10 +27,11 @@ import { addToast } from '~/stores/toast' import { toComboboxItems } from '~/ui/lib/Combobox' import { ALL_ISH } from '~/util/consts' import { pb } from '~/util/path-builder' +import type * as PP from '~/util/path-params' -const useSnapshotDiskItems = (projectSelector: PP.Project) => { +const useSnapshotDiskItems = ({ project }: PP.Project) => { const { data: disks } = useApiQuery('diskList', { - query: { ...projectSelector, limit: ALL_ISH }, + query: { project, limit: ALL_ISH }, }) return disks?.items.filter(diskCan.snapshot) } diff --git a/app/pages/project/disks/DisksPage.tsx b/app/pages/project/disks/DisksPage.tsx index adaa7e7cce..429530f7d7 100644 --- a/app/pages/project/disks/DisksPage.tsx +++ b/app/pages/project/disks/DisksPage.tsx @@ -37,6 +37,7 @@ import { PageHeader, PageTitle } from '~/ui/lib/PageHeader' import { TableActions } from '~/ui/lib/Table' import { docLinks } from '~/util/links' import { pb } from '~/util/path-builder' +import type * as PP from '~/util/path-params' import { fancifyStates } from '../instances/instance/tabs/common' @@ -50,12 +51,12 @@ const EmptyState = () => ( /> ) -const diskList = (project: string) => getListQFn('diskList', { query: { project } }) +const diskList = (query: PP.Project) => getListQFn('diskList', { query }) DisksPage.loader = async ({ params }: LoaderFunctionArgs) => { const { project } = getProjectSelector(params) await Promise.all([ - queryClient.prefetchQuery(diskList(project).optionsFn()), + queryClient.prefetchQuery(diskList({ project }).optionsFn()), // fetch instances and preload into RQ cache so fetches by ID in // InstanceLinkCell can be mostly instant yet gracefully fall back to @@ -162,7 +163,7 @@ export function DisksPage() { const columns = useColsWithActions(staticCols, makeActions) const { table } = useQueryTable({ - query: diskList(project), + query: diskList({ project }), columns, emptyState: , }) diff --git a/app/pages/project/images/ImagesPage.tsx b/app/pages/project/images/ImagesPage.tsx index 226848230b..736475c1f5 100644 --- a/app/pages/project/images/ImagesPage.tsx +++ b/app/pages/project/images/ImagesPage.tsx @@ -36,6 +36,7 @@ import { PageHeader, PageTitle } from '~/ui/lib/PageHeader' import { TableActions } from '~/ui/lib/Table' import { docLinks } from '~/util/links' import { pb } from '~/util/path-builder' +import type * as PP from '~/util/path-params' const EmptyState = () => ( ( const colHelper = createColumnHelper() -const imageList = (project: string) => getListQFn('imageList', { query: { project } }) +const imageList = (query: PP.Project) => getListQFn('imageList', { query }) ImagesPage.loader = async ({ params }: LoaderFunctionArgs) => { const { project } = getProjectSelector(params) - await queryClient.prefetchQuery(imageList(project).optionsFn()) + await queryClient.prefetchQuery(imageList({ project }).optionsFn()) return null } @@ -103,7 +104,7 @@ export function ImagesPage() { }, [project, makeActions]) const { table } = useQueryTable({ - query: imageList(project), + query: imageList({ project }), columns, emptyState: , }) diff --git a/app/pages/project/vpcs/RouterPage.tsx b/app/pages/project/vpcs/RouterPage.tsx index 33b04d1edd..54304780eb 100644 --- a/app/pages/project/vpcs/RouterPage.tsx +++ b/app/pages/project/vpcs/RouterPage.tsx @@ -43,13 +43,12 @@ import { PropertiesTable } from '~/ui/lib/PropertiesTable' import { TableControls, TableTitle } from '~/ui/lib/Table' import { docLinks } from '~/util/links' import { pb } from '~/util/path-builder' +import type * as PP from '~/util/path-params' -type RouterParams = { project: string; vpc: string; router: string } - -const routerView = ({ project, vpc, router }: RouterParams) => +const routerView = ({ project, vpc, router }: PP.VpcRouter) => apiq('vpcRouterView', { path: { router }, query: { vpc, project } }) -const routeList = (query: RouterParams) => getListQFn('vpcRouterRouteList', { query }) +const routeList = (query: PP.VpcRouter) => getListQFn('vpcRouterRouteList', { query }) export async function loader({ params }: LoaderFunctionArgs) { const routerSelector = getVpcRouterSelector(params) diff --git a/app/pages/project/vpcs/VpcPage/tabs/VpcRoutersTab.tsx b/app/pages/project/vpcs/VpcPage/tabs/VpcRoutersTab.tsx index a91e2aaa73..a7486521ee 100644 --- a/app/pages/project/vpcs/VpcPage/tabs/VpcRoutersTab.tsx +++ b/app/pages/project/vpcs/VpcPage/tabs/VpcRoutersTab.tsx @@ -29,11 +29,11 @@ import { useQueryTable } from '~/table/QueryTable' import { CreateLink } from '~/ui/lib/CreateButton' import { EmptyMessage } from '~/ui/lib/EmptyMessage' import { pb } from '~/util/path-builder' +import type * as PP from '~/util/path-params' const colHelper = createColumnHelper() -const vpcRouterList = (params: { project: string; vpc: string }) => - getListQFn('vpcRouterList', { query: params }) +const vpcRouterList = (query: PP.Vpc) => getListQFn('vpcRouterList', { query }) export async function loader({ params }: LoaderFunctionArgs) { const { project, vpc } = getVpcSelector(params) diff --git a/app/pages/project/vpcs/VpcPage/tabs/VpcSubnetsTab.tsx b/app/pages/project/vpcs/VpcPage/tabs/VpcSubnetsTab.tsx index 754762d774..f3111bb605 100644 --- a/app/pages/project/vpcs/VpcPage/tabs/VpcSubnetsTab.tsx +++ b/app/pages/project/vpcs/VpcPage/tabs/VpcSubnetsTab.tsx @@ -29,11 +29,11 @@ import { useQueryTable } from '~/table/QueryTable' import { CreateLink } from '~/ui/lib/CreateButton' import { EmptyMessage } from '~/ui/lib/EmptyMessage' import { pb } from '~/util/path-builder' +import type * as PP from '~/util/path-params' const colHelper = createColumnHelper() -const subnetList = (params: { project: string; vpc: string }) => - getListQFn('vpcSubnetList', { query: params }) +const subnetList = (params: PP.Vpc) => getListQFn('vpcSubnetList', { query: params }) export async function loader({ params }: LoaderFunctionArgs) { const { project, vpc } = getVpcSelector(params) diff --git a/app/pages/project/vpcs/VpcsPage.tsx b/app/pages/project/vpcs/VpcsPage.tsx index 6cb7a7704a..1b8282a4a4 100644 --- a/app/pages/project/vpcs/VpcsPage.tsx +++ b/app/pages/project/vpcs/VpcsPage.tsx @@ -37,6 +37,7 @@ import { PageHeader, PageTitle } from '~/ui/lib/PageHeader' import { TableActions } from '~/ui/lib/Table' import { docLinks } from '~/util/links' import { pb } from '~/util/path-builder' +import type * as PP from '~/util/path-params' const vpcList = (project: string) => getListQFn('vpcList', { query: { project } }) @@ -59,7 +60,7 @@ export const VpcDocsPopover = () => ( /> ) -const FirewallRuleCount = ({ project, vpc }: { project: string; vpc: string }) => { +const FirewallRuleCount = ({ project, vpc }: PP.Vpc) => { const { data } = useApiQuery('vpcFirewallRulesView', { query: { project, vpc } }) if (!data) return // loading diff --git a/app/util/path-builder.ts b/app/util/path-builder.ts index 2fb132d64a..55439bb067 100644 --- a/app/util/path-builder.ts +++ b/app/util/path-builder.ts @@ -5,48 +5,30 @@ * * Copyright Oxide Computer Company */ -import type { PathParams as PP } from '@oxide/api' - -// TODO: required versions of path params probably belong somewhere else, -// they're useful - -type Project = Required -type Instance = Required -type Vpc = Required -type Silo = Required -type IdentityProvider = Required -type Sled = Required -type Image = Required -type Snapshot = Required -type SiloImage = Required -type IpPool = Required -type FloatingIp = Required -type FirewallRule = Required -type VpcRouter = Required -type VpcRouterRoute = Required -type VpcSubnet = Required +import type * as PP from './path-params.ts' // these are used as the basis for many routes but are not themselves routes we // ever want to link to. so we use this to build the routes but pb.project() is // different (includes /instances) -const projectBase = ({ project }: Project) => `${pb.projects()}/${project}` -const instanceBase = ({ project, instance }: Instance) => +const projectBase = ({ project }: PP.Project) => `${pb.projects()}/${project}` +const instanceBase = ({ project, instance }: PP.Instance) => `${pb.instances({ project })}/${instance}` -const vpcBase = ({ project, vpc }: Vpc) => `${pb.vpcs({ project })}/${vpc}` +const vpcBase = ({ project, vpc }: PP.Vpc) => `${pb.vpcs({ project })}/${vpc}` export const pb = { projects: () => `/projects`, projectsNew: () => `/projects-new`, - project: (params: Project) => `${projectBase(params)}/instances`, - projectEdit: (params: Project) => `${projectBase(params)}/edit`, + project: (params: PP.Project) => `${projectBase(params)}/instances`, + projectEdit: (params: PP.Project) => `${projectBase(params)}/edit`, - projectAccess: (params: Project) => `${projectBase(params)}/access`, - projectImages: (params: Project) => `${projectBase(params)}/images`, - projectImagesNew: (params: Project) => `${projectBase(params)}/images-new`, - projectImageEdit: (params: Image) => `${pb.projectImages(params)}/${params.image}/edit`, + projectAccess: (params: PP.Project) => `${projectBase(params)}/access`, + projectImages: (params: PP.Project) => `${projectBase(params)}/images`, + projectImagesNew: (params: PP.Project) => `${projectBase(params)}/images-new`, + projectImageEdit: (params: PP.Image) => + `${pb.projectImages(params)}/${params.image}/edit`, - instances: (params: Project) => `${projectBase(params)}/instances`, - instancesNew: (params: Project) => `${projectBase(params)}/instances-new`, + instances: (params: PP.Project) => `${projectBase(params)}/instances`, + instancesNew: (params: PP.Project) => `${projectBase(params)}/instances-new`, /** * This route exists as a direct link to the default tab of the instance page. Unfortunately @@ -55,76 +37,77 @@ export const pb = { * * @see https://github.com/oxidecomputer/console/pull/1267#discussion_r1016766205 */ - instance: (params: Instance) => pb.instanceStorage(params), + instance: (params: PP.Instance) => pb.instanceStorage(params), - instanceMetrics: (params: Instance) => `${instanceBase(params)}/metrics`, - instanceStorage: (params: Instance) => `${instanceBase(params)}/storage`, - instanceConnect: (params: Instance) => `${instanceBase(params)}/connect`, - instanceNetworking: (params: Instance) => `${instanceBase(params)}/networking`, - serialConsole: (params: Instance) => `${instanceBase(params)}/serial-console`, + instanceMetrics: (params: PP.Instance) => `${instanceBase(params)}/metrics`, + instanceStorage: (params: PP.Instance) => `${instanceBase(params)}/storage`, + instanceConnect: (params: PP.Instance) => `${instanceBase(params)}/connect`, + instanceNetworking: (params: PP.Instance) => `${instanceBase(params)}/networking`, + serialConsole: (params: PP.Instance) => `${instanceBase(params)}/serial-console`, - disksNew: (params: Project) => `${projectBase(params)}/disks-new`, - disks: (params: Project) => `${projectBase(params)}/disks`, + disksNew: (params: PP.Project) => `${projectBase(params)}/disks-new`, + disks: (params: PP.Project) => `${projectBase(params)}/disks`, - snapshotsNew: (params: Project) => `${projectBase(params)}/snapshots-new`, - snapshots: (params: Project) => `${projectBase(params)}/snapshots`, - snapshotImagesNew: (params: Snapshot) => + snapshotsNew: (params: PP.Project) => `${projectBase(params)}/snapshots-new`, + snapshots: (params: PP.Project) => `${projectBase(params)}/snapshots`, + snapshotImagesNew: (params: PP.Snapshot) => `${projectBase(params)}/snapshots/${params.snapshot}/images-new`, - vpcsNew: (params: Project) => `${projectBase(params)}/vpcs-new`, - vpcs: (params: Project) => `${projectBase(params)}/vpcs`, + vpcsNew: (params: PP.Project) => `${projectBase(params)}/vpcs-new`, + vpcs: (params: PP.Project) => `${projectBase(params)}/vpcs`, // same deal as instance detail: go straight to first tab - vpc: (params: Vpc) => pb.vpcFirewallRules(params), - vpcEdit: (params: Vpc) => `${vpcBase(params)}/edit`, + vpc: (params: PP.Vpc) => pb.vpcFirewallRules(params), + vpcEdit: (params: PP.Vpc) => `${vpcBase(params)}/edit`, - vpcFirewallRules: (params: Vpc) => `${vpcBase(params)}/firewall-rules`, - vpcFirewallRulesNew: (params: Vpc) => `${vpcBase(params)}/firewall-rules-new`, - vpcFirewallRuleClone: (params: FirewallRule) => + vpcFirewallRules: (params: PP.Vpc) => `${vpcBase(params)}/firewall-rules`, + vpcFirewallRulesNew: (params: PP.Vpc) => `${vpcBase(params)}/firewall-rules-new`, + vpcFirewallRuleClone: (params: PP.FirewallRule) => `${pb.vpcFirewallRulesNew(params)}/${params.rule}`, - vpcFirewallRuleEdit: (params: FirewallRule) => + vpcFirewallRuleEdit: (params: PP.FirewallRule) => `${pb.vpcFirewallRules(params)}/${params.rule}/edit`, - vpcRouters: (params: Vpc) => `${vpcBase(params)}/routers`, - vpcRoutersNew: (params: Vpc) => `${vpcBase(params)}/routers-new`, - vpcRouter: (params: VpcRouter) => `${pb.vpcRouters(params)}/${params.router}`, - vpcRouterEdit: (params: VpcRouter) => `${pb.vpcRouter(params)}/edit`, - vpcRouterRouteEdit: (params: VpcRouterRoute) => + vpcRouters: (params: PP.Vpc) => `${vpcBase(params)}/routers`, + vpcRoutersNew: (params: PP.Vpc) => `${vpcBase(params)}/routers-new`, + vpcRouter: (params: PP.VpcRouter) => `${pb.vpcRouters(params)}/${params.router}`, + vpcRouterEdit: (params: PP.VpcRouter) => `${pb.vpcRouter(params)}/edit`, + vpcRouterRouteEdit: (params: PP.VpcRouterRoute) => `${pb.vpcRouter(params)}/routes/${params.route}/edit`, - vpcRouterRoutesNew: (params: VpcRouter) => `${pb.vpcRouter(params)}/routes-new`, - - vpcSubnets: (params: Vpc) => `${vpcBase(params)}/subnets`, - vpcSubnetsNew: (params: Vpc) => `${vpcBase(params)}/subnets-new`, - vpcSubnetsEdit: (params: VpcSubnet) => `${pb.vpcSubnets(params)}/${params.subnet}/edit`, - - floatingIps: (params: Project) => `${projectBase(params)}/floating-ips`, - floatingIpsNew: (params: Project) => `${projectBase(params)}/floating-ips-new`, - floatingIpEdit: (params: FloatingIp) => + vpcRouterRoutesNew: (params: PP.VpcRouter) => `${pb.vpcRouter(params)}/routes-new`, + + vpcSubnets: (params: PP.Vpc) => `${vpcBase(params)}/subnets`, + vpcSubnetsNew: (params: PP.Vpc) => `${vpcBase(params)}/subnets-new`, + vpcSubnetsEdit: (params: PP.VpcSubnet) => + `${pb.vpcSubnets(params)}/${params.subnet}/edit`, + floatingIps: (params: PP.Project) => `${projectBase(params)}/floating-ips`, + floatingIpsNew: (params: PP.Project) => `${projectBase(params)}/floating-ips-new`, + floatingIpEdit: (params: PP.FloatingIp) => `${pb.floatingIps(params)}/${params.floatingIp}/edit`, siloUtilization: () => '/utilization', siloAccess: () => '/access', siloImages: () => '/images', - siloImageEdit: (params: SiloImage) => `${pb.siloImages()}/${params.image}/edit`, + siloImageEdit: (params: PP.SiloImage) => `${pb.siloImages()}/${params.image}/edit`, systemUtilization: () => '/system/utilization', ipPools: () => '/system/networking/ip-pools', ipPoolsNew: () => '/system/networking/ip-pools-new', - ipPool: (params: IpPool) => `${pb.ipPools()}/${params.pool}`, - ipPoolEdit: (params: IpPool) => `${pb.ipPool(params)}/edit`, - ipPoolRangeAdd: (params: IpPool) => `${pb.ipPool(params)}/ranges-add`, + ipPool: (params: PP.IpPool) => `${pb.ipPools()}/${params.pool}`, + ipPoolEdit: (params: PP.IpPool) => `${pb.ipPool(params)}/edit`, + ipPoolRangeAdd: (params: PP.IpPool) => `${pb.ipPool(params)}/ranges-add`, sledInventory: () => '/system/inventory/sleds', diskInventory: () => '/system/inventory/disks', - sled: ({ sledId }: Sled) => `/system/inventory/sleds/${sledId}/instances`, - sledInstances: ({ sledId }: Sled) => `/system/inventory/sleds/${sledId}/instances`, + sled: ({ sledId }: PP.Sled) => `/system/inventory/sleds/${sledId}/instances`, + sledInstances: ({ sledId }: PP.Sled) => `/system/inventory/sleds/${sledId}/instances`, silos: () => '/system/silos', silosNew: () => '/system/silos-new', - silo: ({ silo }: Silo) => `/system/silos/${silo}`, - siloIpPools: (params: Silo) => `${pb.silo(params)}?tab=ip-pools`, - siloIdpsNew: (params: Silo) => `${pb.silo(params)}/idps-new`, - samlIdp: (params: IdentityProvider) => `${pb.silo(params)}/idps/saml/${params.provider}`, + silo: ({ silo }: PP.Silo) => `/system/silos/${silo}`, + siloIpPools: (params: PP.Silo) => `${pb.silo(params)}?tab=ip-pools`, + siloIdpsNew: (params: PP.Silo) => `${pb.silo(params)}/idps-new`, + samlIdp: (params: PP.IdentityProvider) => + `${pb.silo(params)}/idps/saml/${params.provider}`, profile: () => '/settings/profile', sshKeys: () => '/settings/ssh-keys', diff --git a/app/util/path-params.ts b/app/util/path-params.ts new file mode 100644 index 0000000000..2a153512ad --- /dev/null +++ b/app/util/path-params.ts @@ -0,0 +1,26 @@ +/* + * 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 type * as Sel from '~/api/selectors' + +// The path versions simply have all params required + +export type Project = Required +export type Instance = Required +export type Vpc = Required +export type Silo = Required +export type IdentityProvider = Required +export type Sled = Required +export type Image = Required +export type Snapshot = Required +export type SiloImage = Required +export type IpPool = Required +export type FloatingIp = Required +export type FirewallRule = Required +export type VpcRouter = Required +export type VpcRouterRoute = Required +export type VpcSubnet = Required diff --git a/mock-api/msw/db.ts b/mock-api/msw/db.ts index f9e1b26ed7..13efe3d9b5 100644 --- a/mock-api/msw/db.ts +++ b/mock-api/msw/db.ts @@ -10,10 +10,11 @@ import * as R from 'remeda' import { validate as isUuid } from 'uuid' -import type { ApiTypes as Api, PathParams as PP } from '@oxide/api' +import type { ApiTypes as Api } from '@oxide/api' import * as mock from '@oxide/api-mocks' import { json } from '~/api/__generated__/msw-handlers' +import type * as Sel from '~/api/selectors' import { commaSeries } from '~/util/str' import type { Json } from '../json-type' @@ -64,7 +65,7 @@ export const getIpFromPool = (poolName: string | undefined) => { } export const lookup = { - project({ project: id }: PP.Project): Json { + project({ project: id }: Sel.Project): Json { if (!id) throw notFoundErr('no project specified') if (isUuid(id)) return lookupById(db.projects, id) @@ -74,7 +75,7 @@ export const lookup = { return project }, - instance({ instance: id, ...projectSelector }: PP.Instance): Json { + instance({ instance: id, ...projectSelector }: Sel.Instance): Json { if (!id) throw notFoundErr('no instance specified') if (isUuid(id)) { @@ -91,7 +92,7 @@ export const lookup = { networkInterface({ interface: id, ...instanceSelector - }: PP.NetworkInterface): Json { + }: Sel.NetworkInterface): Json { if (!id) throw notFoundErr('no NIC specified') if (isUuid(id)) { @@ -108,7 +109,7 @@ export const lookup = { return nic }, - disk({ disk: id, ...projectSelector }: PP.Disk): Json { + disk({ disk: id, ...projectSelector }: Sel.Disk): Json { if (!id) throw notFoundErr('no disk specified') if (isUuid(id)) { @@ -123,7 +124,7 @@ export const lookup = { return disk }, - floatingIp({ floatingIp: id, ...projectSelector }: PP.FloatingIp): Json { + floatingIp({ floatingIp: id, ...projectSelector }: Sel.FloatingIp): Json { if (!id) throw notFoundErr('no floating IP specified') if (isUuid(id)) { @@ -139,7 +140,7 @@ export const lookup = { return floatingIp }, - snapshot({ snapshot: id, ...projectSelector }: PP.Snapshot): Json { + snapshot({ snapshot: id, ...projectSelector }: Sel.Snapshot): Json { if (!id) throw notFoundErr('no snapshot specified') if (isUuid(id)) { @@ -153,7 +154,7 @@ export const lookup = { return snapshot }, - vpc({ vpc: id, ...projectSelector }: PP.Vpc): Json { + vpc({ vpc: id, ...projectSelector }: Sel.Vpc): Json { if (!id) throw notFoundErr('no VPC specified') if (isUuid(id)) { @@ -167,7 +168,7 @@ export const lookup = { return vpc }, - vpcRouter({ router: id, ...vpcSelector }: PP.VpcRouter): Json { + vpcRouter({ router: id, ...vpcSelector }: Sel.VpcRouter): Json { if (!id) throw notFoundErr('no router specified') if (isUuid(id)) { @@ -184,7 +185,7 @@ export const lookup = { vpcRouterRoute({ route: id, ...routerSelector - }: PP.VpcRouterRoute): Json { + }: Sel.VpcRouterRoute): Json { if (!id) throw notFoundErr('no route specified') if (isUuid(id)) { @@ -200,7 +201,7 @@ export const lookup = { return route }, - vpcSubnet({ subnet: id, ...vpcSelector }: PP.VpcSubnet): Json { + vpcSubnet({ subnet: id, ...vpcSelector }: Sel.VpcSubnet): Json { if (!id) throw notFoundErr('no subnet specified') if (isUuid(id)) { @@ -214,7 +215,7 @@ export const lookup = { return subnet }, - image({ image: id, project: projectId }: PP.Image): Json { + image({ image: id, project: projectId }: Sel.Image): Json { if (!id) throw notFoundErr('no image specified') // We match the API logic: @@ -249,7 +250,7 @@ export const lookup = { if (!image) throw notFoundErr(`image '${id}'`) return image }, - ipPool({ pool: id }: PP.IpPool): Json { + ipPool({ pool: id }: Sel.IpPool): Json { if (!id) throw notFoundErr('no pool specified') if (isUuid(id)) return lookupById(db.ipPools, id) @@ -263,7 +264,7 @@ export const lookup = { ipPoolSiloLink({ pool: poolId, silo: siloId, - }: PP.IpPool & PP.Silo): Json { + }: Sel.IpPool & Sel.Silo): Json { const pool = lookup.ipPool({ pool: poolId }) const silo = lookup.silo({ silo: siloId }) @@ -275,7 +276,7 @@ export const lookup = { return ipPoolSilo }, // unusual because it returns a list, but we need it for multiple endpoints - siloIpPools(path: PP.Silo): Json[] { + siloIpPools(path: Sel.Silo): Json[] { const silo = lookup.silo(path) // effectively join db.ipPools and db.ipPoolSilos on ip_pool_id @@ -294,7 +295,7 @@ export const lookup = { return { ...pool, is_default: link.is_default } }) }, - siloIpPool(path: PP.Silo & PP.IpPool): Json { + siloIpPool(path: Sel.Silo & Sel.IpPool): Json { const silo = lookup.silo(path) const pool = lookup.ipPool(path) @@ -308,7 +309,7 @@ export const lookup = { return { ...pool, is_default: ipPoolSilo.is_default } }, - siloDefaultIpPool(path: PP.Silo): Json { + siloDefaultIpPool(path: Sel.Silo): Json { const silo = lookup.silo(path) const link = db.ipPoolSilos.find((ips) => ips.silo_id === silo.id && ips.is_default) @@ -316,7 +317,7 @@ export const lookup = { return lookupById(db.ipPools, link.ip_pool_id) }, - samlIdp({ provider: id, silo }: PP.IdentityProvider): Json { + samlIdp({ provider: id, silo }: Sel.IdentityProvider): Json { if (!id) throw notFoundErr('no IdP specified') if (isUuid(id)) { @@ -337,7 +338,7 @@ export const lookup = { return dbIdp.provider }, - silo({ silo: id }: PP.Silo): Json { + silo({ silo: id }: Sel.Silo): Json { if (!id) throw notFoundErr('silo not specified') if (isUuid(id)) return lookupById(db.silos, id) @@ -346,17 +347,17 @@ export const lookup = { if (!silo) throw notFoundErr(`silo '${id}'`) return silo }, - siloQuotas(params: PP.Silo): Json { + siloQuotas(params: Sel.Silo): Json { const silo = lookup.silo(params) const quotas = db.siloQuotas.find((q) => q.silo_id === silo.id) if (!quotas) throw internalError(`Silo ${silo.name} has no quotas`) return quotas }, - sled({ sledId: id }: PP.Sled): Json { + sled({ sledId: id }: Sel.Sled): Json { if (!id) throw notFoundErr('sled not specified') return lookupById(db.sleds, id) }, - sshKey({ sshKey: id }: PP.SshKey): Json { + sshKey({ sshKey: id }: Sel.SshKey): Json { // we don't have a concept of mock session. assume the user is user1 const userSshKeys = db.sshKeys.filter((key) => key.silo_user_id === mock.user1.id)