mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-11-18 03:26:17 +00:00
Update AppImage
This commit is contained in:
@@ -63,9 +63,14 @@ export function ProxmoxDashboard() {
|
||||
const [lastScrollY, setLastScrollY] = useState(0)
|
||||
|
||||
const fetchSystemData = useCallback(async () => {
|
||||
console.log("[v0] Fetching system data from Flask server...")
|
||||
console.log("[v0] Current window location:", window.location.href)
|
||||
|
||||
const baseUrl = typeof window !== "undefined" ? `${window.location.protocol}//${window.location.hostname}:8008` : ""
|
||||
const apiUrl = `${baseUrl}/api/system`
|
||||
|
||||
console.log("[v0] API URL:", apiUrl)
|
||||
|
||||
try {
|
||||
const response = await fetch(apiUrl, {
|
||||
method: "GET",
|
||||
@@ -74,12 +79,14 @@ export function ProxmoxDashboard() {
|
||||
},
|
||||
cache: "no-store",
|
||||
})
|
||||
console.log("[v0] Response status:", response.status)
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Server responded with status: ${response.status}`)
|
||||
}
|
||||
|
||||
const data: FlaskSystemData = await response.json()
|
||||
console.log("[v0] System data received:", data)
|
||||
|
||||
let status: "healthy" | "warning" | "critical" = "healthy"
|
||||
if (data.cpu_usage > 90 || data.memory_usage > 90) {
|
||||
@@ -97,6 +104,13 @@ export function ProxmoxDashboard() {
|
||||
})
|
||||
setIsServerConnected(true)
|
||||
} catch (error) {
|
||||
console.error("[v0] Failed to fetch system data from Flask server:", error)
|
||||
console.error("[v0] Error details:", {
|
||||
message: error instanceof Error ? error.message : "Unknown error",
|
||||
apiUrl,
|
||||
windowLocation: window.location.href,
|
||||
})
|
||||
|
||||
setIsServerConnected(false)
|
||||
setSystemStatus((prev) => ({
|
||||
...prev,
|
||||
@@ -234,7 +248,9 @@ export function ProxmoxDashboard() {
|
||||
|
||||
<header className="border-b border-border bg-card sticky top-0 z-50 shadow-sm">
|
||||
<div className="container mx-auto px-4 md:px-6 py-4 md:py-4">
|
||||
{/* Logo and Title */}
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
{/* Logo and Title */}
|
||||
<div className="flex items-center space-x-2 md:space-x-3 min-w-0">
|
||||
<div className="w-16 h-16 md:w-10 md:h-10 relative flex items-center justify-center bg-primary/10 flex-shrink-0">
|
||||
<Image
|
||||
@@ -245,6 +261,7 @@ export function ProxmoxDashboard() {
|
||||
className="object-contain md:w-10 md:h-10"
|
||||
priority
|
||||
onError={(e) => {
|
||||
console.log("[v0] Logo failed to load, using fallback icon")
|
||||
const target = e.target as HTMLImageElement
|
||||
target.style.display = "none"
|
||||
const fallback = target.parentElement?.querySelector(".fallback-icon")
|
||||
@@ -265,6 +282,7 @@ export function ProxmoxDashboard() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Desktop Actions */}
|
||||
<div className="hidden lg:flex items-center space-x-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Server className="h-4 w-4 text-muted-foreground" />
|
||||
@@ -294,6 +312,7 @@ export function ProxmoxDashboard() {
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
|
||||
{/* Mobile Actions */}
|
||||
<div className="flex lg:hidden items-center gap-2">
|
||||
<Badge variant="outline" className={`${statusColor} text-xs px-2`}>
|
||||
{statusIcon}
|
||||
@@ -308,6 +327,7 @@ export function ProxmoxDashboard() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Server Info */}
|
||||
<div className="lg:hidden mt-2 flex items-center justify-end text-xs text-muted-foreground">
|
||||
<span className="whitespace-nowrap">Uptime: {systemStatus.uptime}</span>
|
||||
</div>
|
||||
|
||||
@@ -109,12 +109,13 @@ const fetchSystemData = async (): Promise<SystemData | null> => {
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
throw new Error(`Flask server responded with status: ${response.status}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
return data
|
||||
} catch (error) {
|
||||
console.error("[v0] Failed to fetch system data:", error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -133,12 +134,13 @@ const fetchVMData = async (): Promise<VMData[]> => {
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
throw new Error(`Flask server responded with status: ${response.status}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
return data.vms || []
|
||||
return Array.isArray(data) ? data : data.vms || []
|
||||
} catch (error) {
|
||||
console.error("[v0] Failed to fetch VM data:", error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
@@ -157,12 +159,40 @@ const fetchStorageData = async (): Promise<StorageData | null> => {
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
console.log("[v0] Storage API not available (this is normal if not configured)")
|
||||
return null
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
return data
|
||||
} catch (error) {
|
||||
console.log("[v0] Storage data unavailable:", error instanceof Error ? error.message : "Unknown error")
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const fetchNetworkData = async (): Promise<NetworkData | null> => {
|
||||
try {
|
||||
const baseUrl = typeof window !== "undefined" ? `${window.location.protocol}//${window.location.hostname}:8008` : ""
|
||||
const apiUrl = `${baseUrl}/api/network`
|
||||
|
||||
const response = await fetch(apiUrl, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
cache: "no-store",
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
console.log("[v0] Network API not available (this is normal if not configured)")
|
||||
return null
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
return data
|
||||
} catch (error) {
|
||||
console.log("[v0] Network data unavailable:", error instanceof Error ? error.message : "Unknown error")
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -193,30 +223,6 @@ const fetchProxmoxStorageData = async (): Promise<ProxmoxStorageData | null> =>
|
||||
}
|
||||
}
|
||||
|
||||
const fetchNetworkData = async (): Promise<NetworkData | null> => {
|
||||
try {
|
||||
const baseUrl = typeof window !== "undefined" ? `${window.location.protocol}//${window.location.hostname}:8008` : ""
|
||||
const apiUrl = `${baseUrl}/api/network`
|
||||
|
||||
const response = await fetch(apiUrl, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
cache: "no-store",
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
return data
|
||||
} catch (error) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function SystemOverview() {
|
||||
const [systemData, setSystemData] = useState<SystemData | null>(null)
|
||||
const [vmData, setVmData] = useState<VMData[]>([])
|
||||
|
||||
@@ -1087,7 +1087,7 @@ def get_smart_data(disk_name):
|
||||
|
||||
smart_data['media_wearout_indicator'] = wear_used
|
||||
smart_data['ssd_life_left'] = max(0, 100 - wear_used)
|
||||
print(f"[v0] Media Wearout Indicator (ID 230): {smart_data['media_wearout_indicator']}% used, {smart_data['ssd_life_left']}% life left")
|
||||
print(f"[v0] Media Wearout Indicator (ID 230): {wear_used}% used, {smart_data['ssd_life_left']}% life left")
|
||||
except Exception as e:
|
||||
print(f"[v0] Error parsing Media_Wearout_Indicator (ID 230): {e}")
|
||||
elif attr_id == '233': # Media_Wearout_Indicator (Intel/Samsung SSD)
|
||||
@@ -2806,6 +2806,26 @@ def get_detailed_gpu_info(gpu):
|
||||
detailed_info['utilization_memory'] = round(mem_util, 1)
|
||||
print(f"[v0] Memory Utilization: {detailed_info['utilization_memory']}%", flush=True)
|
||||
|
||||
# Parse GRBM (Graphics Register Bus Manager) for engine utilization
|
||||
if 'GRBM' in device:
|
||||
grbm = device['GRBM']
|
||||
|
||||
# Graphics Pipe (similar to Render/3D)
|
||||
if 'Graphics Pipe' in grbm:
|
||||
gfx_pipe = grbm['Graphics Pipe']
|
||||
if 'value' in gfx_pipe:
|
||||
detailed_info['engine_render'] = f"{gfx_pipe['value']:.1f}%"
|
||||
|
||||
# Parse GRBM2 for additional engine info
|
||||
if 'GRBM2' in device:
|
||||
grbm2 = device['GRBM2']
|
||||
|
||||
# Texture Cache (similar to Blitter)
|
||||
if 'Texture Cache' in grbm2:
|
||||
tex_cache = grbm2['Texture Cache']
|
||||
if 'value' in tex_cache:
|
||||
detailed_info['engine_blitter'] = f"{tex_cache['value']:.1f}%"
|
||||
|
||||
# Parse processes (fdinfo)
|
||||
if 'fdinfo' in device:
|
||||
fdinfo = device['fdinfo']
|
||||
@@ -3871,11 +3891,14 @@ def api_network_interface_metrics(interface_name):
|
||||
print(f"[v0] ===== NETWORK INTERFACE METRICS REQUEST EXCEPTION =====")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
# ... existing code ...
|
||||
|
||||
@app.route('/api/vms', methods=['GET'])
|
||||
def api_vms():
|
||||
"""Get virtual machine information"""
|
||||
return jsonify(get_proxmox_vms())
|
||||
|
||||
# Add the new api_vm_metrics endpoint here
|
||||
@app.route('/api/vms/<int:vmid>/metrics', methods=['GET'])
|
||||
def api_vm_metrics(vmid):
|
||||
"""Get historical metrics (RRD data) for a specific VM/LXC"""
|
||||
|
||||
Reference in New Issue
Block a user