|
|
@@ -197,23 +197,29 @@ function displayVMDetails(vm, vmName) {
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <!-- Performance Charts -->
|
|
|
+ <!-- Performance Indicators -->
|
|
|
${vm.state === 'running' ? `
|
|
|
<div class="card">
|
|
|
<div class="card-header">
|
|
|
<h6 class="card-title mb-0"><i class="bi bi-graph-up"></i> Rendimiento</h6>
|
|
|
</div>
|
|
|
<div class="card-body">
|
|
|
- <div class="row">
|
|
|
- <div class="col-md-6">
|
|
|
- <div style="position: relative; height: 250px;">
|
|
|
- <canvas id="cpuChart"></canvas>
|
|
|
- </div>
|
|
|
+ <div class="mb-3">
|
|
|
+ <div class="d-flex justify-content-between mb-1">
|
|
|
+ <strong><i class="bi bi-cpu"></i> CPU</strong>
|
|
|
+ <span id="cpuPercent">0%</span>
|
|
|
</div>
|
|
|
- <div class="col-md-6">
|
|
|
- <div style="position: relative; height: 250px;">
|
|
|
- <canvas id="memoryChart"></canvas>
|
|
|
- </div>
|
|
|
+ <div class="progress" style="height: 25px;">
|
|
|
+ <div id="cpuBar" class="progress-bar bg-primary" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="d-flex justify-content-between mb-1">
|
|
|
+ <strong><i class="bi bi-memory"></i> Memoria</strong>
|
|
|
+ <span id="memPercent">0%</span>
|
|
|
+ </div>
|
|
|
+ <div class="progress" style="height: 25px;">
|
|
|
+ <div id="memBar" class="progress-bar bg-warning" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -988,22 +994,15 @@ async function deleteSnapshot(vmName, snapshotName) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// Chart instances storage
|
|
|
-let cpuChart = null;
|
|
|
-let memoryChart = null;
|
|
|
+// Performance monitoring
|
|
|
let statsInterval = null;
|
|
|
-const statsHistory = {
|
|
|
- cpu: [],
|
|
|
- memory: [],
|
|
|
- maxPoints: 20
|
|
|
-};
|
|
|
|
|
|
-// Initialize and update performance charts
|
|
|
+// Initialize and update performance indicators
|
|
|
async function initializePerformanceCharts(vmName) {
|
|
|
// Clear any existing interval
|
|
|
if (statsInterval) clearInterval(statsInterval);
|
|
|
|
|
|
- // Initialize charts immediately
|
|
|
+ // Update immediately
|
|
|
await updatePerformanceStats(vmName);
|
|
|
|
|
|
// Update every 2 seconds
|
|
|
@@ -1021,44 +1020,28 @@ async function updatePerformanceStats(vmName) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- const timestamp = new Date().toLocaleTimeString('es-ES', {
|
|
|
- hour: '2-digit',
|
|
|
- minute: '2-digit',
|
|
|
- second: '2-digit'
|
|
|
- });
|
|
|
-
|
|
|
- // Update history
|
|
|
- statsHistory.cpu.push({
|
|
|
- time: timestamp,
|
|
|
- value: data.cpu_percent
|
|
|
- });
|
|
|
- statsHistory.memory.push({
|
|
|
- time: timestamp,
|
|
|
- value: data.memory_percent
|
|
|
- });
|
|
|
-
|
|
|
- // Keep only last maxPoints
|
|
|
- if (statsHistory.cpu.length > statsHistory.maxPoints) {
|
|
|
- statsHistory.cpu.shift();
|
|
|
- statsHistory.memory.shift();
|
|
|
+ // Update CPU bar
|
|
|
+ const cpuPercent = data.cpu_percent;
|
|
|
+ const cpuBar = document.getElementById('cpuBar');
|
|
|
+ const cpuPercentEl = document.getElementById('cpuPercent');
|
|
|
+ if (cpuBar) {
|
|
|
+ cpuBar.style.width = cpuPercent + '%';
|
|
|
+ cpuBar.setAttribute('aria-valuenow', cpuPercent);
|
|
|
}
|
|
|
-
|
|
|
- // Update CPU Chart
|
|
|
- if (cpuChart) {
|
|
|
- cpuChart.data.labels = statsHistory.cpu.map(s => s.time);
|
|
|
- cpuChart.data.datasets[0].data = statsHistory.cpu.map(s => s.value);
|
|
|
- cpuChart.update('none');
|
|
|
- } else {
|
|
|
- createCPUChart();
|
|
|
+ if (cpuPercentEl) {
|
|
|
+ cpuPercentEl.textContent = cpuPercent.toFixed(1) + '%';
|
|
|
}
|
|
|
|
|
|
- // Update Memory Chart
|
|
|
- if (memoryChart) {
|
|
|
- memoryChart.data.labels = statsHistory.memory.map(s => s.time);
|
|
|
- memoryChart.data.datasets[0].data = statsHistory.memory.map(s => s.value);
|
|
|
- memoryChart.update('none');
|
|
|
- } else {
|
|
|
- createMemoryChart();
|
|
|
+ // Update Memory bar
|
|
|
+ const memPercent = data.memory_percent;
|
|
|
+ const memBar = document.getElementById('memBar');
|
|
|
+ const memPercentEl = document.getElementById('memPercent');
|
|
|
+ if (memBar) {
|
|
|
+ memBar.style.width = memPercent + '%';
|
|
|
+ memBar.setAttribute('aria-valuenow', memPercent);
|
|
|
+ }
|
|
|
+ if (memPercentEl) {
|
|
|
+ memPercentEl.textContent = memPercent.toFixed(1) + '%';
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
@@ -1066,176 +1049,14 @@ async function updatePerformanceStats(vmName) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// Create CPU chart
|
|
|
-function createCPUChart() {
|
|
|
- const ctx = document.getElementById('cpuChart');
|
|
|
- if (!ctx) return;
|
|
|
-
|
|
|
- // Destroy existing chart if any
|
|
|
- if (cpuChart) cpuChart.destroy();
|
|
|
-
|
|
|
- cpuChart = new Chart(ctx, {
|
|
|
- type: 'line',
|
|
|
- data: {
|
|
|
- labels: statsHistory.cpu.map(s => s.time),
|
|
|
- datasets: [{
|
|
|
- label: 'CPU (%)',
|
|
|
- data: statsHistory.cpu.map(s => s.value),
|
|
|
- borderColor: '#667eea',
|
|
|
- backgroundColor: 'rgba(102, 126, 234, 0.1)',
|
|
|
- tension: 0.4,
|
|
|
- fill: true,
|
|
|
- borderWidth: 2,
|
|
|
- pointRadius: 4,
|
|
|
- pointBackgroundColor: '#667eea',
|
|
|
- pointBorderColor: '#fff',
|
|
|
- pointBorderWidth: 2,
|
|
|
- pointHoverRadius: 6
|
|
|
- }],
|
|
|
- },
|
|
|
- options: {
|
|
|
- responsive: true,
|
|
|
- maintainAspectRatio: false,
|
|
|
- plugins: {
|
|
|
- legend: {
|
|
|
- display: true,
|
|
|
- labels: {
|
|
|
- font: { size: 12 },
|
|
|
- padding: 15,
|
|
|
- color: '#666'
|
|
|
- }
|
|
|
- },
|
|
|
- tooltip: {
|
|
|
- backgroundColor: 'rgba(0,0,0,0.8)',
|
|
|
- padding: 12,
|
|
|
- titleFont: { size: 12 },
|
|
|
- bodyFont: { size: 12 },
|
|
|
- callbacks: {
|
|
|
- label: function(context) {
|
|
|
- return context.dataset.label + ': ' + context.parsed.y.toFixed(2) + '%';
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- scales: {
|
|
|
- y: {
|
|
|
- beginAtZero: true,
|
|
|
- max: 100,
|
|
|
- ticks: {
|
|
|
- stepSize: 25,
|
|
|
- callback: function(value) {
|
|
|
- return value + '%';
|
|
|
- }
|
|
|
- },
|
|
|
- grid: {
|
|
|
- color: 'rgba(0,0,0,0.05)'
|
|
|
- }
|
|
|
- },
|
|
|
- x: {
|
|
|
- grid: {
|
|
|
- color: 'rgba(0,0,0,0.05)'
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-// Create Memory chart
|
|
|
-function createMemoryChart() {
|
|
|
- const ctx = document.getElementById('memoryChart');
|
|
|
- if (!ctx) return;
|
|
|
-
|
|
|
- // Destroy existing chart if any
|
|
|
- if (memoryChart) memoryChart.destroy();
|
|
|
-
|
|
|
- memoryChart = new Chart(ctx, {
|
|
|
- type: 'line',
|
|
|
- data: {
|
|
|
- labels: statsHistory.memory.map(s => s.time),
|
|
|
- datasets: [{
|
|
|
- label: 'Memoria (%)',
|
|
|
- data: statsHistory.memory.map(s => s.value),
|
|
|
- borderColor: '#764ba2',
|
|
|
- backgroundColor: 'rgba(118, 75, 162, 0.1)',
|
|
|
- tension: 0.4,
|
|
|
- fill: true,
|
|
|
- borderWidth: 2,
|
|
|
- pointRadius: 4,
|
|
|
- pointBackgroundColor: '#764ba2',
|
|
|
- pointBorderColor: '#fff',
|
|
|
- pointBorderWidth: 2,
|
|
|
- pointHoverRadius: 6
|
|
|
- }],
|
|
|
- },
|
|
|
- options: {
|
|
|
- responsive: true,
|
|
|
- maintainAspectRatio: false,
|
|
|
- plugins: {
|
|
|
- legend: {
|
|
|
- display: true,
|
|
|
- labels: {
|
|
|
- font: { size: 12 },
|
|
|
- padding: 15,
|
|
|
- color: '#666'
|
|
|
- }
|
|
|
- },
|
|
|
- tooltip: {
|
|
|
- backgroundColor: 'rgba(0,0,0,0.8)',
|
|
|
- padding: 12,
|
|
|
- titleFont: { size: 12 },
|
|
|
- bodyFont: { size: 12 },
|
|
|
- callbacks: {
|
|
|
- label: function(context) {
|
|
|
- return context.dataset.label + ': ' + context.parsed.y.toFixed(2) + '%';
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- scales: {
|
|
|
- y: {
|
|
|
- beginAtZero: true,
|
|
|
- max: 100,
|
|
|
- ticks: {
|
|
|
- stepSize: 25,
|
|
|
- callback: function(value) {
|
|
|
- return value + '%';
|
|
|
- }
|
|
|
- },
|
|
|
- grid: {
|
|
|
- color: 'rgba(0,0,0,0.05)'
|
|
|
- }
|
|
|
- },
|
|
|
- x: {
|
|
|
- grid: {
|
|
|
- color: 'rgba(0,0,0,0.05)'
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
-}
|
|
|
|
|
|
-// Clean up charts when switching VMs
|
|
|
+// Clean up performance monitoring when switching VMs
|
|
|
function cleanupCharts() {
|
|
|
if (statsInterval) {
|
|
|
clearInterval(statsInterval);
|
|
|
statsInterval = null;
|
|
|
}
|
|
|
-
|
|
|
- if (cpuChart) {
|
|
|
- cpuChart.destroy();
|
|
|
- cpuChart = null;
|
|
|
- }
|
|
|
-
|
|
|
- if (memoryChart) {
|
|
|
- memoryChart.destroy();
|
|
|
- memoryChart = null;
|
|
|
- }
|
|
|
-
|
|
|
- // Reset history
|
|
|
- statsHistory.cpu = [];
|
|
|
- statsHistory.memory = [];
|
|
|
}
|
|
|
|
|
|
|
|
|
+
|