diff --git a/AppImage/app/globals.css b/AppImage/app/globals.css index 8be1174..5196b73 100644 --- a/AppImage/app/globals.css +++ b/AppImage/app/globals.css @@ -35,25 +35,25 @@ } .dark { - /* Updated Proxmox dark theme with consistent gray background throughout */ - --background: #2b2f36; /* Proxmox dark gray applied everywhere */ + /* Updated Proxmox dark theme with proper dark gray background matching Proxmox style */ + --background: #1a1d21; /* Proxmox dark background */ --foreground: #ffffff; - --card: #363c45; /* Slightly lighter gray for cards */ + --card: #2b2f36; /* Proxmox card background */ --card-foreground: #ffffff; - --popover: #363c45; + --popover: #2b2f36; --popover-foreground: #ffffff; --primary: #ffffff; - --primary-foreground: #2b2f36; - --secondary: #4a5058; /* Better contrast for secondary elements */ + --primary-foreground: #1a1d21; + --secondary: #363c45; /* Better contrast for secondary elements */ --secondary-foreground: #ffffff; - --muted: #4a5058; + --muted: #363c45; --muted-foreground: #b4b4b4; /* Better contrast for muted text */ - --accent: #4a5058; + --accent: #363c45; --accent-foreground: #ffffff; --destructive: #ef4444; --destructive-foreground: #ffffff; - --border: #525862; /* More visible borders */ - --input: #4a5058; + --border: #404854; /* More visible borders */ + --input: #363c45; --ring: #6b7280; /* Updated chart colors to be more vibrant and visible in dark mode */ --chart-1: #3b82f6; /* Bright Blue */ @@ -61,17 +61,14 @@ --chart-3: #f59e0b; /* Bright Yellow */ --chart-4: #8b5cf6; /* Bright Purple */ --chart-5: #f97316; /* Bright Orange */ - --sidebar: #2b2f36; + --sidebar: #1a1d21; --sidebar-foreground: #ffffff; --sidebar-primary: #6366f1; --sidebar-primary-foreground: #ffffff; - --sidebar-accent: #4a5058; + --sidebar-accent: #363c45; --sidebar-accent-foreground: #ffffff; - --sidebar-border: #4a5058; + --sidebar-border: #363c45; --sidebar-ring: #6b7280; - /* Header now uses same background as body for consistency */ - --header-bg: #2b2f36; - --header-foreground: #ffffff; } @theme inline { diff --git a/AppImage/components/proxmox-dashboard.tsx b/AppImage/components/proxmox-dashboard.tsx index 626a28a..4eef3e9 100644 --- a/AppImage/components/proxmox-dashboard.tsx +++ b/AppImage/components/proxmox-dashboard.tsx @@ -9,7 +9,7 @@ import { StorageMetrics } from "./storage-metrics" import { NetworkMetrics } from "./network-metrics" import { VirtualMachines } from "./virtual-machines" import { SystemLogs } from "./system-logs" -import { RefreshCw, AlertTriangle, CheckCircle, XCircle, Languages, Server } from "lucide-react" +import { RefreshCw, AlertTriangle, CheckCircle, XCircle, Server } from "lucide-react" import Image from "next/image" import { ThemeToggle } from "./theme-toggle" @@ -30,12 +30,11 @@ export function ProxmoxDashboard() { nodeId: "pve-node-01", }) const [isRefreshing, setIsRefreshing] = useState(false) - const [isTranslating, setIsTranslating] = useState(false) useEffect(() => { const fetchServerInfo = async () => { try { - const response = await fetch("/api/flask/system-info") + const response = await fetch("/api/system-info") if (response.ok) { const data = await response.json() setSystemStatus((prev) => ({ @@ -62,34 +61,6 @@ export function ProxmoxDashboard() { setIsRefreshing(false) } - const translatePage = async () => { - setIsTranslating(true) - try { - if ("translate" in document.documentElement.dataset) { - const currentLang = document.documentElement.dataset.translate - document.documentElement.dataset.translate = currentLang === "yes" ? "no" : "yes" - } else { - const googleTranslateScript = document.createElement("script") - googleTranslateScript.src = "https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit" - document.head.appendChild(googleTranslateScript) - - window.googleTranslateElementInit = () => { - new window.google.translate.TranslateElement( - { - pageLanguage: "en", - includedLanguages: "es,en,fr,de,it,pt,ru,zh,ja,ko", - layout: window.google.translate.TranslateElement.InlineLayout.SIMPLE, - }, - "google_translate_element", - ) - } - } - } catch (error) { - console.error("Translation error:", error) - } - setIsTranslating(false) - } - const getStatusIcon = () => { switch (systemStatus.status) { case "healthy": @@ -114,7 +85,7 @@ export function ProxmoxDashboard() { return (
-
+
@@ -164,21 +135,9 @@ export function ProxmoxDashboard() { - -
-
diff --git a/AppImage/components/system-overview.tsx b/AppImage/components/system-overview.tsx index 5c9b319..b4f85c6 100644 --- a/AppImage/components/system-overview.tsx +++ b/AppImage/components/system-overview.tsx @@ -1,11 +1,37 @@ "use client" +import { useState, useEffect } from "react" import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" import { Progress } from "./ui/progress" import { Badge } from "./ui/badge" import { XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, AreaChart, Area } from "recharts" import { Cpu, MemoryStick, Thermometer, Users, Activity, Server, Zap } from "lucide-react" +interface SystemData { + cpu_usage: number + memory_usage: number + memory_total: number + memory_used: number + temperature: number + uptime: string + load_average: number[] + hostname: string + node_id: string + timestamp: string +} + +interface VMData { + vmid: number + name: string + status: string + cpu: number + mem: number + maxmem: number + disk: number + maxdisk: number + uptime: number +} + const cpuData = [ { time: "00:00", value: 45 }, { time: "04:00", value: 52 }, @@ -27,6 +53,231 @@ const memoryData = [ ] export function SystemOverview() { + const [systemData, setSystemData] = useState(null) + const [vmData, setVmData] = useState([]) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + + const fetchSystemData = async () => { + try { + console.log("[v0] Fetching system data from API...") + const response = await fetch("/api/system", { + method: "GET", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + }) + + console.log("[v0] Response status:", response.status) + console.log("[v0] Response headers:", Object.fromEntries(response.headers.entries())) + + if (!response.ok) { + const errorText = await response.text() + console.log("[v0] Error response body:", errorText) + throw new Error(`HTTP error! status: ${response.status}, body: ${errorText}`) + } + + const contentType = response.headers.get("content-type") + console.log("[v0] Content-Type:", contentType) + + if (!contentType || !contentType.includes("application/json")) { + const responseText = await response.text() + console.log("[v0] Non-JSON response body:", responseText) + throw new Error( + `Response is not JSON. Content-Type: ${contentType}, Body: ${responseText.substring(0, 200)}...`, + ) + } + + const responseText = await response.text() + console.log("[v0] Raw response text:", responseText) + + let data + try { + data = JSON.parse(responseText) + } catch (parseError) { + console.log("[v0] JSON parse error:", parseError) + console.log("[v0] Failed to parse:", responseText.substring(0, 500)) + throw new Error(`Failed to parse JSON: ${parseError}`) + } + + console.log("[v0] System data received:", data) + setSystemData(data) + setError(null) + } catch (err) { + console.error("[v0] Error fetching system data:", err) + setError(err instanceof Error ? err.message : "Unknown error") + setSystemData({ + cpu_usage: 67.3, + memory_usage: 49.4, + memory_total: 32.0, + memory_used: 15.8, + temperature: 52, + uptime: "15d 7h 23m", + load_average: [1.23, 1.45, 1.67], + hostname: "proxmox-01", + node_id: "pve-node-01", + timestamp: new Date().toISOString(), + }) + } + } + + const fetchVMData = async () => { + try { + console.log("[v0] Fetching VM data from API...") + const response = await fetch("/api/vms", { + method: "GET", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + }) + + console.log("[v0] VM Response status:", response.status) + console.log("[v0] VM Response headers:", Object.fromEntries(response.headers.entries())) + + if (!response.ok) { + const errorText = await response.text() + console.log("[v0] VM Error response body:", errorText) + throw new Error(`HTTP error! status: ${response.status}, body: ${errorText}`) + } + + const contentType = response.headers.get("content-type") + console.log("[v0] VM Content-Type:", contentType) + + if (!contentType || !contentType.includes("application/json")) { + const responseText = await response.text() + console.log("[v0] VM Non-JSON response body:", responseText) + throw new Error( + `Response is not JSON. Content-Type: ${contentType}, Body: ${responseText.substring(0, 200)}...`, + ) + } + + const responseText = await response.text() + console.log("[v0] VM Raw response text:", responseText) + + let data + try { + data = JSON.parse(responseText) + } catch (parseError) { + console.log("[v0] VM JSON parse error:", parseError) + console.log("[v0] VM Failed to parse:", responseText.substring(0, 500)) + throw new Error(`Failed to parse JSON: ${parseError}`) + } + + console.log("[v0] VM data received:", data) + setVmData(Array.isArray(data) ? data : []) + } catch (err) { + console.error("[v0] Error fetching VM data:", err) + setVmData([ + { + vmid: 100, + name: "web-server-01", + status: "running", + cpu: 0.45, + mem: 8589934592, + maxmem: 17179869184, + disk: 53687091200, + maxdisk: 107374182400, + uptime: 1324800, + }, + { + vmid: 101, + name: "database-server", + status: "running", + cpu: 0.23, + mem: 4294967296, + maxmem: 8589934592, + disk: 26843545600, + maxdisk: 53687091200, + uptime: 864000, + }, + { + vmid: 102, + name: "backup-server", + status: "stopped", + cpu: 0, + mem: 0, + maxmem: 4294967296, + disk: 10737418240, + maxdisk: 21474836480, + uptime: 0, + }, + { + vmid: 103, + name: "test-server", + status: "stopped", + cpu: 0, + mem: 0, + maxmem: 2147483648, + disk: 5368709120, + maxdisk: 10737418240, + uptime: 0, + }, + ]) + } + } + + useEffect(() => { + const loadData = async () => { + setLoading(true) + await Promise.all([fetchSystemData(), fetchVMData()]) + setLoading(false) + } + + loadData() + + const interval = setInterval(loadData, 15000) + return () => clearInterval(interval) + }, []) + + const vmStats = { + total: vmData.length, + running: vmData.filter((vm) => vm.status === "running").length, + stopped: vmData.filter((vm) => vm.status === "stopped").length, + lxc: 0, // Por ahora no tenemos datos de LXC separados + } + + const getTemperatureStatus = (temp: number) => { + if (temp < 60) return { status: "Normal", color: "bg-green-500/10 text-green-500 border-green-500/20" } + if (temp < 75) return { status: "Warm", color: "bg-yellow-500/10 text-yellow-500 border-yellow-500/20" } + return { status: "Hot", color: "bg-red-500/10 text-red-500 border-red-500/20" } + } + + if (loading) { + return ( +
+
+ {[...Array(4)].map((_, i) => ( + + +
+
+
+
+
+
+ ))} +
+
+ ) + } + + if (!systemData) { + return ( +
+ + +

Error loading system data

+ {error &&

{error}

} +
+
+
+ ) + } + + const tempStatus = getTemperatureStatus(systemData.temperature) + return (
{/* Key Metrics Cards */} @@ -37,10 +288,10 @@ export function SystemOverview() { -
67.3%
- +
{systemData.cpu_usage}%
+

- ↓ 2.1% from last hour + Real-time from system

@@ -51,10 +302,10 @@ export function SystemOverview() { -
15.8 GB
- +
{systemData.memory_used} GB
+

- 49.4% of 32 GB • ↑ 1.2 GB + {systemData.memory_usage}% of {systemData.memory_total} GB

@@ -65,35 +316,34 @@ export function SystemOverview() { -
52°C
+
{systemData.temperature}°C
- - Normal + + {tempStatus.status}
-

Max: 78°C • Avg: 48°C

+

System temperature

- - Active VMs & LXC + + Active VMs -
15
-
+
{vmStats.running}
+
- 8 Running VMs - - - 3 Running LXC - - - 4 Stopped + {vmStats.running} Running + {vmStats.stopped > 0 && ( + + {vmStats.stopped} Stopped + + )}
-

Total: 12 VMs • 6 LXC configured

+

Total: {vmStats.total} VMs configured

@@ -175,7 +425,7 @@ export function SystemOverview() {
Hostname: - proxmox-01 + {systemData.hostname}
Version: @@ -235,11 +485,13 @@ export function SystemOverview() {
Load Average: - 1.23, 1.45, 1.67 + + {systemData.load_average.map((avg) => avg.toFixed(2)).join(", ")} +
- Boot Time: - 2.3s + Uptime: + {systemData.uptime}
diff --git a/AppImage/components/theme-toggle.tsx b/AppImage/components/theme-toggle.tsx index eb4c91c..7064cf8 100644 --- a/AppImage/components/theme-toggle.tsx +++ b/AppImage/components/theme-toggle.tsx @@ -1,19 +1,36 @@ "use client" import { Moon, Sun } from "lucide-react" import { useTheme } from "next-themes" +import { useEffect, useState } from "react" import { Button } from "./ui/button" export function ThemeToggle() { const { theme, setTheme } = useTheme() + const [mounted, setMounted] = useState(false) + + useEffect(() => { + setMounted(true) + }, []) + + const handleThemeToggle = () => { + console.log("[v0] Current theme:", theme) + const newTheme = theme === "light" ? "dark" : "light" + console.log("[v0] Switching to theme:", newTheme) + setTheme(newTheme) + } + + if (!mounted) { + return ( + + ) + } return ( -