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:
@@ -54,8 +54,8 @@ export const ServerMetricsOverview = ({ server }: ServerMetricsOverviewProps) =>
|
|||||||
<div
|
<div
|
||||||
className="p-2.5 rounded-xl shadow-sm ring-1 ring-white/10 transition-all duration-300 group-hover:scale-110"
|
className="p-2.5 rounded-xl shadow-sm ring-1 ring-white/10 transition-all duration-300 group-hover:scale-110"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: `${color}15`,
|
backgroundColor: `${color}35`,
|
||||||
boxShadow: `0 4px 12px ${color}20`
|
// boxShadow: `0 4px 12px ${color}20`
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon className="h-4 w-4" style={{ color }} />
|
<Icon className="h-4 w-4" style={{ color }} />
|
||||||
@@ -64,7 +64,7 @@ export const ServerMetricsOverview = ({ server }: ServerMetricsOverviewProps) =>
|
|||||||
</div>
|
</div>
|
||||||
<div className="text-xs font-mono font-bold px-2 py-1 rounded-md" style={{
|
<div className="text-xs font-mono font-bold px-2 py-1 rounded-md" style={{
|
||||||
color,
|
color,
|
||||||
backgroundColor: `${color}10`,
|
backgroundColor: `${color}35`,
|
||||||
border: `1px solid ${color}30`
|
border: `1px solid ${color}30`
|
||||||
}}>
|
}}>
|
||||||
{percentage.toFixed(1)}%
|
{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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import { ArrowLeft, Server, Database } from "lucide-react";
|
|||||||
import { ServerMetricsCharts } from "@/components/servers/ServerMetricsCharts";
|
import { ServerMetricsCharts } from "@/components/servers/ServerMetricsCharts";
|
||||||
import { ServerMetricsOverview } from "@/components/servers/ServerMetricsOverview";
|
import { ServerMetricsOverview } from "@/components/servers/ServerMetricsOverview";
|
||||||
import { ServerHistoryCharts } from "@/components/servers/ServerHistoryCharts";
|
import { ServerHistoryCharts } from "@/components/servers/ServerHistoryCharts";
|
||||||
|
import { ServerSystemInfoCard } from "@/components/servers/ServerSystemInfoCard";
|
||||||
|
|
||||||
const ServerDetail = () => {
|
const ServerDetail = () => {
|
||||||
const { serverId } = useParams();
|
const { serverId } = useParams();
|
||||||
@@ -136,14 +137,18 @@ const ServerDetail = () => {
|
|||||||
Monitor server performance metrics and system health
|
Monitor server performance metrics and system health
|
||||||
{server && (
|
{server && (
|
||||||
<span className="block text-xs text-foreground/80 mt-1">
|
<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>
|
</span>
|
||||||
|
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
{/* System Info Card */}
|
||||||
|
{server && (
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<ServerSystemInfoCard server={server} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user