Stop retired routes highlighting primary nav

This commit is contained in:
rcourtman
2026-04-29 17:47:42 +01:00
parent df3ab06174
commit cd546b8a8e
5 changed files with 55 additions and 4 deletions
@@ -1733,6 +1733,12 @@ route-level data orchestration, section anchors, or Assistant prompt handoffs;
they must not restore `frontend-modern/src/pages/Dashboard.tsx`,
`frontend-modern/src/features/dashboardOverview/`, or deleted dashboard-only
presentation helpers as compatibility paths.
The primary navigation active-tab contract follows that retirement boundary:
retired or unknown routes such as `/dashboard` must not be coerced into the
Infrastructure tab just because Infrastructure is the authenticated landing
surface. Shared desktop and mobile navigation must tolerate a missing active tab
for those paths while still highlighting canonical active routes such as
Infrastructure, Workloads, Storage, Recovery, Alerts, Patrol, and Settings.
The recovery feature shell now also depends on the shared
`frontend-modern/src/components/shared/Subtabs.tsx` primitive for its primary
protected-items versus recovery-events workspace switch. The recovery lane may
@@ -74,6 +74,48 @@ describe('MobileNavBar', () => {
expect(within(navList).queryByRole('button', { name: 'Pulse Patrol Patrol' })).toBeNull();
});
it('allows retired shell routes to render without an active mobile tab', () => {
const { container } = render(() => (
<MobileNavBar
activeTab={() => null}
platformTabs={() => [
{
id: 'infrastructure',
label: 'Infrastructure',
route: '/infrastructure',
settingsRoute: '/settings',
tooltip: 'Infrastructure',
enabled: true,
live: true,
icon: InfrastructureIcon,
alwaysShow: true,
},
]}
utilityTabs={() => [
{
id: 'settings',
label: 'Settings',
route: '/settings',
tooltip: 'Settings',
badge: null,
count: undefined,
breakdown: undefined,
icon: SettingsIcon,
},
]}
onPlatformClick={() => {}}
onUtilityClick={() => {}}
/>
));
const buttons = container.querySelectorAll('button[data-tab-id]');
expect(buttons).toHaveLength(2);
buttons.forEach((button) => {
expect(button).not.toHaveClass('bg-blue-50');
expect(button).not.toHaveClass('text-blue-700');
});
});
it('orders tabs, renders alert badges, and shows fades from scroll state', async () => {
const onPlatformClick = vi.fn();
const onUtilityClick = vi.fn();
@@ -27,7 +27,7 @@ export type MobileNavBarUtilityTab = {
};
export type MobileNavBarProps = {
activeTab: () => string;
activeTab: () => string | null;
platformTabs: () => MobileNavBarPlatformTab[];
utilityTabs: () => MobileNavBarUtilityTab[];
onPlatformClick: (platform: MobileNavBarPlatformTab) => void;
@@ -3,7 +3,8 @@ import { getActiveTabForPath } from '../navigation';
describe('navigation routing helpers', () => {
it('maps paths to the correct primary tab', () => {
expect(getActiveTabForPath('/unknown')).toBe('infrastructure');
expect(getActiveTabForPath('/unknown')).toBeNull();
expect(getActiveTabForPath('/dashboard')).toBeNull();
expect(getActiveTabForPath('/infrastructure')).toBe('infrastructure');
expect(getActiveTabForPath('/workloads?type=pod')).toBe('workloads');
expect(getActiveTabForPath('/storage')).toBe('storage');
+4 -2
View File
@@ -9,7 +9,9 @@ export type AppTabId =
| 'ai'
| 'settings';
export function getActiveTabForPath(path: string): AppTabId {
export type ActiveAppTabId = AppTabId | null;
export function getActiveTabForPath(path: string): ActiveAppTabId {
if (path.startsWith(INFRASTRUCTURE_PATH)) return 'infrastructure';
if (path.startsWith(WORKLOADS_PATH)) return 'workloads';
if (path.startsWith('/storage')) return 'storage';
@@ -19,5 +21,5 @@ export function getActiveTabForPath(path: string): AppTabId {
if (path.startsWith(PATROL_PATH) || path.startsWith('/ai')) return 'ai';
if (path.startsWith('/settings')) return 'settings';
if (path.startsWith('/operations')) return 'settings';
return 'infrastructure';
return null;
}