From beb143aadea03aa3494e3d33bab5374f02fd2a89 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Fri, 17 Apr 2026 23:17:38 +0100 Subject: [PATCH] Fix missing utility navigation icons --- frontend-modern/src/AppLayout.tsx | 155 +++++------------- .../src/__tests__/App.architecture.test.ts | 12 ++ .../src/__tests__/AppLayout.test.tsx | 86 ++++++++++ .../src/components/shared/MobileNavBar.tsx | 63 +++---- .../shared/__tests__/MobileNavBar.test.tsx | 14 +- .../components/shared/mobileNavBarModel.ts | 12 +- 6 files changed, 185 insertions(+), 157 deletions(-) create mode 100644 frontend-modern/src/__tests__/AppLayout.test.tsx diff --git a/frontend-modern/src/AppLayout.tsx b/frontend-modern/src/AppLayout.tsx index a0a416f86c..732fd8fdee 100644 --- a/frontend-modern/src/AppLayout.tsx +++ b/frontend-modern/src/AppLayout.tsx @@ -1,12 +1,4 @@ -import { - For, - Show, - Suspense, - createEffect, - createMemo, - createSignal, - onCleanup, -} from 'solid-js'; +import { For, Show, Suspense, createEffect, createMemo, createSignal, onCleanup } from 'solid-js'; import type { JSX } from 'solid-js'; import { useLocation, useNavigate } from '@solidjs/router'; import BoxesIcon from 'lucide-solid/icons/boxes'; @@ -18,7 +10,11 @@ import BellIcon from 'lucide-solid/icons/bell'; import SettingsIcon from 'lucide-solid/icons/settings'; import Maximize2Icon from 'lucide-solid/icons/maximize-2'; import Minimize2Icon from 'lucide-solid/icons/minimize-2'; -import { MobileNavBar } from '@/components/shared/MobileNavBar'; +import { + MobileNavBar, + type MobileNavBarPlatformTab as PlatformTab, + type MobileNavBarUtilityTab as UtilityTab, +} from '@/components/shared/MobileNavBar'; import { dialogStackHasBlockingDialog } from '@/components/shared/useDialogState'; import { OrgSwitcher } from '@/components/OrgSwitcher'; import { PulsePatrolLogo } from '@/components/Brand/PulsePatrolLogo'; @@ -42,38 +38,12 @@ import { updateStore } from '@/stores/updates'; import { aiChatStore } from '@/stores/aiChat'; import { isPro } from '@/stores/licenseCommercial'; import { presentationPolicyHidesUpgradePrompts } from '@/stores/sessionPresentationPolicy'; -import { - AI_CHAT_LAUNCHER_ARIA_LABEL, - getAIChatLauncherTitle, -} from '@/utils/aiChatPresentation'; +import { AI_CHAT_LAUNCHER_ARIA_LABEL, getAIChatLauncherTitle } from '@/utils/aiChatPresentation'; import type { AppConnectionStatus } from '@/useAppRuntimeState'; const ROOT_INFRASTRUCTURE_PATH = buildInfrastructurePath(); const ROOT_WORKLOADS_PATH = buildWorkloadsPath(); - -type PlatformTab = { - id: string; - label: string; - route: string; - settingsRoute: string; - tooltip: string; - enabled: boolean; - live: boolean; - icon: JSX.Element; - alwaysShow: boolean; - badge?: string; -}; - -type UtilityTab = { - id: 'alerts' | 'ai' | 'settings'; - label: string; - route: string; - tooltip: string; - badge: 'update' | 'pro' | null; - count: number | undefined; - breakdown: { warning: number; critical: number } | undefined; - icon: JSX.Element; -}; +const NAV_TAB_ICON_CLASS = 'w-4 h-4 shrink-0'; export interface AppLayoutProps { connectionStatus: () => AppConnectionStatus; @@ -283,7 +253,7 @@ export function AppLayout(props: AppLayoutProps) { const getActiveTabDesktop = () => getActiveTabForPath(location.pathname); const getActiveTabMobile = () => getActiveTabForPath(location.pathname); - const platformTabsDesktop = createMemo(() => { + const platformTabs = createMemo(() => { const allPlatforms: PlatformTab[] = [ { id: 'dashboard', @@ -293,7 +263,7 @@ export function AppLayout(props: AppLayoutProps) { tooltip: 'Environment overview and command center', enabled: true, live: true, - icon: , + icon: LayoutDashboardIcon, alwaysShow: true, }, { @@ -304,7 +274,7 @@ export function AppLayout(props: AppLayoutProps) { tooltip: 'All agents and nodes across platforms', enabled: true, live: true, - icon: , + icon: ServerIcon, alwaysShow: true, }, { @@ -315,69 +285,14 @@ export function AppLayout(props: AppLayoutProps) { tooltip: 'VMs, containers, and Kubernetes workloads', enabled: true, live: true, - icon: , + icon: BoxesIcon, alwaysShow: true, }, ...buildStorageRecoveryTabSpecs().map((tab) => ({ ...tab, enabled: true, live: true, - icon: tab.id.startsWith('storage') ? ( - - ) : ( - - ), - alwaysShow: true, - })), - ]; - - return allPlatforms.filter((platform) => platform.alwaysShow || platform.enabled); - }); - - const platformTabsMobile = createMemo(() => { - const allPlatforms: PlatformTab[] = [ - { - id: 'dashboard', - label: 'Dashboard', - route: DASHBOARD_PATH, - settingsRoute: '/settings', - tooltip: 'Environment overview and command center', - enabled: true, - live: true, - icon: , - alwaysShow: true, - }, - { - id: 'infrastructure', - label: 'Infrastructure', - route: ROOT_INFRASTRUCTURE_PATH, - settingsRoute: '/settings', - tooltip: 'All agents and nodes across platforms', - enabled: true, - live: true, - icon: , - alwaysShow: true, - }, - { - id: 'workloads', - label: 'Workloads', - route: ROOT_WORKLOADS_PATH, - settingsRoute: '/settings/workloads/docker', - tooltip: 'VMs, containers, and Kubernetes workloads', - enabled: true, - live: true, - icon: , - alwaysShow: true, - }, - ...buildStorageRecoveryTabSpecs().map((tab) => ({ - ...tab, - enabled: true, - live: true, - icon: tab.id.startsWith('storage') ? ( - - ) : ( - - ), + icon: tab.id.startsWith('storage') ? HardDriveIcon : ArchiveIcon, alwaysShow: true, })), ]; @@ -415,7 +330,7 @@ export function AppLayout(props: AppLayoutProps) { badge: null, count: activeAlertCount, breakdown, - icon: , + icon: BellIcon, }, { id: 'ai', @@ -425,7 +340,7 @@ export function AppLayout(props: AppLayoutProps) { badge: null, count: undefined, breakdown: undefined, - icon: , + icon: PulsePatrolLogo, }, ]; @@ -438,7 +353,7 @@ export function AppLayout(props: AppLayoutProps) { badge: updateStore.isUpdateVisible() ? 'update' : null, count: undefined, breakdown: undefined, - icon: , + icon: SettingsIcon, }); } @@ -557,14 +472,24 @@ export function AppLayout(props: AppLayoutProps) { class={`pulse-logo ${props.connectionStatus().kind === 'connected' && props.dataUpdated() ? 'animate-pulse-logo' : ''}`} > Pulse Logo - + - + Pulse @@ -604,10 +529,7 @@ export function AppLayout(props: AppLayoutProps) { aria-label={kioskMode() ? 'Exit kiosk mode' : 'Enter kiosk mode'} aria-pressed={kioskMode()} > - } - > + }> @@ -638,10 +560,7 @@ export function AppLayout(props: AppLayoutProps) { - + @@ -652,10 +571,11 @@ export function AppLayout(props: AppLayoutProps) { aria-label="Primary navigation" >
- + {(platform) => { const isActive = () => getActiveTabDesktop() === platform.id; const disabled = () => !platform.enabled; + const Icon = platform.icon; const baseClasses = 'tab relative px-1.5 sm:px-3 py-1.5 text-xs sm:text-sm font-medium flex items-center gap-1 sm:gap-1.5 rounded-t border border-transparent transition-colors whitespace-nowrap cursor-pointer'; @@ -683,7 +603,7 @@ export function AppLayout(props: AppLayoutProps) { onClick={() => handlePlatformClick(platform)} title={title()} > - {platform.icon} +