diff --git a/app/api/servers/get/route.ts b/app/api/servers/get/route.ts index 8229cf9..65551ee 100644 --- a/app/api/servers/get/route.ts +++ b/app/api/servers/get/route.ts @@ -64,7 +64,7 @@ const getIntervals = (timeRange: '1h' | '7d' | '30d' = '1h') => { const parseUsageValue = (value: string | null): number => { if (!value) return 0; - return parseFloat(value.replace('%', '')); + return Math.round(parseFloat(value.replace('%', '')) * 100) / 100; }; export async function POST(request: NextRequest) { @@ -173,7 +173,7 @@ export async function POST(request: NextRequest) { }; const average = (arr: number[]) => - arr.length ? arr.reduce((a, b) => a + b, 0) / arr.length : null; + arr.length ? Math.round((arr.reduce((a, b) => a + b, 0) / arr.length) * 100) / 100 : null; return { timestamp: key, @@ -202,15 +202,15 @@ export async function POST(request: NextRequest) { datasets: { cpu: intervals.map(d => { const data = historyMap.get(d.toISOString())?.cpu || []; - return data.length ? data.reduce((a, b) => a + b) / data.length : null; + return data.length ? Math.round((data.reduce((a, b) => a + b) / data.length) * 100) / 100 : null; }), ram: intervals.map(d => { const data = historyMap.get(d.toISOString())?.ram || []; - return data.length ? data.reduce((a, b) => a + b) / data.length : null; + return data.length ? Math.round((data.reduce((a, b) => a + b) / data.length) * 100) / 100 : null; }), disk: intervals.map(d => { const data = historyMap.get(d.toISOString())?.disk || []; - return data.length ? data.reduce((a, b) => a + b) / data.length : null; + return data.length ? Math.round((data.reduce((a, b) => a + b) / data.length) * 100) / 100 : null; }), online: intervals.map(d => { const data = historyMap.get(d.toISOString())?.online || []; diff --git a/app/dashboard/servers/Servers.tsx b/app/dashboard/servers/Servers.tsx index 50afa50..a585d63 100644 --- a/app/dashboard/servers/Servers.tsx +++ b/app/dashboard/servers/Servers.tsx @@ -1023,6 +1023,469 @@ export default function Dashboard() { + {server.host && server.hostedVMs && server.hostedVMs.length > 0 && ( + + + + + + + + + + Hosted VMs + + {server.host && ( +
+ +
+ {server.hostedVMs?.map((hostedVM) => ( +
+
+
+ {hostedVM.icon && ( + + )} +
+ {hostedVM.icon && "・ "} + {hostedVM.name} +
+
+
+ + + + + + + + + + Edit VM + + + + General + Hardware + + Virtualization + + + +
+
+
+ +
+ { + const iconElements = + document.querySelectorAll( + "[data-vm-edit-icon-item]", + ) + const searchTerm = + e.target.value.toLowerCase() + + iconElements.forEach((el) => { + const iconName = + el + .getAttribute( + "data-icon-name", + ) + ?.toLowerCase() || "" + if ( + iconName.includes(searchTerm) + ) { + ;( + el as HTMLElement + ).style.display = "flex" + } else { + ;( + el as HTMLElement + ).style.display = "none" + } + }) + }} + /> + {Object.entries(iconCategories).map( + ([category, categoryIcons]) => ( +
+
+ {category} +
+ {categoryIcons.map((iconName) => ( + +
+ + {iconName} +
+
+ ))} +
+ ), + )} + + +
+
+
+ +
+ {editIcon && ( + + )} +
+
+
+
+ + setEditName(e.target.value)} + /> +
+
+ + +
+
+ + setEditIp(e.target.value)} + /> +
+
+ + setEditUrl(e.target.value)} + /> +
+
+
+ + +
+
+ + setEditCpu(e.target.value)} + /> +
+
+ + setEditGpu(e.target.value)} + /> +
+
+ + setEditRam(e.target.value)} + /> +
+
+ + setEditDisk(e.target.value)} + /> +
+
+
+ +
+
+ + setEditHost(checked === true) + } + disabled={ + server.hostedVMs && + server.hostedVMs.length > 0 + } + /> + +
+ {!editHost && ( +
+ + +
+ )} +
+
+
+
+
+ + Cancel + + +
+
+
+
+ +
+ +
+ +
+
+ + + OS: {hostedVM.os || "-"} + +
+
+ + + IP: {hostedVM.ip || "Not set"} + +
+
+ +
+

Hardware Information

+
+ +
+ + + CPU: {hostedVM.cpu || "-"} + +
+
+ + + GPU: {hostedVM.gpu || "-"} + +
+
+ + + RAM: {hostedVM.ram || "-"} + +
+
+ + + Disk: {hostedVM.disk || "-"} + +
+ + {hostedVM.monitoring && ( + <> +
+ +
+ +
+
+
+
+ + CPU +
+ + {hostedVM.cpuUsage || 0}% + +
+
+
80 ? "bg-destructive" : hostedVM.cpuUsage && hostedVM.cpuUsage > 60 ? "bg-amber-500" : "bg-emerald-500"}`} + style={{ width: `${hostedVM.cpuUsage || 0}%` }} + /> +
+
+ +
+
+
+ + RAM +
+ + {hostedVM.ramUsage || 0}% + +
+
+
80 ? "bg-destructive" : hostedVM.ramUsage && hostedVM.ramUsage > 60 ? "bg-amber-500" : "bg-emerald-500"}`} + style={{ width: `${hostedVM.ramUsage || 0}%` }} + /> +
+
+ +
+
+
+ + Disk +
+ + {hostedVM.diskUsage || 0}% + +
+
+
80 ? "bg-destructive" : hostedVM.diskUsage && hostedVM.diskUsage > 60 ? "bg-amber-500" : "bg-emerald-500"}`} + style={{ width: `${hostedVM.diskUsage || 0}%` }} + /> +
+
+
+ + )} +
+ ))} +
+ +
+ )} + + + + Close + + + + + View VMs ({server.hostedVMs.length}) + + + )} +
- -
-
- setEditMonitoring(checked === true)} - /> - -
- {editMonitoring && ( -
- - setEditMonitoringURL(e.target.value)} - /> -
- )} -
-
Cancel - Save Changes + diff --git a/package-lock.json b/package-lock.json index 698c024..cad316a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5062,6 +5062,21 @@ "optional": true } } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.0.tgz", + "integrity": "sha512-vHUQS4YVGJPmpjn7r5lEZuMhK5UQBNBRSB+iGDvJjaNk649pTIcRluDWNb9siunyLLiu/LDPHfvxBtNamyuLTw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } }