mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-11-18 11:36:17 +00:00
Update AppImage
This commit is contained in:
@@ -66,6 +66,19 @@ interface ProxmoxStorageData {
|
|||||||
error?: string
|
error?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const formatStorage = (sizeInGB: number): string => {
|
||||||
|
if (sizeInGB < 1) {
|
||||||
|
// Less than 1 GB, show in MB
|
||||||
|
return `${(sizeInGB * 1024).toFixed(1)} MB`
|
||||||
|
} else if (sizeInGB < 1024) {
|
||||||
|
// Less than 1024 GB, show in GB
|
||||||
|
return `${sizeInGB.toFixed(1)} GB`
|
||||||
|
} else {
|
||||||
|
// 1024 GB or more, show in TB
|
||||||
|
return `${(sizeInGB / 1024).toFixed(1)} TB`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function StorageOverview() {
|
export function StorageOverview() {
|
||||||
const [storageData, setStorageData] = useState<StorageData | null>(null)
|
const [storageData, setStorageData] = useState<StorageData | null>(null)
|
||||||
const [proxmoxStorage, setProxmoxStorage] = useState<ProxmoxStorageData | null>(null)
|
const [proxmoxStorage, setProxmoxStorage] = useState<ProxmoxStorageData | null>(null)
|
||||||
@@ -257,7 +270,7 @@ export function StorageOverview() {
|
|||||||
<Database className="h-4 w-4 text-muted-foreground" />
|
<Database className="h-4 w-4 text-muted-foreground" />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="text-2xl font-bold">{totalProxmoxUsed.toFixed(1)} GB</div>
|
<div className="text-2xl font-bold">{formatStorage(totalProxmoxUsed)}</div>
|
||||||
<p className="text-xs text-muted-foreground mt-1">{usagePercent}% used</p>
|
<p className="text-xs text-muted-foreground mt-1">{usagePercent}% used</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -383,6 +383,19 @@ export function SystemOverview() {
|
|||||||
return (bytes / 1024 ** 3).toFixed(2)
|
return (bytes / 1024 ** 3).toFixed(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const formatStorage = (sizeInGB: number): string => {
|
||||||
|
if (sizeInGB < 1) {
|
||||||
|
// Less than 1 GB, show in MB
|
||||||
|
return `${(sizeInGB * 1024).toFixed(1)} MB`
|
||||||
|
} else if (sizeInGB < 1024) {
|
||||||
|
// Less than 1024 GB, show in GB
|
||||||
|
return `${sizeInGB.toFixed(1)} GB`
|
||||||
|
} else {
|
||||||
|
// 1024 GB or more, show in TB
|
||||||
|
return `${(sizeInGB / 1024).toFixed(1)} TB`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const tempStatus = getTemperatureStatus(systemData.temperature)
|
const tempStatus = getTemperatureStatus(systemData.temperature)
|
||||||
|
|
||||||
const localStorage = proxmoxStorageData?.storage.find(
|
const localStorage = proxmoxStorageData?.storage.find(
|
||||||
@@ -623,15 +636,15 @@ export function SystemOverview() {
|
|||||||
|
|
||||||
<div className="pt-2 border-t border-border space-y-2">
|
<div className="pt-2 border-t border-border space-y-2">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span className="text-sm text-muted-foreground">Data Sent:</span>
|
<span className="text-sm text-muted-foreground">Received:</span>
|
||||||
<span className="text-lg font-semibold text-foreground">
|
<span className="text-lg font-semibold text-green-500 flex items-center gap-1">
|
||||||
{(networkData.traffic.bytes_sent / 1024 ** 3).toFixed(2)} GB
|
↓ {formatStorage(networkData.traffic.bytes_recv / 1024 ** 3)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span className="text-sm text-muted-foreground">Data Received:</span>
|
<span className="text-sm text-muted-foreground">Sent:</span>
|
||||||
<span className="text-lg font-semibold text-foreground">
|
<span className="text-lg font-semibold text-blue-500 flex items-center gap-1">
|
||||||
{(networkData.traffic.bytes_recv / 1024 ** 3).toFixed(2)} GB
|
↑ {formatStorage(networkData.traffic.bytes_sent / 1024 ** 3)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -114,6 +114,19 @@ const extractIPFromConfig = (config?: VMConfig): string => {
|
|||||||
return "DHCP"
|
return "DHCP"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const formatStorage = (sizeInGB: number): string => {
|
||||||
|
if (sizeInGB < 1) {
|
||||||
|
// Less than 1 GB, show in MB
|
||||||
|
return `${(sizeInGB * 1024).toFixed(1)} MB`
|
||||||
|
} else if (sizeInGB < 1024) {
|
||||||
|
// Less than 1024 GB, show in GB
|
||||||
|
return `${sizeInGB.toFixed(1)} GB`
|
||||||
|
} else {
|
||||||
|
// 1024 GB or more, show in TB
|
||||||
|
return `${(sizeInGB / 1024).toFixed(1)} TB`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function VirtualMachines() {
|
export function VirtualMachines() {
|
||||||
const {
|
const {
|
||||||
data: vmData,
|
data: vmData,
|
||||||
@@ -419,7 +432,7 @@ export function VirtualMachines() {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="text-2xl font-bold text-foreground">
|
<div className="text-2xl font-bold text-foreground">
|
||||||
{(safeVMData.reduce((sum, vm) => sum + (vm.maxdisk || 0), 0) / 1024 ** 3).toFixed(1)} GB
|
{formatStorage(safeVMData.reduce((sum, vm) => sum + (vm.maxdisk || 0), 0) / 1024 ** 3)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-muted-foreground mt-2">Allocated disk space</p>
|
<p className="text-xs text-muted-foreground mt-2">Allocated disk space</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@@ -3672,8 +3672,7 @@ def api_backups():
|
|||||||
# Get content of storage
|
# Get content of storage
|
||||||
content_result = subprocess.run(
|
content_result = subprocess.run(
|
||||||
['pvesh', 'get', f'/nodes/localhost/storage/{storage_id}/content', '--output-format', 'json'],
|
['pvesh', 'get', f'/nodes/localhost/storage/{storage_id}/content', '--output-format', 'json'],
|
||||||
capture_output=True, text=True, timeout=10
|
capture_output=True, text=True, timeout=10)
|
||||||
)
|
|
||||||
|
|
||||||
if content_result.returncode == 0:
|
if content_result.returncode == 0:
|
||||||
contents = json.loads(content_result.stdout)
|
contents = json.loads(content_result.stdout)
|
||||||
@@ -4097,8 +4096,7 @@ def api_vm_details(vmid):
|
|||||||
# Get detailed config
|
# Get detailed config
|
||||||
config_result = subprocess.run(
|
config_result = subprocess.run(
|
||||||
['pvesh', 'get', f'/nodes/{node}/{vm_type}/{vmid}/config', '--output-format', 'json'],
|
['pvesh', 'get', f'/nodes/{node}/{vm_type}/{vmid}/config', '--output-format', 'json'],
|
||||||
capture_output=True, text=True, timeout=10
|
capture_output=True, text=True, timeout=10)
|
||||||
)
|
|
||||||
|
|
||||||
config = {}
|
config = {}
|
||||||
if config_result.returncode == 0:
|
if config_result.returncode == 0:
|
||||||
@@ -4143,8 +4141,7 @@ def api_vm_logs(vmid):
|
|||||||
# Get real logs from the container/VM (last 1000 lines)
|
# Get real logs from the container/VM (last 1000 lines)
|
||||||
log_result = subprocess.run(
|
log_result = subprocess.run(
|
||||||
['pvesh', 'get', f'/nodes/{node}/{vm_type}/{vmid}/log', '--start', '0', '--limit', '1000'],
|
['pvesh', 'get', f'/nodes/{node}/{vm_type}/{vmid}/log', '--start', '0', '--limit', '1000'],
|
||||||
capture_output=True, text=True, timeout=10
|
capture_output=True, text=True, timeout=10)
|
||||||
)
|
|
||||||
|
|
||||||
logs = []
|
logs = []
|
||||||
if log_result.returncode == 0:
|
if log_result.returncode == 0:
|
||||||
@@ -4198,8 +4195,7 @@ def api_vm_control(vmid):
|
|||||||
# Execute action
|
# Execute action
|
||||||
control_result = subprocess.run(
|
control_result = subprocess.run(
|
||||||
['pvesh', 'create', f'/nodes/{node}/{vm_type}/{vmid}/status/{action}'],
|
['pvesh', 'create', f'/nodes/{node}/{vm_type}/{vmid}/status/{action}'],
|
||||||
capture_output=True, text=True, timeout=30
|
capture_output=True, text=True, timeout=30)
|
||||||
)
|
|
||||||
|
|
||||||
if control_result.returncode == 0:
|
if control_result.returncode == 0:
|
||||||
return jsonify({
|
return jsonify({
|
||||||
@@ -4222,8 +4218,18 @@ def api_vm_control(vmid):
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# API endpoints available at: /api/system, /api/system-info, /api/storage, /api/proxmox-storage, /api/network, /api/vms, /api/logs, /api/health, /api/hardware
|
# API endpoints available at: /api/system, /api/system-info, /api/storage, /api/proxmox-storage, /api/network, /api/vms, /api/logs, /api/health, /api/hardware
|
||||||
|
|
||||||
|
import sys
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
# Silence werkzeug logger
|
||||||
log = logging.getLogger('werkzeug')
|
log = logging.getLogger('werkzeug')
|
||||||
log.setLevel(logging.ERROR)
|
log.setLevel(logging.ERROR)
|
||||||
|
|
||||||
|
# Silence Flask CLI banner (removes "Serving Flask app", "Debug mode", "WARNING" messages)
|
||||||
|
cli = sys.modules['flask.cli']
|
||||||
|
cli.show_server_banner = lambda *x: None
|
||||||
|
|
||||||
|
# Print only essential information
|
||||||
|
print("API endpoints available at: /api/system, /api/system-info, /api/storage, /api/proxmox-storage, /api/network, /api/vms, /api/logs, /api/health, /api/hardware")
|
||||||
|
|
||||||
app.run(host='0.0.0.0', port=8008, debug=False)
|
app.run(host='0.0.0.0', port=8008, debug=False)
|
||||||
|
|||||||
Reference in New Issue
Block a user