feat: restore circular gauges for system health display
- Replaced horizontal progress bars with beautiful circular SVG gauges - Added smooth animations for gauge updates - Color-coded gauges (green < 70%, orange < 85%, red >= 85%) - Centered layout with better visual hierarchy - Maintains auto-refresh and dynamic updates 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
d61dcf2821
commit
b7e9b21b47
@ -141,52 +141,64 @@
|
|||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Progress Bars */
|
/* Circular Gauges */
|
||||||
.secubox-health-grid {
|
.secubox-health-grid {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-direction: column;
|
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||||
gap: 20px;
|
gap: 24px;
|
||||||
|
justify-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.secubox-progress-item {
|
.secubox-gauge-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secubox-progress-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.secubox-progress-label {
|
.secubox-gauge {
|
||||||
font-weight: 600;
|
position: relative;
|
||||||
color: #1e293b;
|
width: 120px;
|
||||||
font-size: 14px;
|
height: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.secubox-progress-value {
|
.secubox-gauge-svg {
|
||||||
font-weight: 700;
|
width: 100%;
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secubox-progress-bar {
|
|
||||||
height: 8px;
|
|
||||||
background: #f1f5f9;
|
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secubox-progress-fill {
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
transition: width 0.6s ease, background 0.3s ease;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.secubox-progress-details {
|
.secubox-gauge-progress {
|
||||||
|
transition: stroke-dashoffset 0.8s ease, stroke 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secubox-gauge-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secubox-gauge-percent {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secubox-gauge-label {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secubox-gauge-details {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #64748b;
|
||||||
|
text-align: center;
|
||||||
|
max-width: 140px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Active Modules */
|
/* Active Modules */
|
||||||
|
|||||||
@ -154,39 +154,64 @@ return view.extend({
|
|||||||
return E('div', { 'class': 'secubox-card' }, [
|
return E('div', { 'class': 'secubox-card' }, [
|
||||||
E('h3', { 'class': 'secubox-card-title' }, '📊 System Health'),
|
E('h3', { 'class': 'secubox-card-title' }, '📊 System Health'),
|
||||||
E('div', { 'class': 'secubox-health-grid' }, [
|
E('div', { 'class': 'secubox-health-grid' }, [
|
||||||
this.renderProgressBar('CPU', cpu.percent || 0, cpu.load_1min || '0.00', 'cpu'),
|
this.renderCircularGauge('CPU', cpu.percent || 0,
|
||||||
this.renderProgressBar('Memory', memory.percent || 0,
|
'Load: ' + (cpu.load_1min || '0.00'), 'cpu', '#6366f1'),
|
||||||
|
this.renderCircularGauge('Memory', memory.percent || 0,
|
||||||
API.formatBytes((memory.used_kb || 0) * 1024) + ' / ' +
|
API.formatBytes((memory.used_kb || 0) * 1024) + ' / ' +
|
||||||
API.formatBytes((memory.total_kb || 0) * 1024), 'memory'),
|
API.formatBytes((memory.total_kb || 0) * 1024), 'memory', '#22c55e'),
|
||||||
this.renderProgressBar('Disk', disk.percent || 0,
|
this.renderCircularGauge('Disk', disk.percent || 0,
|
||||||
API.formatBytes((disk.used_kb || 0) * 1024) + ' / ' +
|
API.formatBytes((disk.used_kb || 0) * 1024) + ' / ' +
|
||||||
API.formatBytes((disk.total_kb || 0) * 1024), 'disk')
|
API.formatBytes((disk.total_kb || 0) * 1024), 'disk', '#f59e0b')
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
renderProgressBar: function(label, percent, details, id) {
|
renderCircularGauge: function(label, percent, details, id, baseColor) {
|
||||||
var color = percent < 70 ? '#22c55e' : percent < 85 ? '#f59e0b' : '#ef4444';
|
var color = percent < 70 ? '#22c55e' : percent < 85 ? '#f59e0b' : '#ef4444';
|
||||||
|
var radius = 45;
|
||||||
|
var circumference = 2 * Math.PI * radius;
|
||||||
|
var offset = circumference - (percent / 100) * circumference;
|
||||||
|
|
||||||
return E('div', { 'class': 'secubox-progress-item' }, [
|
return E('div', { 'class': 'secubox-gauge-container' }, [
|
||||||
E('div', { 'class': 'secubox-progress-header' }, [
|
E('div', { 'class': 'secubox-gauge' }, [
|
||||||
E('span', { 'class': 'secubox-progress-label' }, label),
|
E('svg', { 'viewBox': '0 0 120 120', 'class': 'secubox-gauge-svg' }, [
|
||||||
E('span', {
|
// Background circle
|
||||||
'class': 'secubox-progress-value',
|
E('circle', {
|
||||||
'id': 'health-' + id + '-percent',
|
'cx': '60',
|
||||||
'style': 'color: ' + color
|
'cy': '60',
|
||||||
}, percent + '%')
|
'r': radius,
|
||||||
]),
|
'fill': 'none',
|
||||||
E('div', { 'class': 'secubox-progress-bar' }, [
|
'stroke': '#f1f5f9',
|
||||||
E('div', {
|
'stroke-width': '10'
|
||||||
'class': 'secubox-progress-fill',
|
}),
|
||||||
'id': 'health-' + id + '-bar',
|
// Progress circle
|
||||||
'style': 'width: ' + percent + '%; background: ' + color
|
E('circle', {
|
||||||
})
|
'id': 'gauge-' + id,
|
||||||
|
'cx': '60',
|
||||||
|
'cy': '60',
|
||||||
|
'r': radius,
|
||||||
|
'fill': 'none',
|
||||||
|
'stroke': color,
|
||||||
|
'stroke-width': '10',
|
||||||
|
'stroke-linecap': 'round',
|
||||||
|
'stroke-dasharray': circumference,
|
||||||
|
'stroke-dashoffset': offset,
|
||||||
|
'transform': 'rotate(-90 60 60)',
|
||||||
|
'class': 'secubox-gauge-progress'
|
||||||
|
})
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'secubox-gauge-content' }, [
|
||||||
|
E('div', {
|
||||||
|
'class': 'secubox-gauge-percent',
|
||||||
|
'id': 'gauge-' + id + '-percent',
|
||||||
|
'style': 'color: ' + color
|
||||||
|
}, Math.round(percent) + '%'),
|
||||||
|
E('div', { 'class': 'secubox-gauge-label' }, label)
|
||||||
|
])
|
||||||
]),
|
]),
|
||||||
E('div', {
|
E('div', {
|
||||||
'class': 'secubox-progress-details',
|
'class': 'secubox-gauge-details',
|
||||||
'id': 'health-' + id + '-details'
|
'id': 'gauge-' + id + '-details'
|
||||||
}, details)
|
}, details)
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
@ -371,16 +396,31 @@ return view.extend({
|
|||||||
var percent = data.percent || 0;
|
var percent = data.percent || 0;
|
||||||
var color = percent < 70 ? '#22c55e' : percent < 85 ? '#f59e0b' : '#ef4444';
|
var color = percent < 70 ? '#22c55e' : percent < 85 ? '#f59e0b' : '#ef4444';
|
||||||
|
|
||||||
var percentEl = document.getElementById('health-' + type + '-percent');
|
var percentEl = document.getElementById('gauge-' + type + '-percent');
|
||||||
var barEl = document.getElementById('health-' + type + '-bar');
|
var gaugeEl = document.getElementById('gauge-' + type);
|
||||||
|
|
||||||
if (percentEl) {
|
if (percentEl) {
|
||||||
percentEl.textContent = percent + '%';
|
percentEl.textContent = Math.round(percent) + '%';
|
||||||
percentEl.style.color = color;
|
percentEl.style.color = color;
|
||||||
}
|
}
|
||||||
if (barEl) {
|
if (gaugeEl) {
|
||||||
barEl.style.width = percent + '%';
|
var radius = 45;
|
||||||
barEl.style.background = color;
|
var circumference = 2 * Math.PI * radius;
|
||||||
|
var offset = circumference - (percent / 100) * circumference;
|
||||||
|
gaugeEl.setAttribute('stroke-dashoffset', offset);
|
||||||
|
gaugeEl.setAttribute('stroke', color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update details
|
||||||
|
var detailsEl = document.getElementById('gauge-' + type + '-details');
|
||||||
|
if (detailsEl && type === 'cpu') {
|
||||||
|
detailsEl.textContent = 'Load: ' + (data.load_1min || '0.00');
|
||||||
|
} else if (detailsEl && type === 'memory') {
|
||||||
|
detailsEl.textContent = API.formatBytes((data.used_kb || 0) * 1024) + ' / ' +
|
||||||
|
API.formatBytes((data.total_kb || 0) * 1024);
|
||||||
|
} else if (detailsEl && type === 'disk') {
|
||||||
|
detailsEl.textContent = API.formatBytes((data.used_kb || 0) * 1024) + ' / ' +
|
||||||
|
API.formatBytes((data.total_kb || 0) * 1024);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user