Feature: Storage cylinder chart no dashboard - cilindro transparente com preenchimento verde mostrando uso de storage
This commit is contained in:
@@ -342,6 +342,114 @@
|
|||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Storage Cylinder Chart */
|
||||||
|
.storage-cylinder-card {
|
||||||
|
background: linear-gradient(135deg, #2B2B2B 0%, #1E1E1E 100%);
|
||||||
|
border: 1px solid #404040;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.storage-cylinder-card:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.storage-cylinder {
|
||||||
|
width: 80px;
|
||||||
|
height: 120px;
|
||||||
|
position: relative;
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cylinder-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cylinder-outline {
|
||||||
|
width: 60px;
|
||||||
|
height: 100px;
|
||||||
|
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 30px;
|
||||||
|
position: relative;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cylinder-fill {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: linear-gradient(to top,
|
||||||
|
rgba(34, 197, 94, 0.8) 0%,
|
||||||
|
rgba(34, 197, 94, 0.6) 50%,
|
||||||
|
rgba(34, 197, 94, 0.4) 100%);
|
||||||
|
border-radius: 0 0 27px 27px;
|
||||||
|
transition: height 0.8s ease-in-out;
|
||||||
|
min-height: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cylinder-top {
|
||||||
|
position: absolute;
|
||||||
|
top: -3px;
|
||||||
|
left: -3px;
|
||||||
|
width: 66px;
|
||||||
|
height: 20px;
|
||||||
|
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-bottom: none;
|
||||||
|
border-radius: 33px 33px 0 0;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cylinder-bottom {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -3px;
|
||||||
|
left: -3px;
|
||||||
|
width: 66px;
|
||||||
|
height: 20px;
|
||||||
|
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-top: none;
|
||||||
|
border-radius: 0 0 33px 33px;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.storage-cylinder-info {
|
||||||
|
margin-top: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.storage-cylinder-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--pf-global--Color--200);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.storage-cylinder-value {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--pf-global--Color--100);
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.storage-cylinder-percentage {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--pf-global--success-color--100);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
/* Chart Cards */
|
/* Chart Cards */
|
||||||
.chart-card {
|
.chart-card {
|
||||||
@@ -1821,6 +1929,50 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Storage Overview -->
|
||||||
|
<div class="metrics-grid" style="margin-top: 24px;">
|
||||||
|
<div class="storage-cylinder-card">
|
||||||
|
<div class="metric-icon success">
|
||||||
|
<i class="fas fa-database"></i>
|
||||||
|
</div>
|
||||||
|
<div class="storage-cylinder">
|
||||||
|
<div class="cylinder-container">
|
||||||
|
<div class="cylinder-outline">
|
||||||
|
<div class="cylinder-fill" id="storage-cylinder-fill" style="height: 0%"></div>
|
||||||
|
</div>
|
||||||
|
<div class="cylinder-top"></div>
|
||||||
|
<div class="cylinder-bottom"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="storage-cylinder-info">
|
||||||
|
<div class="storage-cylinder-label">Storage Usage</div>
|
||||||
|
<div class="storage-cylinder-value" id="storage-cylinder-used">-</div>
|
||||||
|
<div class="storage-cylinder-percentage" id="storage-cylinder-percentage">0%</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-icon info">
|
||||||
|
<i class="fas fa-hdd"></i>
|
||||||
|
</div>
|
||||||
|
<div class="metric-value" id="dashboard-total-pvcs">-</div>
|
||||||
|
<div class="metric-label">Total PVCs</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-icon warning">
|
||||||
|
<i class="fas fa-exclamation-triangle"></i>
|
||||||
|
</div>
|
||||||
|
<div class="metric-value" id="dashboard-storage-warnings">-</div>
|
||||||
|
<div class="metric-label">Storage Warnings</div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-card">
|
||||||
|
<div class="metric-icon success">
|
||||||
|
<i class="fas fa-chart-pie"></i>
|
||||||
|
</div>
|
||||||
|
<div class="metric-value" id="dashboard-storage-classes">-</div>
|
||||||
|
<div class="metric-label">Storage Classes</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Dashboard Charts Section -->
|
<!-- Dashboard Charts Section -->
|
||||||
<div class="dashboard-charts-section" style="margin-top: 32px;">
|
<div class="dashboard-charts-section" style="margin-top: 32px;">
|
||||||
<h2 style="color: var(--pf-global--Color--100); margin-bottom: 24px; font-size: 24px; font-weight: 600;">Resource Analytics</h2>
|
<h2 style="color: var(--pf-global--Color--100); margin-bottom: 24px; font-size: 24px; font-weight: 600;">Resource Analytics</h2>
|
||||||
@@ -2727,6 +2879,86 @@
|
|||||||
return 'Healthy';
|
return 'Healthy';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dashboard Storage Functions
|
||||||
|
async function loadDashboardStorageData() {
|
||||||
|
try {
|
||||||
|
console.log('Loading dashboard storage data...');
|
||||||
|
|
||||||
|
// Load storage data from API
|
||||||
|
const response = await fetch('/api/v1/storage/analysis');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
// Update dashboard storage metrics
|
||||||
|
updateDashboardStorageMetrics(data);
|
||||||
|
|
||||||
|
console.log('Dashboard storage data loaded successfully');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading dashboard storage data:', error);
|
||||||
|
// Don't show error for storage data, just log it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDashboardStorageMetrics(data) {
|
||||||
|
try {
|
||||||
|
// Update storage metrics cards
|
||||||
|
document.getElementById('dashboard-total-pvcs').textContent = data.total_pvcs || '0';
|
||||||
|
document.getElementById('dashboard-storage-warnings').textContent = data.storage_warnings || '0';
|
||||||
|
document.getElementById('dashboard-storage-classes').textContent = data.storage_classes ? data.storage_classes.length : '0';
|
||||||
|
|
||||||
|
// Update storage cylinder
|
||||||
|
updateStorageCylinder(data);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating dashboard storage metrics:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateStorageCylinder(data) {
|
||||||
|
try {
|
||||||
|
const totalStorageUsed = data.total_storage_used || 0;
|
||||||
|
const storageUtilization = data.storage_utilization_percent || 0;
|
||||||
|
|
||||||
|
// Calculate cylinder fill percentage (use storage utilization or mock calculation)
|
||||||
|
const fillPercentage = Math.min(100, Math.max(0, storageUtilization));
|
||||||
|
|
||||||
|
// Update cylinder fill
|
||||||
|
const cylinderFill = document.getElementById('storage-cylinder-fill');
|
||||||
|
if (cylinderFill) {
|
||||||
|
cylinderFill.style.height = `${fillPercentage}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update cylinder info
|
||||||
|
document.getElementById('storage-cylinder-used').textContent = formatBytes(totalStorageUsed);
|
||||||
|
document.getElementById('storage-cylinder-percentage').textContent = `${fillPercentage.toFixed(1)}%`;
|
||||||
|
|
||||||
|
// Change color based on utilization level
|
||||||
|
const cylinderPercentage = document.getElementById('storage-cylinder-percentage');
|
||||||
|
if (cylinderPercentage) {
|
||||||
|
if (fillPercentage >= 90) {
|
||||||
|
cylinderPercentage.style.color = 'var(--pf-global--danger-color--100)';
|
||||||
|
cylinderFill.style.background = 'linear-gradient(to top, rgba(220, 38, 38, 0.8) 0%, rgba(220, 38, 38, 0.6) 50%, rgba(220, 38, 38, 0.4) 100%)';
|
||||||
|
} else if (fillPercentage >= 75) {
|
||||||
|
cylinderPercentage.style.color = 'var(--pf-global--warning-color--100)';
|
||||||
|
cylinderFill.style.background = 'linear-gradient(to top, rgba(245, 158, 11, 0.8) 0%, rgba(245, 158, 11, 0.6) 50%, rgba(245, 158, 11, 0.4) 100%)';
|
||||||
|
} else if (fillPercentage >= 50) {
|
||||||
|
cylinderPercentage.style.color = 'var(--pf-global--info-color--100)';
|
||||||
|
cylinderFill.style.background = 'linear-gradient(to top, rgba(59, 130, 246, 0.8) 0%, rgba(59, 130, 246, 0.6) 50%, rgba(59, 130, 246, 0.4) 100%)';
|
||||||
|
} else {
|
||||||
|
cylinderPercentage.style.color = 'var(--pf-global--success-color--100)';
|
||||||
|
cylinderFill.style.background = 'linear-gradient(to top, rgba(34, 197, 94, 0.8) 0%, rgba(34, 197, 94, 0.6) 50%, rgba(34, 197, 94, 0.4) 100%)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating storage cylinder:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the application
|
// Initialize the application
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
initializeApp();
|
initializeApp();
|
||||||
@@ -3088,6 +3320,9 @@
|
|||||||
// Update metrics cards with results
|
// Update metrics cards with results
|
||||||
updateMetricsCards(statusData.result);
|
updateMetricsCards(statusData.result);
|
||||||
|
|
||||||
|
// Load storage data for dashboard
|
||||||
|
await loadDashboardStorageData();
|
||||||
|
|
||||||
// Load dashboard charts
|
// Load dashboard charts
|
||||||
updateSmartProgress(100, 'Loading dashboard charts...');
|
updateSmartProgress(100, 'Loading dashboard charts...');
|
||||||
await loadDashboardCharts();
|
await loadDashboardCharts();
|
||||||
|
|||||||
Reference in New Issue
Block a user