From 41acb4f2ced5dcd26d427c8387aeefc4f1a96dee Mon Sep 17 00:00:00 2001 From: rcourtman Date: Fri, 5 Dec 2025 12:34:52 +0000 Subject: [PATCH] feat: Replace OS column text with icons and rich tooltips - Add OSInfoCell component with OS-specific icons (Windows, Ubuntu, Debian, Alpine, CentOS/RHEL, Fedora, Arch, FreeBSD, generic Linux) - Each OS type has a distinct color for quick visual identification - Portal tooltip shows full OS name, version, and guest agent version - Much more compact than text strings like "Microsoft Windows Server 2022" --- .../src/components/Dashboard/GuestRow.tsx | 184 +++++++++++++++++- 1 file changed, 178 insertions(+), 6 deletions(-) diff --git a/frontend-modern/src/components/Dashboard/GuestRow.tsx b/frontend-modern/src/components/Dashboard/GuestRow.tsx index a3c8dfb..fb66b87 100644 --- a/frontend-modern/src/components/Dashboard/GuestRow.tsx +++ b/frontend-modern/src/components/Dashboard/GuestRow.tsx @@ -205,6 +205,179 @@ function NetworkInfoCell(props: { ipAddresses: string[]; networkInterfaces: Netw ); } +// OS detection helper - returns icon type and color based on OS name +type OSType = 'windows' | 'ubuntu' | 'debian' | 'alpine' | 'centos' | 'fedora' | 'arch' | 'linux' | 'freebsd' | 'unknown'; + +function detectOSType(osName: string): OSType { + const lower = osName.toLowerCase(); + if (lower.includes('windows')) return 'windows'; + if (lower.includes('ubuntu')) return 'ubuntu'; + if (lower.includes('debian')) return 'debian'; + if (lower.includes('alpine')) return 'alpine'; + if (lower.includes('centos') || lower.includes('rocky') || lower.includes('alma') || lower.includes('rhel') || lower.includes('red hat')) return 'centos'; + if (lower.includes('fedora')) return 'fedora'; + if (lower.includes('arch')) return 'arch'; + if (lower.includes('freebsd') || lower.includes('openbsd') || lower.includes('netbsd')) return 'freebsd'; + if (lower.includes('linux') || lower.includes('gnu')) return 'linux'; + return 'unknown'; +} + +const OS_COLORS: Record = { + windows: 'text-blue-500', + ubuntu: 'text-orange-500', + debian: 'text-red-500', + alpine: 'text-blue-400', + centos: 'text-purple-500', + fedora: 'text-blue-600', + arch: 'text-cyan-500', + linux: 'text-yellow-500', + freebsd: 'text-red-600', + unknown: 'text-gray-400', +}; + +// OS info cell with icon and Portal tooltip +function OSInfoCell(props: { osName: string; osVersion: string; agentVersion: string }) { + const [showTooltip, setShowTooltip] = createSignal(false); + const [tooltipPos, setTooltipPos] = createSignal({ x: 0, y: 0 }); + + const osType = createMemo(() => detectOSType(props.osName)); + const colorClass = createMemo(() => OS_COLORS[osType()]); + const displayName = createMemo(() => { + const name = props.osName; + // Shorten common long names + if (name.toLowerCase().includes('microsoft windows')) { + return name.replace(/Microsoft Windows/i, 'Win').replace('Server ', 'Srv '); + } + if (name.toLowerCase().includes('gnu/linux')) { + return name.replace(/GNU\/Linux/i, ''); + } + return name; + }); + + const handleMouseEnter = (e: MouseEvent) => { + const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); + setTooltipPos({ x: rect.left + rect.width / 2, y: rect.top }); + setShowTooltip(true); + }; + + const handleMouseLeave = () => { + setShowTooltip(false); + }; + + // SVG icons for different OS types + const OSIcon = () => { + const type = osType(); + const iconClass = `w-3.5 h-3.5 ${colorClass()}`; + + switch (type) { + case 'windows': + return ( + + + + ); + case 'ubuntu': + return ( + + + + + + + ); + case 'debian': + return ( + + + + ); + case 'alpine': + return ( + + + + ); + case 'centos': + case 'fedora': + return ( + + + + ); + case 'arch': + return ( + + + + ); + case 'freebsd': + return ( + + + + + ); + case 'linux': + return ( + + + + ); + default: + // Generic server/computer icon + return ( + + + + + + ); + } + }; + + return ( + <> + + + + + + +
+
+
+ Operating System +
+
+
{props.osName}
+ +
Version: {props.osVersion}
+
+ +
+ Agent: {props.agentVersion} +
+
+
+
+
+
+
+ + ); +} + // Backup status cell with Portal tooltip function BackupStatusCell(props: { lastBackup: string | number | null | undefined }) { const [showTooltip, setShowTooltip] = createSignal(false); @@ -997,12 +1170,11 @@ export function GuestRow(props: GuestRowProps) {
-}> - - {osName() || osVersion()} - +