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 (
-