From 1cdd6eba6dd65fa5ccf1e6f95c67c3bbe79dd752 Mon Sep 17 00:00:00 2001 From: Muhammad Ibrahim Date: Sat, 20 Sep 2025 12:40:31 +0100 Subject: [PATCH] Added better view on host details and improved filtering --- frontend/src/pages/HostDetail.jsx | 962 ++++++++++++++++-------------- 1 file changed, 509 insertions(+), 453 deletions(-) diff --git a/frontend/src/pages/HostDetail.jsx b/frontend/src/pages/HostDetail.jsx index c45db48..0e2338e 100644 --- a/frontend/src/pages/HostDetail.jsx +++ b/frontend/src/pages/HostDetail.jsx @@ -46,6 +46,7 @@ const HostDetail = () => { const [isEditingFriendlyName, setIsEditingFriendlyName] = useState(false) const [editedFriendlyName, setEditedFriendlyName] = useState('') const [showAllUpdates, setShowAllUpdates] = useState(false) + const [activeTab, setActiveTab] = useState('host') const { data: host, isLoading, error, refetch } = useQuery({ queryKey: ['host', hostId], @@ -180,476 +181,531 @@ const HostDetail = () => { const isStale = new Date() - new Date(host.lastUpdate) > 24 * 60 * 60 * 1000 return ( -
- {/* Host Information */} -
- {/* Basic Info */} -
-
-

Host Information

-
- - - +
+ {/* Header */} +
+
+ + + +

{host.friendlyName}

+ {host.systemUptime && ( +
+ + Uptime: + {host.systemUptime}
+ )} +
+ + Last updated: + {formatRelativeTime(host.lastUpdate)}
-
-
- -
-

Friendly Name

- updateFriendlyNameMutation.mutate(newName)} - placeholder="Enter friendly name..." - maxLength={100} - validate={(value) => { - if (!value.trim()) return 'Friendly name is required'; - if (value.trim().length < 1) return 'Friendly name must be at least 1 character'; - if (value.trim().length > 100) return 'Friendly name must be less than 100 characters'; - return null; - }} - className="w-full" - /> -
-
- - {host.hostname && ( -
- -
-

System Hostname

-

{host.hostname}

-
-
- )} - -
- -
-

Host Group

- {host.hostGroup ? ( - - {host.hostGroup.name} - - ) : ( - - Ungrouped - - )} -
-
- -
- -
-

Operating System

-
- -

{host.osType} {host.osVersion}

-
-
-
- - {host.ip && ( -
- -
-

IP Address

-

{host.ip}

-
-
- )} - - {host.architecture && ( -
- -
-

Architecture

-

{host.architecture}

-
-
- )} - -
- -
-

Last Update

-

{formatRelativeTime(host.lastUpdate)}

-
-
- - {host.agentVersion && ( -
-
- -
-

Agent Version

-

{host.agentVersion}

-
-
- - {/* Auto-Update Toggle */} -
- Auto-update - -
-
- )} -
- - {/* Action Buttons */} -
- - +
0)}`}> + {getStatusIcon(isStale, host.stats.outdatedPackages > 0)} + {getStatusText(isStale, host.stats.outdatedPackages > 0)}
- - {/* Statistics */} -
-

Statistics

-
-
-
- -
-

{host.stats.totalPackages}

-

Total Packages

-
- - - -
-
- -
-

{host.stats.securityUpdates}

-

Security Updates

-
-
- - {/* Status */} -
-
0)}`}> - {getStatusIcon(isStale, host.stats.outdatedPackages > 0)} - {getStatusText(isStale, host.stats.outdatedPackages > 0)} -
-
+
+ +
- {/* Hardware Information */} - {(host.cpuModel || host.ramInstalled || host.diskDetails) && ( -
-

Hardware Information

-
- {host.cpuModel && ( -
- -
-

CPU Model

-

{host.cpuModel}

-
-
- )} - - {host.cpuCores && ( -
- -
-

CPU Cores

-

{host.cpuCores}

-
-
- )} - - {host.ramInstalled && ( -
- -
-

RAM Installed

-

{host.ramInstalled} GB

-
-
- )} - - {host.swapSize !== undefined && ( -
- -
-

Swap Size

-

{host.swapSize} GB

-
-
- )} -
- - {host.diskDetails && Array.isArray(host.diskDetails) && host.diskDetails.length > 0 && ( -
-

Disk Details

-
- {host.diskDetails.map((disk, index) => ( -
-
- - {disk.name} -
-

Size: {disk.size}

- {disk.mountpoint && ( -

Mount: {disk.mountpoint}

- )} -
- ))} -
+ {/* Main Content Grid */} +
+ {/* Left Column - System Details with Tabs */} +
+ {/* Host Info, Hardware, Network, System Info in Tabs */} +
+
+ + + + + +
- )} -
- )} - - {/* Network Information */} - {(host.gatewayIp || host.dnsServers || host.networkInterfaces) && ( -
-

Network Information

-
- {host.gatewayIp && ( -
- -
-

Gateway IP

-

{host.gatewayIp}

-
-
- )} - {host.dnsServers && Array.isArray(host.dnsServers) && host.dnsServers.length > 0 && ( -
- -
-

DNS Servers

-
- {host.dnsServers.map((dns, index) => ( -

{dns}

- ))} -
-
-
- )} - - {host.networkInterfaces && Array.isArray(host.networkInterfaces) && host.networkInterfaces.length > 0 && ( -
- -
-

Network Interfaces

-
- {host.networkInterfaces.map((iface, index) => ( -

{iface.name}

- ))} -
-
-
- )} -
-
- )} - - {/* System Information */} - {(host.kernelVersion || host.selinuxStatus || host.systemUptime || host.loadAverage) && ( -
-

System Information

-
- {host.kernelVersion && ( -
- -
-

Kernel Version

-

{host.kernelVersion}

-
-
- )} - - {host.selinuxStatus && ( -
- -
-

SELinux Status

- - {host.selinuxStatus} - -
-
- )} - - {host.systemUptime && ( -
- -
-

System Uptime

-

{host.systemUptime}

-
-
- )} - - {host.loadAverage && Array.isArray(host.loadAverage) && host.loadAverage.length > 0 && ( -
- -
-

Load Average

-

- {host.loadAverage.map((load, index) => ( - - {load.toFixed(2)} - {index < host.loadAverage.length - 1 && ', '} - - ))} -

-
-
- )} -
-
- )} - - {/* Update History */} -
-
-
-

Agent Update History

-
- -
- {host.updateHistory?.length > 0 ? ( - <> - - - - - - - - - - - {(showAllUpdates ? host.updateHistory : host.updateHistory.slice(0, 3)).map((update, index) => ( - - - - - - - ))} - -
- Status - - Date - - Packages - - Security -
-
-
- - {update.status === 'success' ? 'Success' : 'Failed'} - -
-
- {formatDate(update.timestamp)} - - {update.packagesCount} - - {update.securityCount > 0 ? ( -
- - - {update.securityCount} - -
- ) : ( - - - )} -
- - {host.updateHistory.length > 3 && ( -
- + +
+

Host Group

+ {host.hostGroup ? ( + + {host.hostGroup.name} + + ) : ( + + Ungrouped + + )} +
+ +
+

Operating System

+
+ +

{host.osType} {host.osVersion}

+
+
+ + {host.ip && ( +
+

IP Address

+

{host.ip}

+
+ )} + + +
+

Last Update

+

{formatRelativeTime(host.lastUpdate)}

+
+ + {host.agentVersion && ( +
+
+

Agent Version

+

{host.agentVersion}

+
+
+ Auto-update + +
+
+ )} +
+
+ )} + + {/* Hardware Information */} + {activeTab === 'hardware' && (host.cpuModel || host.ramInstalled || host.diskDetails) && ( +
+
+ {host.cpuModel && ( +
+

CPU Model

+

{host.cpuModel}

+
+ )} + + {host.cpuCores && ( +
+

CPU Cores

+

{host.cpuCores}

+
+ )} + + {host.ramInstalled && ( +
+

RAM Installed

+

{host.ramInstalled} GB

+
+ )} + + {host.swapSize !== undefined && ( +
+

Swap Size

+

{host.swapSize} GB

+
+ )} +
+ + {host.diskDetails && Array.isArray(host.diskDetails) && host.diskDetails.length > 0 && ( +
+

Disk Details

+
+ {host.diskDetails.map((disk, index) => ( +
+
+ + {disk.name} +
+

Size: {disk.size}

+ {disk.mountpoint && ( +

Mount: {disk.mountpoint}

+ )} +
+ ))} +
+
+ )} +
+ )} + + {/* Network Information */} + {activeTab === 'network' && (host.gatewayIp || host.dnsServers || host.networkInterfaces) && ( +
+
+ {host.gatewayIp && ( +
+

Gateway IP

+

{host.gatewayIp}

+
+ )} + + {host.dnsServers && Array.isArray(host.dnsServers) && host.dnsServers.length > 0 && ( +
+

DNS Servers

+
+ {host.dnsServers.map((dns, index) => ( +

{dns}

+ ))} +
+
+ )} + + {host.networkInterfaces && Array.isArray(host.networkInterfaces) && host.networkInterfaces.length > 0 && ( +
+

Network Interfaces

+
+ {host.networkInterfaces.map((iface, index) => ( +

{iface.name}

+ ))} +
+
+ )} +
+
+ )} + + {/* System Information */} + {activeTab === 'system' && (host.kernelVersion || host.selinuxStatus || host.architecture) && ( +
+
+ {host.architecture && ( +
+

Architecture

+

{host.architecture}

+
+ )} + + {host.kernelVersion && ( +
+

Kernel Version

+

{host.kernelVersion}

+
+ )} + + {host.selinuxStatus && ( +
+

SELinux Status

+ + {host.selinuxStatus} + +
+ )} + + +
+
+ )} + + {/* Empty state for tabs with no data */} + {activeTab === 'hardware' && !(host.cpuModel || host.ramInstalled || host.diskDetails) && ( +
+ +

No hardware information available

+
+ )} + + {activeTab === 'network' && !(host.gatewayIp || host.dnsServers || host.networkInterfaces) && ( +
+ +

No network information available

+
+ )} + + {activeTab === 'system' && !(host.kernelVersion || host.selinuxStatus || host.architecture) && ( +
+ +

No system information available

+
+ )} + + {/* System Monitoring */} + {activeTab === 'monitoring' && host.loadAverage && Array.isArray(host.loadAverage) && host.loadAverage.length > 0 && ( +
+
+
+

Load Average

+

+ {host.loadAverage.map((load, index) => ( + + {load.toFixed(2)} + {index < host.loadAverage.length - 1 && ', '} + + ))} +

+
+
+
+ )} + + {activeTab === 'monitoring' && (!host.loadAverage || !Array.isArray(host.loadAverage) || host.loadAverage.length === 0) && ( +
+ +

No monitoring data available

+
+ )} + + {/* Update History */} + {activeTab === 'history' && ( +
+ {host.updateHistory?.length > 0 ? ( + <> + + + + + + + + + + + {(showAllUpdates ? host.updateHistory : host.updateHistory.slice(0, 5)).map((update, index) => ( + + + + + + + ))} + +
+ Status + + Date + + Packages + + Security +
+
+
+ + {update.status === 'success' ? 'Success' : 'Failed'} + +
+
+ {formatDate(update.timestamp)} + + {update.packagesCount} + + {update.securityCount > 0 ? ( +
+ + + {update.securityCount} + +
+ ) : ( + - + )} +
+ + {host.updateHistory.length > 5 && ( +
+ +
+ )} + + ) : ( +
+ +

No update history available

+
+ )}
)} - - ) : ( -
- -

No update history available

- )} +
+ + {/* Right Column - Package Statistics */} +
+ {/* Package Statistics */} +
+
+

Package Statistics

+
+
+
+
+
+ +
+

{host.stats.totalPackages}

+

Total Packages

+
+ + + + +
+
+
+ {/* Credentials Modal */} {showCredentialsModal && (