diff --git a/app/components/RouteTabs.tsx b/app/components/RouteTabs.tsx index b1c0b3b39..8e9e5e7a4 100644 --- a/app/components/RouteTabs.tsx +++ b/app/components/RouteTabs.tsx @@ -84,11 +84,11 @@ export interface TabProps { * able to link directly to the first sidebar tab, but we of course also want * this tab to appear active for all the sidebar tabs. See instance metrics. */ - toPrefix?: string + activePrefix?: string children: ReactNode } -export const Tab = ({ to, toPrefix, children }: TabProps) => { - const isActive = useIsActivePath({ to: toPrefix || to }) +export const Tab = ({ to, activePrefix, children }: TabProps) => { + const isActive = useIsActivePath({ to: activePrefix || to }) return ( ( ) -export const NavLinkItem = (props: { +type NavLinkProps = { to: string children: React.ReactNode end?: boolean disabled?: boolean -}) => { + // Only for cases where we want to spoof the path and pretend 'isActive' + activePrefix?: string +} + +export const NavLinkItem = ({ + to, + children, + end, + disabled, + activePrefix, +}: NavLinkProps) => { // If the current page is the create form for this NavLinkItem's resource, highlight the NavLink in the sidebar - const currentPathIsCreateForm = useLocation().pathname.startsWith(`${props.to}-new`) + const currentPathIsCreateForm = useLocation().pathname.startsWith(`${to}-new`) + // We aren't using NavLink, as we need to occasionally use an activePrefix to create an active state for matching root paths + // so we also recreate the isActive logic here + const isActive = useIsActivePath({ to: activePrefix || to, end }) return (
  • - - cn(linkStyles, { - 'text-accent !bg-accent-secondary hover:!bg-accent-secondary-hover [&>svg]:!text-accent-tertiary': - isActive || currentPathIsCreateForm, - 'pointer-events-none text-disabled': props.disabled, - }) - } - end={props.end} + svg]:!text-accent-tertiary': + isActive || currentPathIsCreateForm, + 'pointer-events-none text-disabled': disabled, + })} + aria-current={isActive ? 'page' : undefined} > - {props.children} - + {children} +
  • ) } diff --git a/app/layouts/SystemLayout.tsx b/app/layouts/SystemLayout.tsx index c85680d7b..df120206b 100644 --- a/app/layouts/SystemLayout.tsx +++ b/app/layouts/SystemLayout.tsx @@ -22,7 +22,7 @@ import { TopBar } from '~/components/TopBar' import { useCurrentUser } from '~/hooks/use-current-user' import { useQuickActions } from '~/hooks/use-quick-actions' import { Divider } from '~/ui/lib/Divider' -import { pb } from '~/util/path-builder' +import { inventoryBase, pb } from '~/util/path-builder' import { ContentPane, PageContainer } from './helpers' @@ -102,7 +102,7 @@ export default function SystemLayout() { Utilization - + Inventory diff --git a/app/pages/project/instances/InstancePage.tsx b/app/pages/project/instances/InstancePage.tsx index 861a1553d..22e1ded89 100644 --- a/app/pages/project/instances/InstancePage.tsx +++ b/app/pages/project/instances/InstancePage.tsx @@ -258,7 +258,7 @@ export default function InstancePage() { Networking Metrics diff --git a/app/pages/system/inventory/SledsTab.tsx b/app/pages/system/inventory/SledsTab.tsx index 68b94f344..3358a78d8 100644 --- a/app/pages/system/inventory/SledsTab.tsx +++ b/app/pages/system/inventory/SledsTab.tsx @@ -40,7 +40,7 @@ export const handle = { crumb: 'Sleds' } const colHelper = createColumnHelper() const staticCols = [ colHelper.accessor('id', { - cell: makeLinkCell((sledId) => pb.sled({ sledId })), + cell: makeLinkCell((sledId) => pb.sledInstances({ sledId })), }), // TODO: colHelper.accessor('baseboard.serviceAddress', { header: 'service address' }), colHelper.group({ diff --git a/app/pages/system/inventory/sled/SledPage.tsx b/app/pages/system/inventory/sled/SledPage.tsx index fd90de5f1..116961691 100644 --- a/app/pages/system/inventory/sled/SledPage.tsx +++ b/app/pages/system/inventory/sled/SledPage.tsx @@ -28,7 +28,7 @@ export async function clientLoader({ params }: LoaderFunctionArgs) { } export const handle = makeCrumb( (p) => truncate(p.sledId!, 12, 'middle'), - (p) => pb.sled({ sledId: p.sledId! }) + (p) => pb.sledInstances({ sledId: p.sledId! }) ) export default function SledPage() { diff --git a/app/util/__snapshots__/path-builder.spec.ts.snap b/app/util/__snapshots__/path-builder.spec.ts.snap index 18627378c..1efaa684a 100644 --- a/app/util/__snapshots__/path-builder.spec.ts.snap +++ b/app/util/__snapshots__/path-builder.spec.ts.snap @@ -529,24 +529,6 @@ exports[`breadcrumbs 2`] = ` "path": "/system/silos", }, ], - "sled (/system/inventory/sleds/5c56b522-c9b8-49e4-9f9a-8d52a89ec3e0/instances)": [ - { - "label": "Inventory", - "path": "/system/inventory", - }, - { - "label": "Sleds", - "path": "/system/inventory/sleds", - }, - { - "label": "5c56b…ec3e0", - "path": "/system/inventory/sleds/5c56b522-c9b8-49e4-9f9a-8d52a89ec3e0/instances", - }, - { - "label": "Instances", - "path": "/system/inventory/sleds/5c56b522-c9b8-49e4-9f9a-8d52a89ec3e0/instances", - }, - ], "sledInstances (/system/inventory/sleds/5c56b522-c9b8-49e4-9f9a-8d52a89ec3e0/instances)": [ { "label": "Inventory", diff --git a/app/util/path-builder.spec.ts b/app/util/path-builder.spec.ts index cbdb90fb9..65744284d 100644 --- a/app/util/path-builder.spec.ts +++ b/app/util/path-builder.spec.ts @@ -81,7 +81,6 @@ test('path builder', () => { "siloUtilization": "/utilization", "silos": "/system/silos", "silosNew": "/system/silos-new", - "sled": "/system/inventory/sleds/5c56b522-c9b8-49e4-9f9a-8d52a89ec3e0/instances", "sledInstances": "/system/inventory/sleds/5c56b522-c9b8-49e4-9f9a-8d52a89ec3e0/instances", "sledInventory": "/system/inventory/sleds", "snapshotImagesNew": "/projects/p/snapshots/sn/images-new", diff --git a/app/util/path-builder.ts b/app/util/path-builder.ts index 1e65f73fa..19c088773 100644 --- a/app/util/path-builder.ts +++ b/app/util/path-builder.ts @@ -15,9 +15,10 @@ const instanceBase = ({ project, instance }: PP.Instance) => `${pb.instances({ project })}/${instance}` const vpcBase = ({ project, vpc }: PP.Vpc) => `${pb.vpcs({ project })}/${vpc}` -/** Don't use this for links. only exported for use as toPrefix on metrics tab */ +/** Don't use these for links. only exported for use with activePrefix */ export const instanceMetricsBase = ({ project, instance }: PP.Instance) => `${instanceBase({ project, instance })}/metrics` +export const inventoryBase = () => '/system/inventory' export const pb = { projects: () => `/projects`, @@ -109,10 +110,9 @@ export const pb = { 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 }: PP.Sled) => `/system/inventory/sleds/${sledId}/instances`, - sledInstances: ({ sledId }: PP.Sled) => `/system/inventory/sleds/${sledId}/instances`, + sledInventory: () => `${inventoryBase()}/sleds`, + diskInventory: () => `${inventoryBase()}/disks`, + sledInstances: ({ sledId }: PP.Sled) => `${pb.sledInventory()}/${sledId}/instances`, silos: () => '/system/silos', silosNew: () => '/system/silos-new',