feat: Add system info cards to server detail header

Adds small cards in the server detail page header to display server system information.
This commit is contained in:
samang-dauth
2025-07-05 17:00:21 +07:00
parent 671f22c1d3
commit f0eec90e75
3 changed files with 123 additions and 6 deletions
@@ -54,8 +54,8 @@ export const ServerMetricsOverview = ({ server }: ServerMetricsOverviewProps) =>
<div
className="p-2.5 rounded-xl shadow-sm ring-1 ring-white/10 transition-all duration-300 group-hover:scale-110"
style={{
backgroundColor: `${color}15`,
boxShadow: `0 4px 12px ${color}20`
backgroundColor: `${color}35`,
// boxShadow: `0 4px 12px ${color}20`
}}
>
<Icon className="h-4 w-4" style={{ color }} />
@@ -64,7 +64,7 @@ export const ServerMetricsOverview = ({ server }: ServerMetricsOverviewProps) =>
</div>
<div className="text-xs font-mono font-bold px-2 py-1 rounded-md" style={{
color,
backgroundColor: `${color}10`,
backgroundColor: `${color}35`,
border: `1px solid ${color}30`
}}>
{percentage.toFixed(1)}%
@@ -0,0 +1,112 @@
import { Card, CardContent } from "@/components/ui/card";
import { Server, Monitor, Cpu, HardDrive, DatabaseIcon, InfoIcon } from "lucide-react";
import { Server as ServerType } from "@/types/server.types";
interface ServerSystemInfoCardProps {
server: ServerType;
}
export function ServerSystemInfoCard({ server }: ServerSystemInfoCardProps) {
// Parse system_info if it's a string
let systemInfo: any = {};
if (server.system_info) {
try {
systemInfo = typeof server.system_info === 'string'
? JSON.parse(server.system_info)
: server.system_info;
} catch (error) {
console.log('Error parsing system_info:', error);
}
}
const formatBytes = (bytes: number) => {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
const formatUptime = (uptimeSeconds: string | number) => {
const seconds = typeof uptimeSeconds === 'string' ? parseInt(uptimeSeconds) : uptimeSeconds;
const days = Math.floor(seconds / 86400);
const hours = Math.floor((seconds % 86400) / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
if (days > 0) return `${days}d ${hours}h`;
if (hours > 0) return `${hours}h ${minutes}m`;
return `${minutes}m`;
};
// Format the detailed system info string
const getDetailedSystemInfo = () => {
if (typeof server.system_info === 'string' && server.system_info.includes('|')) {
// If system_info is already in the detailed format, return it
return server.system_info;
}
// Otherwise, build the detailed string from available data
const parts = [];
// Basic server info
parts.push(server.hostname || 'Unknown');
parts.push(server.ip_address || 'Unknown IP');
parts.push(server.os_type || 'Unknown OS');
// Parse additional info from system_info if available
if (systemInfo.OSName) {
parts.push(systemInfo.OSName + (systemInfo.OSVersion ? ` ${systemInfo.OSVersion}` : ''));
}
if (systemInfo.Architecture) {
parts.push(`| ${systemInfo.Architecture}`);
}
if (systemInfo.KernelVersion) {
parts.push(`| Kernel: ${systemInfo.KernelVersion}`);
}
if (systemInfo.CPUModel) {
parts.push(`| CPU: ${systemInfo.CPUModel} (${server.cpu_cores || 0} cores)`);
} else if (server.cpu_cores) {
parts.push(`| CPU: ${server.cpu_cores} cores`);
}
if (server.ram_total) {
parts.push(`| RAM: ${formatBytes(server.ram_total)}`);
}
if (systemInfo.GoVersion) {
parts.push(`| Go ${systemInfo.GoVersion}`);
}
if (systemInfo.IPAddress && systemInfo.IPAddress !== server.ip_address) {
parts.push(`| IP: ${systemInfo.IPAddress}`);
}
// Check for Docker info
const dockerInfo = server.docker || systemInfo.Docker;
if (dockerInfo !== undefined) {
parts.push(`| Docker: ${dockerInfo}`);
}
return parts.join(' • ').replace(/• \|/g, '|');
};
return (
<Card className="bg-card/50 backdrop-blur-sm border-border/50 max-w-md">
<CardContent className="p-4">
<div className="flex items-center gap-2 mb-3">
<div className="h-6 w-6 rounded bg-primary/10 flex items-center justify-center">
<InfoIcon className="h-3 w-3 text-primary" />
</div>
<h3 className="text-sm font-medium">System Information</h3>
</div>
<div className="text-xs text-muted-foreground leading-relaxed break-all">
{getDetailedSystemInfo()}
</div>
</CardContent>
</Card>
);
}
+8 -3
View File
@@ -14,6 +14,7 @@ import { ArrowLeft, Server, Database } from "lucide-react";
import { ServerMetricsCharts } from "@/components/servers/ServerMetricsCharts";
import { ServerMetricsOverview } from "@/components/servers/ServerMetricsOverview";
import { ServerHistoryCharts } from "@/components/servers/ServerHistoryCharts";
import { ServerSystemInfoCard } from "@/components/servers/ServerSystemInfoCard";
const ServerDetail = () => {
const { serverId } = useParams();
@@ -136,14 +137,18 @@ const ServerDetail = () => {
Monitor server performance metrics and system health
{server && (
<span className="block text-xs text-foreground/80 mt-1">
{server.hostname} {server.ip_address} {server.os_type} {server.system_info}
{server.hostname} {server.ip_address} {server.os_type}
</span>
)}
</p>
</div>
{/* System Info Card */}
{server && (
<div className="flex-shrink-0">
<ServerSystemInfoCard server={server} />
</div>
)}
</div>
</div>