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' }} - /> +