diff --git a/app/components/form/fields/SshKeysField.tsx b/app/components/form/fields/SshKeysField.tsx
index 7f5cea2f30..f177b9a3ac 100644
--- a/app/components/form/fields/SshKeysField.tsx
+++ b/app/components/form/fields/SshKeysField.tsx
@@ -12,7 +12,7 @@ import { usePrefetchedApiQuery } from '@oxide/api'
import { Key16Icon } from '@oxide/design-system/icons/react'
import type { InstanceCreateInput } from '~/forms/instance-create'
-import { CreateSSHKeySideModalForm } from '~/forms/ssh-key-create'
+import { Component as CreateSSHKeySideModalForm } from '~/forms/ssh-key-create'
import { Button } from '~/ui/lib/Button'
import { Checkbox } from '~/ui/lib/Checkbox'
import { Divider } from '~/ui/lib/Divider'
diff --git a/app/forms/image-edit.tsx b/app/forms/image-edit.tsx
index 11d1c7929f..81cfb761cb 100644
--- a/app/forms/image-edit.tsx
+++ b/app/forms/image-edit.tsx
@@ -29,13 +29,25 @@ import { pb } from '~/util/path-builder'
import { capitalize } from '~/util/str'
import { bytesToGiB } from '~/util/units'
-EditProjectImageSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => {
- const { project, image } = getProjectImageSelector(params)
- await apiQueryClient.prefetchQuery('imageView', { path: { image }, query: { project } })
- return null
+export const ProjectImageEdit = {
+ loader: async ({ params }: LoaderFunctionArgs) => {
+ const { project, image } = getProjectImageSelector(params)
+ await apiQueryClient.prefetchQuery('imageView', { path: { image }, query: { project } })
+ return null
+ },
+ Component: EditProjectImageSideModalForm,
}
-export function EditProjectImageSideModalForm() {
+export const SiloImageEdit = {
+ loader: async ({ params }: LoaderFunctionArgs) => {
+ const { image } = getSiloImageSelector(params)
+ await apiQueryClient.prefetchQuery('imageView', { path: { image } })
+ return null
+ },
+ Component: EditSiloImageSideModalForm,
+}
+
+function EditProjectImageSideModalForm() {
const { project, image } = useProjectImageSelector()
const { data } = usePrefetchedApiQuery('imageView', {
path: { image },
@@ -46,20 +58,14 @@ export function EditProjectImageSideModalForm() {
return
}
-EditSiloImageSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => {
- const { image } = getSiloImageSelector(params)
- await apiQueryClient.prefetchQuery('imageView', { path: { image } })
- return null
-}
-
-export function EditSiloImageSideModalForm() {
+function EditSiloImageSideModalForm() {
const { image } = useSiloImageSelector()
const { data } = usePrefetchedApiQuery('imageView', { path: { image } })
return
}
-export function EditImageSideModalForm({
+function EditImageSideModalForm({
image,
dismissLink,
type,
diff --git a/app/forms/image-upload.tsx b/app/forms/image-upload.tsx
index b7b7dbbbe8..34a2165f1a 100644
--- a/app/forms/image-upload.tsx
+++ b/app/forms/image-upload.tsx
@@ -177,10 +177,11 @@ const CHUNK_SIZE_BYTES = 512 * KiB
// TODO: make sure cleanup, cancelEverything, and resetMainFlow are called in
// the right places
+Component.displayName = 'ImageCreate'
/**
* Upload an image. Opens a second modal to show upload progress.
*/
-export function CreateImageSideModalForm() {
+export function Component() {
const navigate = useNavigate()
const queryClient = useApiQueryClient()
const { project } = useProjectSelector()
diff --git a/app/forms/ip-pool-edit.tsx b/app/forms/ip-pool-edit.tsx
index cbd0b7db7d..e917101996 100644
--- a/app/forms/ip-pool-edit.tsx
+++ b/app/forms/ip-pool-edit.tsx
@@ -25,13 +25,14 @@ import { pb } from '~/util/path-builder'
import { IpPoolVisibilityMessage } from './ip-pool-create'
-EditIpPoolSideModalForm.loader = async ({ params }: LoaderFunctionArgs) => {
+export async function loader({ params }: LoaderFunctionArgs) {
const { pool } = getIpPoolSelector(params)
await apiQueryClient.prefetchQuery('ipPoolView', { path: { pool } })
return null
}
-export function EditIpPoolSideModalForm() {
+Component.displayName = 'EditIpPoolSideModalForm'
+export function Component() {
const queryClient = useApiQueryClient()
const navigate = useNavigate()
const poolSelector = useIpPoolSelector()
diff --git a/app/forms/ip-pool-range-add.tsx b/app/forms/ip-pool-range-add.tsx
index b5cb0488e0..3183656262 100644
--- a/app/forms/ip-pool-range-add.tsx
+++ b/app/forms/ip-pool-range-add.tsx
@@ -59,7 +59,8 @@ function resolver(values: IpRange) {
return Object.keys(errors).length > 0 ? { values: {}, errors } : { values, errors: {} }
}
-export function IpPoolAddRangeSideModalForm() {
+Component.displayName = 'IpPoolAddRange'
+export function Component() {
const { pool } = useIpPoolSelector()
const navigate = useNavigate()
const queryClient = useApiQueryClient()
diff --git a/app/forms/project-create.tsx b/app/forms/project-create.tsx
index faaee13df7..6616c641de 100644
--- a/app/forms/project-create.tsx
+++ b/app/forms/project-create.tsx
@@ -22,7 +22,8 @@ const defaultValues: ProjectCreate = {
description: '',
}
-export function CreateProjectSideModalForm() {
+Component.displayName = 'ProjectCreateSideModalForm'
+export function Component() {
const navigate = useNavigate()
const queryClient = useApiQueryClient()
diff --git a/app/forms/snapshot-create.tsx b/app/forms/snapshot-create.tsx
index 3ad4c448f0..7424770a44 100644
--- a/app/forms/snapshot-create.tsx
+++ b/app/forms/snapshot-create.tsx
@@ -42,7 +42,8 @@ const defaultValues: SnapshotCreate = {
name: '',
}
-export function CreateSnapshotSideModalForm() {
+Component.displayName = 'SnapshotCreate'
+export function Component() {
const queryClient = useApiQueryClient()
const projectSelector = useProjectSelector()
const navigate = useNavigate()
diff --git a/app/forms/ssh-key-create.tsx b/app/forms/ssh-key-create.tsx
index 82ba183e23..d3c0f68c95 100644
--- a/app/forms/ssh-key-create.tsx
+++ b/app/forms/ssh-key-create.tsx
@@ -29,7 +29,8 @@ type Props = {
message?: React.ReactNode
}
-export function CreateSSHKeySideModalForm({ onDismiss, message }: Props) {
+Component.displayName = 'SSHKeyCreate'
+export function Component({ onDismiss, message }: Props) {
const queryClient = useApiQueryClient()
const navigate = useNavigate()
diff --git a/app/forms/vpc-router-create.tsx b/app/forms/vpc-router-create.tsx
index 3d08d456cc..743685312c 100644
--- a/app/forms/vpc-router-create.tsx
+++ b/app/forms/vpc-router-create.tsx
@@ -23,7 +23,8 @@ const defaultValues: VpcRouterCreate = {
description: '',
}
-export function CreateRouterSideModalForm() {
+Component.displayName = 'RouterCreate'
+export function Component() {
const queryClient = useApiQueryClient()
const vpcSelector = useVpcSelector()
const navigate = useNavigate()
diff --git a/app/hooks/use-crumbs.ts b/app/hooks/use-crumbs.ts
index 898d9f094d..519a614561 100644
--- a/app/hooks/use-crumbs.ts
+++ b/app/hooks/use-crumbs.ts
@@ -34,7 +34,8 @@ type MatchWithCrumb = UIMatch
type MakeStr = string | ((p: Params) => string)
/** Helper to make crumb definitions less verbose */
-export const makeCrumb = (crumb: MakeStr, path?: MakeStr) => ({ crumb, path })
+export const makeCrumb = (crumb: MakeStr, path?: MakeStr): Crumb => ({ crumb, path })
+export const titleCrumb = (crumb: string): Crumb => ({ crumb, titleOnly: true })
function hasCrumb(m: UIMatch): m is MatchWithCrumb {
return !!(m.handle && typeof m.handle === 'object' && 'crumb' in m.handle)
diff --git a/app/layouts/SystemLayout.tsx b/app/layouts/SystemLayout.tsx
index 9d5ad97ffa..e58cb5cab8 100644
--- a/app/layouts/SystemLayout.tsx
+++ b/app/layouts/SystemLayout.tsx
@@ -34,7 +34,7 @@ import { ContentPane, PageContainer } from './helpers'
* error. We're being a little cavalier here with the error. If it's something
* other than a 403, that would be strange and we would want to know.
*/
-SystemLayout.loader = async () => {
+export async function loader() {
// we don't need to use the ErrorsAllowed version here because we're 404ing
// immediately on error, so we don't need to pick the result up from the cache
const isFleetViewer = await apiQueryClient
@@ -49,7 +49,8 @@ SystemLayout.loader = async () => {
return null
}
-export function SystemLayout() {
+Component.displayName = 'SystemLayout'
+export function Component() {
// Only show silo picker if we are looking at a particular silo. The more
// robust way of doing this would be to make a separate layout for the
// silo-specific routes in the route config, but it's overkill considering
diff --git a/app/pages/ProjectsPage.tsx b/app/pages/ProjectsPage.tsx
index 32b749a91e..7a43282554 100644
--- a/app/pages/ProjectsPage.tsx
+++ b/app/pages/ProjectsPage.tsx
@@ -42,7 +42,7 @@ const EmptyState = () => (
/>
)
-ProjectsPage.loader = async () => {
+export async function loader() {
await apiQueryClient.prefetchQuery('projectList', { query: { limit: PAGE_SIZE } })
return null
}
@@ -56,7 +56,8 @@ const staticCols = [
colHelper.accessor('timeCreated', Columns.timeCreated),
]
-export function ProjectsPage() {
+Component.displayName = 'ProjectsPage'
+export function Component() {
const navigate = useNavigate()
const queryClient = useApiQueryClient()
diff --git a/app/pages/SiloAccessPage.tsx b/app/pages/SiloAccessPage.tsx
index ad9060a622..3eabc68f75 100644
--- a/app/pages/SiloAccessPage.tsx
+++ b/app/pages/SiloAccessPage.tsx
@@ -52,7 +52,7 @@ const EmptyState = ({ onClick }: { onClick: () => void }) => (
)
-SiloAccessPage.loader = async () => {
+export async function loader() {
await Promise.all([
apiQueryClient.prefetchQuery('policyView', {}),
// used to resolve user names
@@ -72,7 +72,8 @@ type UserRow = {
const colHelper = createColumnHelper()
-export function SiloAccessPage() {
+Component.displayName = 'SiloAccessPage'
+export function Component() {
const [addModalOpen, setAddModalOpen] = useState(false)
const [editingUserRow, setEditingUserRow] = useState(null)
diff --git a/app/pages/SiloUtilizationPage.tsx b/app/pages/SiloUtilizationPage.tsx
index ade4ff1a1a..2ab2eaf68d 100644
--- a/app/pages/SiloUtilizationPage.tsx
+++ b/app/pages/SiloUtilizationPage.tsx
@@ -26,7 +26,7 @@ import { bytesToGiB, bytesToTiB } from '~/util/units'
const toListboxItem = (x: { name: string; id: string }) => ({ label: x.name, value: x.id })
-SiloUtilizationPage.loader = async () => {
+export async function loader() {
await Promise.all([
apiQueryClient.prefetchQuery('projectList', {}),
apiQueryClient.prefetchQuery('utilizationView', {}),
@@ -34,7 +34,8 @@ SiloUtilizationPage.loader = async () => {
return null
}
-export function SiloUtilizationPage() {
+Component.displayName = 'SiloUtilizationPage'
+export function Component() {
const { me } = useCurrentUser()
const siloId = me.siloId
diff --git a/app/pages/project/access/ProjectAccessPage.tsx b/app/pages/project/access/ProjectAccessPage.tsx
index 05173294af..e68d5497b7 100644
--- a/app/pages/project/access/ProjectAccessPage.tsx
+++ b/app/pages/project/access/ProjectAccessPage.tsx
@@ -59,7 +59,7 @@ const EmptyState = ({ onClick }: { onClick: () => void }) => (
)
-ProjectAccessPage.loader = async ({ params }: LoaderFunctionArgs) => {
+export async function loader({ params }: LoaderFunctionArgs) {
const { project } = getProjectSelector(params)
await Promise.all([
apiQueryClient.prefetchQuery('policyView', {}),
@@ -81,7 +81,8 @@ type UserRow = {
const colHelper = createColumnHelper()
-export function ProjectAccessPage() {
+Component.displayName = 'ProjectAccessPage'
+export function Component() {
const [addModalOpen, setAddModalOpen] = useState(false)
const [editingUserRow, setEditingUserRow] = useState(null)
const { project } = useProjectSelector()
diff --git a/app/pages/project/instances/instance/SerialConsolePage.tsx b/app/pages/project/instances/instance/SerialConsolePage.tsx
index a09c84577a..d8b71a69c8 100644
--- a/app/pages/project/instances/instance/SerialConsolePage.tsx
+++ b/app/pages/project/instances/instance/SerialConsolePage.tsx
@@ -44,7 +44,7 @@ const statusMessage: Record = {
error: 'error',
}
-SerialConsolePage.loader = async ({ params }: LoaderFunctionArgs) => {
+export async function loader({ params }: LoaderFunctionArgs) {
const { project, instance } = getInstanceSelector(params)
await apiQueryClient.prefetchQuery('instanceView', {
path: { instance },
@@ -57,7 +57,8 @@ function isStarting(i: Instance | undefined) {
return i?.runState === 'creating' || i?.runState === 'starting'
}
-export function SerialConsolePage() {
+Component.displayName = 'SerialConsolePage'
+export function Component() {
const instanceSelector = useInstanceSelector()
const { project, instance } = instanceSelector
diff --git a/app/pages/project/instances/instance/tabs/ConnectTab.tsx b/app/pages/project/instances/instance/tabs/ConnectTab.tsx
index 71b07990dc..b57d924182 100644
--- a/app/pages/project/instances/instance/tabs/ConnectTab.tsx
+++ b/app/pages/project/instances/instance/tabs/ConnectTab.tsx
@@ -18,7 +18,7 @@ import { cliCmd } from '~/util/cli-cmd'
import { links } from '~/util/links'
import { pb } from '~/util/path-builder'
-ConnectTab.loader = async ({ params }: LoaderFunctionArgs) => {
+export async function loader({ params }: LoaderFunctionArgs) {
const { project, instance } = getInstanceSelector(params)
await apiQueryClient.prefetchQuery('instanceExternalIpList', {
path: { instance },
@@ -27,7 +27,8 @@ ConnectTab.loader = async ({ params }: LoaderFunctionArgs) => {
return null
}
-export function ConnectTab() {
+Component.displayName = 'ConnectTab'
+export function Component() {
const { project, instance } = useInstanceSelector()
const { data: externalIps } = usePrefetchedApiQuery('instanceExternalIpList', {
path: { instance },
diff --git a/app/pages/project/instances/instance/tabs/MetricsTab.tsx b/app/pages/project/instances/instance/tabs/MetricsTab.tsx
index 20fc68b853..aa3f76dcaa 100644
--- a/app/pages/project/instances/instance/tabs/MetricsTab.tsx
+++ b/app/pages/project/instances/instance/tabs/MetricsTab.tsx
@@ -150,7 +150,7 @@ function DiskMetric({
// Considering the data is going to be swapped out as soon as they change the
// date range, I'm inclined to punt.
-MetricsTab.loader = async ({ params }: LoaderFunctionArgs) => {
+export async function loader({ params }: LoaderFunctionArgs) {
const { project, instance } = getInstanceSelector(params)
await apiQueryClient.prefetchQuery('instanceDiskList', {
path: { instance },
@@ -159,7 +159,8 @@ MetricsTab.loader = async ({ params }: LoaderFunctionArgs) => {
return null
}
-export function MetricsTab() {
+Component.displayName = 'MetricsTab'
+export function Component() {
const { project, instance } = useInstanceSelector()
const { data } = usePrefetchedApiQuery('instanceDiskList', {
path: { instance },
diff --git a/app/pages/project/instances/instance/tabs/NetworkingTab.tsx b/app/pages/project/instances/instance/tabs/NetworkingTab.tsx
index d1d8c11431..a9ea921675 100644
--- a/app/pages/project/instances/instance/tabs/NetworkingTab.tsx
+++ b/app/pages/project/instances/instance/tabs/NetworkingTab.tsx
@@ -83,7 +83,7 @@ const SubnetNameFromId = ({ value }: { value: string }) => {
return {subnet.name}
}
-NetworkingTab.loader = async ({ params }: LoaderFunctionArgs) => {
+export async function loader({ params }: LoaderFunctionArgs) {
const { project, instance } = getInstanceSelector(params)
await Promise.all([
apiQueryClient.prefetchQuery('instanceNetworkInterfaceList', {
@@ -177,7 +177,8 @@ const staticIpCols = [
}),
]
-export function NetworkingTab() {
+Component.displayName = 'NetworkingTab'
+export function Component() {
const instanceSelector = useInstanceSelector()
const { instance: instanceName, project } = instanceSelector
diff --git a/app/pages/project/instances/instance/tabs/StorageTab.tsx b/app/pages/project/instances/instance/tabs/StorageTab.tsx
index dbac4b0f67..1850907363 100644
--- a/app/pages/project/instances/instance/tabs/StorageTab.tsx
+++ b/app/pages/project/instances/instance/tabs/StorageTab.tsx
@@ -41,7 +41,7 @@ import { links } from '~/util/links'
import { fancifyStates } from './common'
-StorageTab.loader = async ({ params }: LoaderFunctionArgs) => {
+export async function loader({ params }: LoaderFunctionArgs) {
const { project, instance } = getInstanceSelector(params)
const selector = { path: { instance }, query: { project } }
await Promise.all([
@@ -75,7 +75,8 @@ const staticCols = [
colHelper.accessor('timeCreated', Columns.timeCreated),
]
-export function StorageTab() {
+Component.displayName = 'StorageTab'
+export function Component() {
const [showDiskCreate, setShowDiskCreate] = useState(false)
const [showDiskAttach, setShowDiskAttach] = useState(false)
diff --git a/app/pages/project/vpcs/RouterPage.tsx b/app/pages/project/vpcs/RouterPage.tsx
index 1374602b31..b1aae9edce 100644
--- a/app/pages/project/vpcs/RouterPage.tsx
+++ b/app/pages/project/vpcs/RouterPage.tsx
@@ -41,7 +41,7 @@ import { TableControls, TableTitle } from '~/ui/lib/Table'
import { docLinks } from '~/util/links'
import { pb } from '~/util/path-builder'
-RouterPage.loader = async function ({ params }: LoaderFunctionArgs) {
+export async function loader({ params }: LoaderFunctionArgs) {
const { project, vpc, router } = getVpcRouterSelector(params)
await Promise.all([
apiQueryClient.prefetchQuery('vpcRouterView', {
@@ -80,7 +80,8 @@ const RouterRouteTypeValueBadge = ({
)
}
-export function RouterPage() {
+Component.displayName = 'RouterPage'
+export function Component() {
const { project, vpc, router } = useVpcRouterSelector()
const { data: routerData } = usePrefetchedApiQuery('vpcRouterView', {
path: { router },
diff --git a/app/pages/project/vpcs/VpcPage/tabs/VpcRoutersTab.tsx b/app/pages/project/vpcs/VpcPage/tabs/VpcRoutersTab.tsx
index cd411c4c90..4f1bc835c7 100644
--- a/app/pages/project/vpcs/VpcPage/tabs/VpcRoutersTab.tsx
+++ b/app/pages/project/vpcs/VpcPage/tabs/VpcRoutersTab.tsx
@@ -26,7 +26,7 @@ import { pb } from '~/util/path-builder'
const colHelper = createColumnHelper()
-VpcRoutersTab.loader = async ({ params }: LoaderFunctionArgs) => {
+export async function loader({ params }: LoaderFunctionArgs) {
const { project, vpc } = getVpcSelector(params)
await apiQueryClient.prefetchQuery('vpcRouterList', {
query: { project, vpc, limit: PAGE_SIZE },
@@ -34,7 +34,8 @@ VpcRoutersTab.loader = async ({ params }: LoaderFunctionArgs) => {
return null
}
-export function VpcRoutersTab() {
+Component.displayName = 'VpcRoutersTab'
+export function Component() {
const vpcSelector = useVpcSelector()
const navigate = useNavigate()
const { project, vpc } = vpcSelector
diff --git a/app/pages/project/vpcs/VpcPage/tabs/VpcSubnetsTab.tsx b/app/pages/project/vpcs/VpcPage/tabs/VpcSubnetsTab.tsx
index 0dcb974a19..253f98b871 100644
--- a/app/pages/project/vpcs/VpcPage/tabs/VpcSubnetsTab.tsx
+++ b/app/pages/project/vpcs/VpcPage/tabs/VpcSubnetsTab.tsx
@@ -31,7 +31,7 @@ import { pb } from '~/util/path-builder'
const colHelper = createColumnHelper()
-VpcSubnetsTab.loader = async ({ params }: LoaderFunctionArgs) => {
+export async function loader({ params }: LoaderFunctionArgs) {
const { project, vpc } = getVpcSelector(params)
await apiQueryClient.prefetchQuery('vpcSubnetList', {
query: { project, vpc, limit: PAGE_SIZE },
@@ -39,7 +39,8 @@ VpcSubnetsTab.loader = async ({ params }: LoaderFunctionArgs) => {
return null
}
-export function VpcSubnetsTab() {
+Component.displayName = 'VpcSubnetsTab'
+export function Component() {
const vpcSelector = useVpcSelector()
const queryClient = useApiQueryClient()
diff --git a/app/pages/settings/SSHKeysPage.tsx b/app/pages/settings/SSHKeysPage.tsx
index 3b2fd881c8..39735134dc 100644
--- a/app/pages/settings/SSHKeysPage.tsx
+++ b/app/pages/settings/SSHKeysPage.tsx
@@ -26,7 +26,7 @@ import { TableActions } from '~/ui/lib/Table'
import { docLinks } from '~/util/links'
import { pb } from '~/util/path-builder'
-SSHKeysPage.loader = async () => {
+export async function loader() {
await apiQueryClient.prefetchQuery('currentUserSshKeyList', {
query: { limit: PAGE_SIZE },
})
@@ -40,7 +40,8 @@ const staticCols = [
colHelper.accessor('timeModified', Columns.timeModified),
]
-export function SSHKeysPage() {
+Component.displayName = 'SSHKeysPage'
+export function Component() {
const navigate = useNavigate()
const { Table } = useQueryTable('currentUserSshKeyList', {})
diff --git a/app/pages/system/SiloImagesPage.tsx b/app/pages/system/SiloImagesPage.tsx
index 2346153936..27dacff831 100644
--- a/app/pages/system/SiloImagesPage.tsx
+++ b/app/pages/system/SiloImagesPage.tsx
@@ -48,7 +48,7 @@ const EmptyState = () => (
/>
)
-SiloImagesPage.loader = async () => {
+export async function loader() {
await apiQueryClient.prefetchQuery('imageList', {
query: { limit: PAGE_SIZE },
})
@@ -65,7 +65,8 @@ const staticCols = [
colHelper.accessor('timeCreated', Columns.timeCreated),
]
-export function SiloImagesPage() {
+Component.displayName = 'SiloImagesPage'
+export function Component() {
const { Table } = useQueryTable('imageList', {})
const [showModal, setShowModal] = useState(false)
const [demoteImage, setDemoteImage] = useState(null)
diff --git a/app/pages/system/UtilizationPage.tsx b/app/pages/system/UtilizationPage.tsx
index 8a1e4a5675..69a5c155d2 100644
--- a/app/pages/system/UtilizationPage.tsx
+++ b/app/pages/system/UtilizationPage.tsx
@@ -35,7 +35,7 @@ import { round } from '~/util/math'
import { pb } from '~/util/path-builder'
import { bytesToGiB, bytesToTiB } from '~/util/units'
-SystemUtilizationPage.loader = async () => {
+export async function loader() {
await Promise.all([
apiQueryClient.prefetchQuery('siloList', {}),
apiQueryClient.prefetchQuery('siloUtilizationList', {}),
@@ -43,7 +43,8 @@ SystemUtilizationPage.loader = async () => {
return null
}
-export function SystemUtilizationPage() {
+Component.displayName = 'SystemUtilizationPage'
+export function Component() {
const { data: siloUtilizationList } = usePrefetchedApiQuery('siloUtilizationList', {})
const { totalAllocated, totalProvisioned } = totalUtilization(siloUtilizationList.items)
diff --git a/app/pages/system/inventory/DisksTab.tsx b/app/pages/system/inventory/DisksTab.tsx
index c11fb3bffc..e029e66f9e 100644
--- a/app/pages/system/inventory/DisksTab.tsx
+++ b/app/pages/system/inventory/DisksTab.tsx
@@ -37,7 +37,7 @@ const EmptyState = () => (
/>
)
-DisksTab.loader = async () => {
+export async function loader() {
await apiQueryClient.prefetchQuery('physicalDiskList', { query: { limit: PAGE_SIZE } })
return null
}
@@ -66,7 +66,8 @@ const staticCols = [
}),
]
-export function DisksTab() {
+Component.displayName = 'DisksTab'
+export function Component() {
const { Table } = useQueryTable('physicalDiskList', {})
return } columns={staticCols} />
}
diff --git a/app/pages/system/inventory/SledsTab.tsx b/app/pages/system/inventory/SledsTab.tsx
index 1dcc3e187f..94b8da375f 100644
--- a/app/pages/system/inventory/SledsTab.tsx
+++ b/app/pages/system/inventory/SledsTab.tsx
@@ -36,7 +36,7 @@ const EmptyState = () => {
)
}
-SledsTab.loader = async () => {
+export async function loader() {
await apiQueryClient.prefetchQuery('sledList', {
query: { limit: PAGE_SIZE },
})
@@ -67,7 +67,8 @@ const staticCols = [
}),
]
-export function SledsTab() {
+Component.displayName = 'SledsTab'
+export function Component() {
const { Table } = useQueryTable('sledList', {}, { placeholderData: (x) => x })
return } columns={staticCols} />
}
diff --git a/app/pages/system/inventory/sled/SledInstancesTab.tsx b/app/pages/system/inventory/sled/SledInstancesTab.tsx
index 2cee238522..8a14da3466 100644
--- a/app/pages/system/inventory/sled/SledInstancesTab.tsx
+++ b/app/pages/system/inventory/sled/SledInstancesTab.tsx
@@ -30,7 +30,7 @@ const EmptyState = () => {
)
}
-SledInstancesTab.loader = async ({ params }: LoaderFunctionArgs) => {
+export async function loader({ params }: LoaderFunctionArgs) {
const { sledId } = requireSledParams(params)
await apiQueryClient.prefetchQuery('sledInstanceList', {
path: { sledId },
@@ -69,7 +69,8 @@ const staticCols = [
colHelper.accessor('timeCreated', Columns.timeCreated),
]
-export function SledInstancesTab() {
+Component.displayName = 'SledInstancesTab'
+export function Component() {
const { sledId } = useSledParams()
const { Table } = useQueryTable(
'sledInstanceList',
diff --git a/app/pages/system/inventory/sled/SledPage.tsx b/app/pages/system/inventory/sled/SledPage.tsx
index 633b5f6b39..91eb8dfe03 100644
--- a/app/pages/system/inventory/sled/SledPage.tsx
+++ b/app/pages/system/inventory/sled/SledPage.tsx
@@ -17,7 +17,7 @@ import { PageHeader, PageTitle } from '~/ui/lib/PageHeader'
import { PropertiesTable } from '~/ui/lib/PropertiesTable'
import { pb } from '~/util/path-builder'
-SledPage.loader = async ({ params }: LoaderFunctionArgs) => {
+export async function loader({ params }: LoaderFunctionArgs) {
const { sledId } = requireSledParams(params)
await apiQueryClient.prefetchQuery('sledView', {
path: { sledId },
@@ -25,7 +25,8 @@ SledPage.loader = async ({ params }: LoaderFunctionArgs) => {
return null
}
-export function SledPage() {
+Component.displayName = 'SledPage'
+export function Component() {
const { sledId } = useSledParams()
const { data: sled } = usePrefetchedApiQuery('sledView', { path: { sledId } })
diff --git a/app/pages/system/networking/IpPoolPage.tsx b/app/pages/system/networking/IpPoolPage.tsx
index a5c44487e7..26f106b8c3 100644
--- a/app/pages/system/networking/IpPoolPage.tsx
+++ b/app/pages/system/networking/IpPoolPage.tsx
@@ -53,7 +53,7 @@ import { pb } from '~/util/path-builder'
const query = { limit: PAGE_SIZE }
-IpPoolPage.loader = async function ({ params }: LoaderFunctionArgs) {
+export async function loader({ params }: LoaderFunctionArgs) {
const { pool } = getIpPoolSelector(params)
await Promise.all([
apiQueryClient.prefetchQuery('ipPoolView', { path: { pool } }),
@@ -73,7 +73,8 @@ IpPoolPage.loader = async function ({ params }: LoaderFunctionArgs) {
return null
}
-export function IpPoolPage() {
+Component.displayName = 'IpPoolPage'
+export function Component() {
const poolSelector = useIpPoolSelector()
const { data: pool } = usePrefetchedApiQuery('ipPoolView', { path: poolSelector })
const { data: ranges } = usePrefetchedApiQuery('ipPoolRangeList', {
diff --git a/app/pages/system/networking/IpPoolsPage.tsx b/app/pages/system/networking/IpPoolsPage.tsx
index eaa8fcf386..a77be45173 100644
--- a/app/pages/system/networking/IpPoolsPage.tsx
+++ b/app/pages/system/networking/IpPoolsPage.tsx
@@ -66,12 +66,13 @@ const staticColumns = [
colHelper.accessor('timeCreated', Columns.timeCreated),
]
-IpPoolsPage.loader = async function () {
+export async function loader() {
await apiQueryClient.prefetchQuery('ipPoolList', { query: { limit: PAGE_SIZE } })
return null
}
-export function IpPoolsPage() {
+Component.displayName = 'IpPoolsPage'
+export function Component() {
const navigate = useNavigate()
const { Table } = useQueryTable('ipPoolList', {})
const { data: pools } = usePrefetchedApiQuery('ipPoolList', {
diff --git a/app/pages/system/silos/SiloPage.tsx b/app/pages/system/silos/SiloPage.tsx
index 65a634a7dd..83b3553eea 100644
--- a/app/pages/system/silos/SiloPage.tsx
+++ b/app/pages/system/silos/SiloPage.tsx
@@ -28,7 +28,7 @@ import { SiloIdpsTab } from './SiloIdpsTab'
import { SiloIpPoolsTab } from './SiloIpPoolsTab'
import { SiloQuotasTab } from './SiloQuotasTab'
-SiloPage.loader = async ({ params }: LoaderFunctionArgs) => {
+export async function loader({ params }: LoaderFunctionArgs) {
const { silo } = getSiloSelector(params)
await Promise.all([
apiQueryClient.prefetchQuery('siloView', { path: { silo } }),
@@ -44,7 +44,8 @@ SiloPage.loader = async ({ params }: LoaderFunctionArgs) => {
return null
}
-export function SiloPage() {
+Component.displayName = 'SiloPage'
+export function Component() {
const siloSelector = useSiloSelector()
const { data: silo } = usePrefetchedApiQuery('siloView', { path: siloSelector })
diff --git a/app/pages/system/silos/SilosPage.tsx b/app/pages/system/silos/SilosPage.tsx
index 7f10b98449..f68655f4f2 100644
--- a/app/pages/system/silos/SilosPage.tsx
+++ b/app/pages/system/silos/SilosPage.tsx
@@ -62,12 +62,13 @@ const staticCols = [
colHelper.accessor('timeCreated', Columns.timeCreated),
]
-SilosPage.loader = async () => {
+export async function loader() {
await apiQueryClient.prefetchQuery('siloList', { query: { limit: PAGE_SIZE } })
return null
}
-export function SilosPage() {
+Component.displayName = 'SilosPage'
+export function Component() {
const navigate = useNavigate()
const { Table } = useQueryTable('siloList', {})
diff --git a/app/routes.tsx b/app/routes.tsx
index 10e8d1b7da..cf6af56e75 100644
--- a/app/routes.tsx
+++ b/app/routes.tsx
@@ -16,30 +16,27 @@ import { CreateFloatingIpSideModalForm } from './forms/floating-ip-create'
import { EditFloatingIpSideModalForm } from './forms/floating-ip-edit'
import { CreateIdpSideModalForm } from './forms/idp/create'
import { EditIdpSideModalForm } from './forms/idp/edit'
-import {
- EditProjectImageSideModalForm,
- EditSiloImageSideModalForm,
-} from './forms/image-edit'
+import { ProjectImageEdit, SiloImageEdit } from './forms/image-edit'
import { CreateImageFromSnapshotSideModalForm } from './forms/image-from-snapshot'
-import { CreateImageSideModalForm } from './forms/image-upload'
+import * as ImageCreate from './forms/image-upload'
import { CreateInstanceForm } from './forms/instance-create'
import { CreateIpPoolSideModalForm } from './forms/ip-pool-create'
-import { EditIpPoolSideModalForm } from './forms/ip-pool-edit'
-import { IpPoolAddRangeSideModalForm } from './forms/ip-pool-range-add'
-import { CreateProjectSideModalForm } from './forms/project-create'
+import * as IpPoolEdit from './forms/ip-pool-edit'
+import * as IpPoolAddRange from './forms/ip-pool-range-add'
+import * as ProjectCreate from './forms/project-create'
import { EditProjectSideModalForm } from './forms/project-edit'
import { CreateSiloSideModalForm } from './forms/silo-create'
-import { CreateSnapshotSideModalForm } from './forms/snapshot-create'
-import { CreateSSHKeySideModalForm } from './forms/ssh-key-create'
+import * as SnapshotCreate from './forms/snapshot-create'
+import * as SSHKeyCreate from './forms/ssh-key-create'
import { CreateSubnetForm } from './forms/subnet-create'
import { EditSubnetForm } from './forms/subnet-edit'
import { CreateVpcSideModalForm } from './forms/vpc-create'
import { EditVpcSideModalForm } from './forms/vpc-edit'
-import { CreateRouterSideModalForm } from './forms/vpc-router-create'
+import * as RouterCreate from './forms/vpc-router-create'
import { EditRouterSideModalForm } from './forms/vpc-router-edit'
import { CreateRouterRouteSideModalForm } from './forms/vpc-router-route-create'
import { EditRouterRouteSideModalForm } from './forms/vpc-router-route-edit'
-import { makeCrumb } from './hooks/use-crumbs'
+import { makeCrumb, titleCrumb } from './hooks/use-crumbs'
import { getInstanceSelector, getProjectSelector, getVpcSelector } from './hooks/use-params'
import { AuthenticatedLayout } from './layouts/AuthenticatedLayout'
import { AuthLayout } from './layouts/AuthLayout'
@@ -49,46 +46,46 @@ import { ProjectLayout } from './layouts/ProjectLayout'
import { RootLayout } from './layouts/RootLayout'
import { SettingsLayout } from './layouts/SettingsLayout'
import { SiloLayout } from './layouts/SiloLayout'
-import { SystemLayout } from './layouts/SystemLayout'
+import * as SystemLayout from './layouts/SystemLayout'
import { DeviceAuthSuccessPage } from './pages/DeviceAuthSuccessPage'
import { DeviceAuthVerifyPage } from './pages/DeviceAuthVerifyPage'
import { LoginPage } from './pages/LoginPage'
import { LoginPageSaml } from './pages/LoginPageSaml'
import { instanceLookupLoader } from './pages/lookups'
-import { ProjectAccessPage } from './pages/project/access/ProjectAccessPage'
+import * as ProjectAccess from './pages/project/access/ProjectAccessPage'
import { DisksPage } from './pages/project/disks/DisksPage'
import { FloatingIpsPage } from './pages/project/floating-ips/FloatingIpsPage'
import { ImagesPage } from './pages/project/images/ImagesPage'
import { InstancePage } from './pages/project/instances/instance/InstancePage'
-import { SerialConsolePage } from './pages/project/instances/instance/SerialConsolePage'
-import { ConnectTab } from './pages/project/instances/instance/tabs/ConnectTab'
-import { MetricsTab } from './pages/project/instances/instance/tabs/MetricsTab'
-import { NetworkingTab } from './pages/project/instances/instance/tabs/NetworkingTab'
-import { StorageTab } from './pages/project/instances/instance/tabs/StorageTab'
+import * as SerialConsole from './pages/project/instances/instance/SerialConsolePage'
+import * as ConnectTab from './pages/project/instances/instance/tabs/ConnectTab'
+import * as MetricsTab from './pages/project/instances/instance/tabs/MetricsTab'
+import * as NetworkingTab from './pages/project/instances/instance/tabs/NetworkingTab'
+import * as StorageTab from './pages/project/instances/instance/tabs/StorageTab'
import { InstancesPage } from './pages/project/instances/InstancesPage'
import { SnapshotsPage } from './pages/project/snapshots/SnapshotsPage'
-import { RouterPage } from './pages/project/vpcs/RouterPage'
+import * as RouterPage from './pages/project/vpcs/RouterPage'
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 * as VpcRoutersTab from './pages/project/vpcs/VpcPage/tabs/VpcRoutersTab'
+import * as VpcSubnetsTab from './pages/project/vpcs/VpcPage/tabs/VpcSubnetsTab'
import { VpcPage } from './pages/project/vpcs/VpcPage/VpcPage'
import { VpcsPage } from './pages/project/vpcs/VpcsPage'
-import { ProjectsPage } from './pages/ProjectsPage'
+import * as Projects from './pages/ProjectsPage'
import { ProfilePage } from './pages/settings/ProfilePage'
-import { SSHKeysPage } from './pages/settings/SSHKeysPage'
-import { SiloAccessPage } from './pages/SiloAccessPage'
-import { SiloUtilizationPage } from './pages/SiloUtilizationPage'
-import { DisksTab } from './pages/system/inventory/DisksTab'
+import * as SSHKeysPage from './pages/settings/SSHKeysPage'
+import * as SiloAccess from './pages/SiloAccessPage'
+import * as SiloUtilization from './pages/SiloUtilizationPage'
+import * as DisksTab from './pages/system/inventory/DisksTab'
import { InventoryPage } from './pages/system/inventory/InventoryPage'
-import { SledInstancesTab } from './pages/system/inventory/sled/SledInstancesTab'
-import { SledPage } from './pages/system/inventory/sled/SledPage'
-import { SledsTab } from './pages/system/inventory/SledsTab'
-import { IpPoolPage } from './pages/system/networking/IpPoolPage'
-import { IpPoolsPage } from './pages/system/networking/IpPoolsPage'
-import { SiloImagesPage } from './pages/system/SiloImagesPage'
-import { SiloPage } from './pages/system/silos/SiloPage'
-import { SilosPage } from './pages/system/silos/SilosPage'
-import { SystemUtilizationPage } from './pages/system/UtilizationPage'
+import * as SledInstances from './pages/system/inventory/sled/SledInstancesTab'
+import * as SledPage from './pages/system/inventory/sled/SledPage'
+import * as SledsTab from './pages/system/inventory/SledsTab'
+import * as IpPool from './pages/system/networking/IpPoolPage'
+import * as IpPools from './pages/system/networking/IpPoolsPage'
+import * as SiloImages from './pages/system/SiloImagesPage'
+import * as SiloPage from './pages/system/silos/SiloPage'
+import * as SilosPage from './pages/system/silos/SilosPage'
+import * as SystemUtilization from './pages/system/UtilizationPage'
import { pb } from './util/path-builder'
export const routes = createRoutesFromElements(
@@ -119,50 +116,32 @@ export const routes = createRoutesFromElements(
>
} />
} handle={{ crumb: 'Profile' }} />
- }
- loader={SSHKeysPage.loader}
- handle={makeCrumb('SSH Keys', pb.sshKeys)}
- >
+
- }
- handle={{ crumb: 'New SSH key', titleOnly: true }}
- />
+
- } loader={SystemLayout.loader}>
- }
- loader={SilosPage.loader}
- handle={makeCrumb('Silos', pb.silos())}
- >
+
+
} />
- }
- loader={SiloPage.loader}
- handle={makeCrumb((p) => p.silo!)}
- >
+ p.silo!)}>
} />
}
loader={EditIdpSideModalForm.loader}
- handle={{ crumb: 'Edit Identity Provider', titleOnly: true }}
+ handle={titleCrumb('Edit Identity Provider')}
/>
}
- loader={SystemUtilizationPage.loader}
+ {...SystemUtilization}
handle={{ crumb: 'Utilization' }}
/>
} loader={SledsTab.loader} />
- }
- handle={{ crumb: 'Sleds' }}
- loader={SledsTab.loader}
- />
- }
- handle={{ crumb: 'Disks' }}
- loader={DisksTab.loader}
- />
+
+
- }
- loader={SledPage.loader}
- // a crumb for the sled ID looks ridiculous, unfortunately
- >
+ {/* a crumb for the sled ID looks ridiculous, unfortunately */}
+
}
- loader={SledInstancesTab.loader}
- />
- }
- loader={SledInstancesTab.loader}
+ loader={SledInstances.loader}
/>
+
} />
- }
- loader={IpPoolsPage.loader}
- handle={{ crumb: 'IP Pools' }}
- >
+
} />
- }
- loader={IpPoolPage.loader}
- handle={makeCrumb((p) => p.pool!)}
- >
- }
- loader={EditIpPoolSideModalForm.loader}
- handle={{ crumb: 'Edit IP pool' }}
- />
- }
- handle={{ crumb: 'Add Range', titleOnly: true }}
- />
+ p.pool!)}>
+
+
@@ -243,25 +185,10 @@ export const routes = createRoutesFromElements(
} />
}>
- }
- loader={SiloImagesPage.loader}
- handle={{ crumb: 'Images' }}
- >
- }
- loader={EditSiloImageSideModalForm.loader}
- handle={{ crumb: 'Edit Image', titleOnly: true }}
- />
+
+
- }
- loader={SiloUtilizationPage.loader}
- handle={{ crumb: 'Utilization' }}
- />
+
{/* let's do both. what could go wrong*/}
{/* these are here instead of under projects because they need to use SiloLayout */}
- }
- >
+
}
- handle={{ crumb: 'New project', titleOnly: true }}
+ {...ProjectCreate}
+ handle={titleCrumb('New project')}
/>
}
loader={EditProjectSideModalForm.loader}
- handle={{ crumb: 'Edit project', titleOnly: true }}
+ handle={titleCrumb('Edit project')}
/>
- }
- loader={SiloAccessPage.loader}
- handle={{ crumb: 'Access' }}
- />
+
{/* PROJECT */}
@@ -317,8 +235,7 @@ export const routes = createRoutesFromElements(
p.instance!)}>
}
+ {...SerialConsole}
handle={{ crumb: 'Serial Console' }}
/>
@@ -352,30 +269,14 @@ export const routes = createRoutesFromElements(
>
} />
} loader={InstancePage.loader}>
+
}
- loader={StorageTab.loader}
- handle={{ crumb: 'Storage' }}
- />
- }
- loader={NetworkingTab.loader}
handle={{ crumb: 'Networking' }}
/>
- }
- loader={MetricsTab.loader}
- handle={{ crumb: 'Metrics' }}
- />
- }
- loader={ConnectTab.loader}
- handle={{ crumb: 'Connect' }}
- />
+
+
@@ -389,7 +290,7 @@ export const routes = createRoutesFromElements(
}
- handle={{ crumb: 'New VPC', titleOnly: true }}
+ handle={titleCrumb('New VPC')}
/>
@@ -427,51 +328,43 @@ export const routes = createRoutesFromElements(
path="firewall-rules-new/:rule?"
element={}
loader={CreateFirewallRuleForm.loader}
- handle={{ crumb: 'New Rule', titleOnly: true }}
+ handle={titleCrumb('New Rule')}
/>
}
loader={EditFirewallRuleForm.loader}
- handle={{ crumb: 'Edit Rule', titleOnly: true }}
+ handle={titleCrumb('Edit Rule')}
/>
- }
- loader={VpcSubnetsTab.loader}
- handle={{ crumb: 'Subnets' }}
- >
+
}
- handle={{ crumb: 'New Subnet', titleOnly: true }}
+ handle={titleCrumb('New Subnet')}
/>
}
loader={EditSubnetForm.loader}
- handle={{ crumb: 'Edit Subnet', titleOnly: true }}
+ handle={titleCrumb('Edit Subnet')}
/>
- }
- handle={{ crumb: 'Routers' }}
- loader={VpcRoutersTab.loader}
- >
+
}
loader={EditRouterSideModalForm.loader}
- handle={{ crumb: 'Edit Router', titleOnly: true }}
+ handle={titleCrumb('Edit Router')}
/>
}
- handle={{ crumb: 'New Router', titleOnly: true }}
+ {...RouterCreate}
+ handle={titleCrumb('New Router')}
/>
@@ -480,25 +373,20 @@ export const routes = createRoutesFromElements(
p.vpc!)}>
- }
- loader={RouterPage.loader}
- handle={makeCrumb((p) => p.router!)}
- >
+ p.router!)}>
}
loader={CreateRouterRouteSideModalForm.loader}
- handle={{ crumb: 'New Route', titleOnly: true }}
+ handle={titleCrumb('New Route')}
/>
}
loader={EditRouterRouteSideModalForm.loader}
- handle={{ crumb: 'Edit Route', titleOnly: true }}
+ handle={titleCrumb('Edit Route')}
/>
@@ -514,13 +402,13 @@ export const routes = createRoutesFromElements(
}
- handle={{ crumb: 'New Floating IP', titleOnly: true }}
+ handle={titleCrumb('New Floating IP')}
/>
}
loader={EditFloatingIpSideModalForm.loader}
- handle={{ crumb: 'Edit Floating IP', titleOnly: true }}
+ handle={titleCrumb('Edit Floating IP')}
/>
@@ -537,7 +425,7 @@ export const routes = createRoutesFromElements(
// literally right there
navigate('../disks')} />
}
- handle={{ crumb: 'New disk', titleOnly: true }}
+ handle={titleCrumb('New disk')}
/>
@@ -549,14 +437,14 @@ export const routes = createRoutesFromElements(
}
- handle={{ crumb: 'New snapshot', titleOnly: true }}
+ {...SnapshotCreate}
+ handle={titleCrumb('New snapshot')}
/>
}
loader={CreateImageFromSnapshotSideModalForm.loader}
- handle={{ crumb: 'Create image from snapshot', titleOnly: true }}
+ handle={titleCrumb('Create image from snapshot')}
/>
@@ -566,24 +454,14 @@ export const routes = createRoutesFromElements(
loader={ImagesPage.loader}
>
- }
- />
+
}
- loader={EditProjectImageSideModalForm.loader}
- handle={{ crumb: 'Edit Image', titleOnly: true }}
+ {...ProjectImageEdit}
+ handle={titleCrumb('Edit Image')}
/>
- }
- loader={ProjectAccessPage.loader}
- handle={{ crumb: 'Access' }}
- />
+