First Commit
This commit is contained in:
335
templates/overview.html
Normal file
335
templates/overview.html
Normal file
@@ -0,0 +1,335 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Overview - Proxmox Manager{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="dashboard-header">
|
||||
<div>
|
||||
<h1>Dashboard Overview</h1>
|
||||
<p class="subtitle">Riepilogo di tutte le tue macchine virtuali</p>
|
||||
</div>
|
||||
<div class="dashboard-actions">
|
||||
<button class="btn btn-ghost btn-sm" onclick="loadOverviewStats()">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/>
|
||||
<path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/>
|
||||
</svg>
|
||||
Aggiorna
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stats Cards -->
|
||||
<div class="stats-grid" id="stats-grid">
|
||||
<div class="stat-card stat-total">
|
||||
<div class="stat-icon">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
|
||||
<line x1="8" y1="21" x2="16" y2="21"/>
|
||||
<line x1="12" y1="17" x2="12" y2="21"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value" id="total-vms">-</div>
|
||||
<div class="stat-label">VM Totali</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card stat-running">
|
||||
<div class="stat-icon">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--accent-green)" stroke-width="2">
|
||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
|
||||
<polyline points="22 4 12 14.01 9 11.01"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value" id="running-vms">-</div>
|
||||
<div class="stat-label">In Esecuzione</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card stat-stopped">
|
||||
<div class="stat-icon">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--accent-red)" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<line x1="15" y1="9" x2="9" y2="15"/>
|
||||
<line x1="9" y1="9" x2="15" y2="15"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value" id="stopped-vms">-</div>
|
||||
<div class="stat-label">Ferme</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card stat-cpu">
|
||||
<div class="stat-icon">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--accent-purple)" stroke-width="2">
|
||||
<rect x="4" y="4" width="16" height="16" rx="2" ry="2"/>
|
||||
<rect x="9" y="9" width="6" height="6"/>
|
||||
<line x1="9" y1="1" x2="9" y2="4"/>
|
||||
<line x1="15" y1="1" x2="15" y2="4"/>
|
||||
<line x1="9" y1="20" x2="9" y2="23"/>
|
||||
<line x1="15" y1="20" x2="15" y2="23"/>
|
||||
<line x1="20" y1="9" x2="23" y2="9"/>
|
||||
<line x1="20" y1="14" x2="23" y2="14"/>
|
||||
<line x1="1" y1="9" x2="4" y2="9"/>
|
||||
<line x1="1" y1="14" x2="4" y2="14"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value" id="avg-cpu">-</div>
|
||||
<div class="stat-label">CPU Medio</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Resource Charts -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-title">Utilizzo Risorse</div>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-xl);">
|
||||
<div>
|
||||
<h3 style="color: var(--text-secondary); font-size: 0.9rem; margin-bottom: var(--space-md);">Memoria Totale</h3>
|
||||
<div style="height: 200px; position: relative;">
|
||||
<canvas id="memoryChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 style="color: var(--text-secondary); font-size: 0.9rem; margin-bottom: var(--space-md);">Stato VM</h3>
|
||||
<div style="height: 200px; position: relative;">
|
||||
<canvas id="statusChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- VM List -->
|
||||
<div class="card">
|
||||
<div class="card-title">Le Tue Macchine Virtuali</div>
|
||||
<div class="vm-overview-list" id="vm-list">
|
||||
<div class="loading">
|
||||
<div class="spinner"></div>
|
||||
<p>Caricamento...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script>
|
||||
let memoryChart = null;
|
||||
let statusChart = null;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadOverviewStats();
|
||||
});
|
||||
|
||||
async function loadOverviewStats() {
|
||||
const result = await apiCall('/api/overview/stats');
|
||||
|
||||
if (result.status === 'success') {
|
||||
const data = result.data;
|
||||
|
||||
// Update stat cards
|
||||
document.getElementById('total-vms').textContent = data.total_vms;
|
||||
document.getElementById('running-vms').textContent = data.running_vms;
|
||||
document.getElementById('stopped-vms').textContent = data.stopped_vms;
|
||||
document.getElementById('avg-cpu').textContent = data.avg_cpu_usage + '%';
|
||||
|
||||
// Render charts
|
||||
renderMemoryChart(data);
|
||||
renderStatusChart(data);
|
||||
|
||||
// Render VM list
|
||||
renderVMList(data.vms);
|
||||
} else {
|
||||
document.getElementById('vm-list').innerHTML = `
|
||||
<div class="alert alert-error">
|
||||
Errore nel caricamento: ${result.message}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
function renderMemoryChart(data) {
|
||||
const ctx = document.getElementById('memoryChart').getContext('2d');
|
||||
|
||||
if (memoryChart) {
|
||||
memoryChart.destroy();
|
||||
}
|
||||
|
||||
const usedMemory = data.total_memory_used || 0;
|
||||
const freeMemory = (data.total_memory_max || 0) - usedMemory;
|
||||
|
||||
memoryChart = new Chart(ctx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: ['Utilizzata', 'Disponibile'],
|
||||
datasets: [{
|
||||
data: [usedMemory, freeMemory],
|
||||
backgroundColor: ['#a371f7', '#21262d'],
|
||||
borderWidth: 0,
|
||||
borderRadius: 4
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
cutout: '70%',
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'bottom',
|
||||
labels: {
|
||||
color: '#8b949e',
|
||||
usePointStyle: true,
|
||||
padding: 16
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
backgroundColor: '#21262d',
|
||||
titleColor: '#e6edf3',
|
||||
bodyColor: '#8b949e',
|
||||
borderColor: '#30363d',
|
||||
borderWidth: 1,
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
return formatBytes(context.raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [{
|
||||
id: 'centerText',
|
||||
afterDraw: function(chart) {
|
||||
const ctx = chart.ctx;
|
||||
const centerX = (chart.chartArea.left + chart.chartArea.right) / 2;
|
||||
const centerY = (chart.chartArea.top + chart.chartArea.bottom) / 2;
|
||||
|
||||
ctx.save();
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
|
||||
ctx.fillStyle = '#e6edf3';
|
||||
ctx.font = 'bold 24px sans-serif';
|
||||
ctx.fillText(data.memory_percent + '%', centerX, centerY - 8);
|
||||
|
||||
ctx.fillStyle = '#8b949e';
|
||||
ctx.font = '12px sans-serif';
|
||||
ctx.fillText('utilizzata', centerX, centerY + 14);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
function renderStatusChart(data) {
|
||||
const ctx = document.getElementById('statusChart').getContext('2d');
|
||||
|
||||
if (statusChart) {
|
||||
statusChart.destroy();
|
||||
}
|
||||
|
||||
statusChart = new Chart(ctx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: ['Running', 'Stopped'],
|
||||
datasets: [{
|
||||
data: [data.running_vms, data.stopped_vms],
|
||||
backgroundColor: ['#3fb950', '#f85149'],
|
||||
borderWidth: 0,
|
||||
borderRadius: 4
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
cutout: '70%',
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'bottom',
|
||||
labels: {
|
||||
color: '#8b949e',
|
||||
usePointStyle: true,
|
||||
padding: 16
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
backgroundColor: '#21262d',
|
||||
titleColor: '#e6edf3',
|
||||
bodyColor: '#8b949e',
|
||||
borderColor: '#30363d',
|
||||
borderWidth: 1
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [{
|
||||
id: 'centerText',
|
||||
afterDraw: function(chart) {
|
||||
const ctx = chart.ctx;
|
||||
const centerX = (chart.chartArea.left + chart.chartArea.right) / 2;
|
||||
const centerY = (chart.chartArea.top + chart.chartArea.bottom) / 2;
|
||||
|
||||
ctx.save();
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
|
||||
ctx.fillStyle = '#e6edf3';
|
||||
ctx.font = 'bold 24px sans-serif';
|
||||
ctx.fillText(data.total_vms, centerX, centerY - 8);
|
||||
|
||||
ctx.fillStyle = '#8b949e';
|
||||
ctx.font = '12px sans-serif';
|
||||
ctx.fillText('totali', centerX, centerY + 14);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
function renderVMList(vms) {
|
||||
const container = document.getElementById('vm-list');
|
||||
|
||||
if (!vms || vms.length === 0) {
|
||||
container.innerHTML = `
|
||||
<p class="text-muted text-center" style="padding: var(--space-xl);">
|
||||
Nessuna VM assegnata
|
||||
</p>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = vms.map(vm => {
|
||||
const statusClass = vm.status === 'running' ? 'status-running' : 'status-stopped';
|
||||
const statusText = vm.status === 'running' ? 'Running' : 'Stopped';
|
||||
const cpuPercent = Math.round((vm.cpu || 0) * 100);
|
||||
|
||||
return `
|
||||
<div class="vm-overview-item">
|
||||
<div class="vm-overview-info">
|
||||
<span class="status-badge ${statusClass}" style="margin-right: var(--space-md);">${statusText}</span>
|
||||
<div>
|
||||
<div class="vm-overview-name">${vm.name}</div>
|
||||
<div class="vm-overview-id">ID: ${vm.vm_id}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vm-overview-metrics">
|
||||
<div class="vm-overview-metric">
|
||||
<div class="vm-overview-metric-value">${cpuPercent}%</div>
|
||||
<div class="vm-overview-metric-label">CPU</div>
|
||||
</div>
|
||||
<div class="vm-overview-metric">
|
||||
<div class="vm-overview-metric-value">${vm.memory_percent || 0}%</div>
|
||||
<div class="vm-overview-metric-label">RAM</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vm-overview-actions">
|
||||
<a href="{{ url_for('dashboard') }}" class="btn btn-ghost btn-sm">Gestisci</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user