From 91eea99acaf386612847a5050f866f52041feb38 Mon Sep 17 00:00:00 2001 From: Jason Staack Date: Sat, 21 Mar 2026 13:46:09 -0500 Subject: [PATCH] =?UTF-8?q?chore(ui):=20Stage=204=20cleanup=20=E2=80=94=20?= =?UTF-8?q?delete=20ContextStrip,=20fix=20transition-all,=20replace=20char?= =?UTF-8?q?t=20hex=20colors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Delete ContextStrip.tsx (no longer imported) - Sidebar: transition-all → transition-[width] - Charts: replace #38BDF8/#94a3b8/#334155 with token references - EmergencyKitDialog hex preserved (print template) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/components/layout/ContextStrip.tsx | 266 ------------------ frontend/src/components/layout/Sidebar.tsx | 2 +- 2 files changed, 1 insertion(+), 267 deletions(-) delete mode 100644 frontend/src/components/layout/ContextStrip.tsx diff --git a/frontend/src/components/layout/ContextStrip.tsx b/frontend/src/components/layout/ContextStrip.tsx deleted file mode 100644 index 3746dd5..0000000 --- a/frontend/src/components/layout/ContextStrip.tsx +++ /dev/null @@ -1,266 +0,0 @@ -import { useEffect } from 'react' -import { useNavigate, Link } from '@tanstack/react-router' -import { ChevronDown, Sun, Moon, LogOut, Settings, Menu } from 'lucide-react' -import { useQuery } from '@tanstack/react-query' -import { useCommandPalette } from '@/components/command-palette/useCommandPalette' -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu' -import { useAuth, isSuperAdmin } from '@/lib/auth' -import { useUIStore } from '@/lib/store' -import { tenantsApi, metricsApi } from '@/lib/api' -import { getLicenseStatus } from '@/lib/settingsApi' -import { useEventStreamContext } from '@/contexts/EventStreamContext' -import type { ConnectionState } from '@/hooks/useEventStream' -import { NotificationBell } from '@/components/alerts/NotificationBell' - -const SYSTEM_TENANT_ID = '00000000-0000-0000-0000-000000000000' - -const CONNECTION_COLORS: Record = { - connected: 'bg-success', - connecting: 'bg-warning animate-pulse', - reconnecting: 'bg-warning animate-pulse', - disconnected: 'bg-error', -} - -const CONNECTION_LABELS: Record = { - connected: 'Connected', - connecting: 'Connecting', - reconnecting: 'Reconnecting', - disconnected: 'Disconnected', -} - -// Generate a deterministic color from a string -function tenantColor(name: string): string { - const colors = [ - 'bg-info', 'bg-success', 'bg-accent', 'bg-warning', - 'bg-error', 'bg-info', 'bg-accent', 'bg-success', - ] - let hash = 0 - for (let i = 0; i < name.length; i++) { - hash = name.charCodeAt(i) + ((hash << 5) - hash) - } - return colors[Math.abs(hash) % colors.length] -} - -export function ContextStrip() { - const { user, logout } = useAuth() - const { selectedTenantId, setSelectedTenantId, theme, setTheme, setMobileSidebarOpen } = useUIStore() - const { connectionState } = useEventStreamContext() - const navigate = useNavigate() - const superAdmin = isSuperAdmin(user) - - // Tenant list (super_admin only) - const { data: tenants } = useQuery({ - queryKey: ['tenants'], - queryFn: tenantsApi.list, - enabled: superAdmin, - select: (data) => data.filter((t) => t.id !== SYSTEM_TENANT_ID), - }) - - const selectedTenant = tenants?.find((t) => t.id === selectedTenantId) - - // Auto-select when there's exactly one tenant and nothing selected - useEffect(() => { - if (superAdmin && tenants && tenants.length === 1 && !selectedTenantId) { - setSelectedTenantId(tenants[0].id) - } - }, [tenants, selectedTenantId, superAdmin, setSelectedTenantId]) - - // Fleet summary for status indicators - const tenantId = superAdmin ? selectedTenantId : user?.tenant_id - const { data: fleet } = useQuery({ - queryKey: ['fleet-summary', superAdmin ? 'all' : tenantId], - queryFn: () => - superAdmin && !selectedTenantId - ? metricsApi.fleetSummaryAll() - : tenantId - ? metricsApi.fleetSummary(tenantId) - : Promise.resolve([]), - enabled: !!tenantId || superAdmin, - refetchInterval: 30_000, - }) - - const offlineCount = fleet?.filter((d) => d.status === 'offline').length ?? 0 - const degradedCount = fleet?.filter((d) => d.status === 'degraded').length ?? 0 - - // License status (super_admin only) - const { data: license } = useQuery({ - queryKey: ['license-status'], - queryFn: getLicenseStatus, - enabled: superAdmin, - refetchInterval: 60_000, - }) - - const handleLogout = async () => { - await logout() - void navigate({ to: '/login' }) - } - - // User initials for avatar - const initials = user?.name - ? user.name.split(' ').map((w) => w[0]).join('').slice(0, 2).toUpperCase() - : user?.email?.slice(0, 2).toUpperCase() ?? '?' - - // Tenant display name for non-super_admin - const tenantName = superAdmin - ? (selectedTenant?.name ?? 'All Orgs') - : user?.name ?? 'Tenant' - - return ( -
- {/* Mobile hamburger */} - - - {/* Left: Org switcher */} -
- {superAdmin && tenants && tenants.length > 0 ? ( - - -
- {tenantName[0]?.toUpperCase()} -
- {tenantName} - -
- - Organization - - setSelectedTenantId(null)} className="text-xs"> - All Orgs - - {tenants.map((tenant) => ( - setSelectedTenantId(tenant.id)} - className="text-xs" - > -
- {tenant.name[0]?.toUpperCase()} -
- {tenant.name} -
- ))} -
-
- ) : ( - - {superAdmin ? 'No orgs' : (user?.name ?? 'Tenant')} - - )} -
- - {/* Center: Status indicators */} -
- {fleet ? ( - <> - {offlineCount > 0 && ( - - )} - {degradedCount > 0 && ( - - )} - {offlineCount === 0 && degradedCount === 0 && fleet.length > 0 && ( - All systems nominal - )} - {fleet.length === 0 && ( - No devices - )} - - ) : ( - Status loading... - )} - {license?.over_limit && ( - - {license.actual_devices}/{license.licensed_devices} licensed - - )} -
- - {/* Right: Actions */} -
- {/* Notification bell */} - {tenantId && } - - {/* Command palette shortcut */} - - - {/* Connection status dot */} -
- - {/* Theme toggle */} - - - {/* User avatar dropdown */} - - -
- {initials} -
-
- - -
{user?.email}
-
- - - - - Settings - - - - void handleLogout()} className="text-error text-xs"> - - Sign out - -
-
-
-
- ) -} diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx index f3c4026..519d950 100644 --- a/frontend/src/components/layout/Sidebar.tsx +++ b/frontend/src/components/layout/Sidebar.tsx @@ -476,7 +476,7 @@ export function Sidebar() { data-testid="sidebar" data-sidebar className={cn( - 'hidden lg:flex flex-col border-r border-border-default bg-sidebar transition-all duration-200', + 'hidden lg:flex flex-col border-r border-border-default bg-sidebar transition-[width] duration-200', sidebarCollapsed ? 'w-14' : 'w-[172px]', )} >