diff --git a/luci-app-secubox/htdocs/luci-static/resources/secubox/secubox.css b/luci-app-secubox/htdocs/luci-static/resources/secubox/secubox.css index ecd26c0e..3e1f6935 100644 --- a/luci-app-secubox/htdocs/luci-static/resources/secubox/secubox.css +++ b/luci-app-secubox/htdocs/luci-static/resources/secubox/secubox.css @@ -21,6 +21,55 @@ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } +/* Stats Overview */ +.secubox-stats-overview { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 16px; + margin: 20px 0; +} + +.secubox-stat-box { + background: var(--sb-bg-card); + border: 1px solid var(--sb-border); + border-radius: 8px; + padding: 20px; + display: flex; + align-items: center; + gap: 16px; + transition: all 0.2s ease; +} + +.secubox-stat-box:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + +.secubox-stat-icon { + font-size: 36px; + line-height: 1; +} + +.secubox-stat-content { + flex: 1; +} + +.secubox-stat-value { + font-size: 32px; + font-weight: 700; + color: var(--sb-text); + line-height: 1; + margin-bottom: 4px; +} + +.secubox-stat-label { + font-size: 12px; + color: var(--sb-text-muted); + text-transform: uppercase; + letter-spacing: 0.5px; + font-weight: 600; +} + /* SecuBox brand colors for each module */ .sb-color-crowdsec { --module-color: #22c55e; } .sb-color-netdata { --module-color: #00ab44; } diff --git a/luci-app-secubox/htdocs/luci-static/resources/view/secubox/dashboard.js b/luci-app-secubox/htdocs/luci-static/resources/view/secubox/dashboard.js index 1d26c1da..35f5db70 100644 --- a/luci-app-secubox/htdocs/luci-static/resources/view/secubox/dashboard.js +++ b/luci-app-secubox/htdocs/luci-static/resources/view/secubox/dashboard.js @@ -9,7 +9,7 @@ document.head.appendChild(E('link', { 'rel': 'stylesheet', 'type': 'text/css', - 'href': L.resource('secubox/dashboard.css') + 'href': L.resource('secubox/secubox.css') })); return view.extend({ @@ -37,30 +37,38 @@ return view.extend({ render: function(data) { var self = this; - var container = E('div', { 'class': 'secubox-dashboard' }); - - // Header with version var status = this.dashboardData.status || {}; - container.appendChild(this.renderHeader(status)); + var modules = this.dashboardData.modules || []; + var counts = this.dashboardData.counts || {}; + var alerts = this.alertsData.alerts || []; - // Stats Overview Cards - container.appendChild(this.renderStatsOverview()); + var container = E('div', { 'class': 'cbi-map secubox-dashboard' }); - // Main Content Grid - var mainGrid = E('div', { 'class': 'secubox-main-grid' }, [ - // Left column - E('div', { 'class': 'secubox-column-left' }, [ - this.renderSystemHealth(this.healthData), - this.renderAlerts(this.alertsData.alerts || []) - ]), - // Right column - E('div', { 'class': 'secubox-column-right' }, [ - this.renderActiveModules(), - this.renderQuickActions() - ]) - ]); + // Header + container.appendChild(E('h2', {}, '๐Ÿ›ก๏ธ SecuBox Central Hub')); + container.appendChild(E('p', {}, + 'Hostname: ' + (status.hostname || 'Unknown') + ' | ' + + 'Uptime: ' + API.formatUptime(status.uptime) + ' | ' + + 'Load: ' + (status.load || '0.00') + ' | ' + + 'Version: ' + (status.version || 'v0.0.1-beta') + )); - container.appendChild(mainGrid); + // Stats Overview + container.appendChild(this.renderStatsOverview(counts, alerts)); + + // System Health Section + container.appendChild(this.renderSystemHealth(this.healthData)); + + // Quick Actions Section + container.appendChild(this.renderQuickActions()); + + // Alerts Section + if (alerts.length > 0) { + container.appendChild(this.renderAlerts(alerts)); + } + + // Modules Grid + container.appendChild(this.renderModulesGrid(modules)); // Start auto-refresh poll poll.add(function() { @@ -72,237 +80,113 @@ return view.extend({ return container; }, - renderHeader: function(status) { - return E('div', { 'class': 'secubox-header' }, [ - E('div', { 'class': 'secubox-header-content' }, [ - E('div', {}, [ - E('h2', {}, '๐Ÿ›ก๏ธ SecuBox Central Hub'), - E('p', { 'class': 'secubox-subtitle' }, 'Security & Network Management Suite') - ]), - E('div', { 'class': 'secubox-header-info' }, [ - E('span', { 'class': 'secubox-badge secubox-badge-version' }, - 'v' + (status.version || '0.0.1-beta')), - E('span', { 'class': 'secubox-badge' }, - 'โฑ๏ธ ' + API.formatUptime(status.uptime)), - E('span', { 'class': 'secubox-badge', 'id': 'secubox-hostname' }, - '๐Ÿ–ฅ๏ธ ' + (status.hostname || 'SecuBox')) + renderStatsOverview: function(counts, alerts) { + return E('div', { 'class': 'secubox-stats-overview' }, [ + E('div', { 'class': 'secubox-stat-box' }, [ + E('div', { 'class': 'secubox-stat-icon' }, '๐Ÿ“ฆ'), + E('div', { 'class': 'secubox-stat-content' }, [ + E('div', { 'class': 'secubox-stat-value', 'id': 'stat-total' }, counts.total || 0), + E('div', { 'class': 'secubox-stat-label' }, 'Total Modules') + ]) + ]), + E('div', { 'class': 'secubox-stat-box' }, [ + E('div', { 'class': 'secubox-stat-icon' }, 'โœ…'), + E('div', { 'class': 'secubox-stat-content' }, [ + E('div', { 'class': 'secubox-stat-value', 'id': 'stat-installed', 'style': 'color: #22c55e' }, counts.installed || 0), + E('div', { 'class': 'secubox-stat-label' }, 'Installed') + ]) + ]), + E('div', { 'class': 'secubox-stat-box' }, [ + E('div', { 'class': 'secubox-stat-icon' }, 'โ–ถ๏ธ'), + E('div', { 'class': 'secubox-stat-content' }, [ + E('div', { 'class': 'secubox-stat-value', 'id': 'stat-running', 'style': 'color: #00ab44' }, counts.running || 0), + E('div', { 'class': 'secubox-stat-label' }, 'Running') + ]) + ]), + E('div', { 'class': 'secubox-stat-box' }, [ + E('div', { 'class': 'secubox-stat-icon' }, 'โš ๏ธ'), + E('div', { 'class': 'secubox-stat-content' }, [ + E('div', { 'class': 'secubox-stat-value', 'id': 'stat-alerts', 'style': 'color: #f59e0b' }, alerts.length || 0), + E('div', { 'class': 'secubox-stat-label' }, 'Alerts') ]) ]) ]); }, - renderStatsOverview: function() { - var modules = this.dashboardData.modules || []; - var counts = this.dashboardData.counts || {}; - - var stats = [ - { - label: 'Total Modules', - value: counts.total || modules.length, - icon: '๐Ÿ“ฆ', - color: '#6366f1', - id: 'stat-total' - }, - { - label: 'Installed', - value: counts.installed || 0, - icon: 'โœ“', - color: '#22c55e', - id: 'stat-installed' - }, - { - label: 'Running', - value: counts.running || 0, - icon: 'โ–ถ', - color: '#00ab44', - id: 'stat-running' - }, - { - label: 'Alerts', - value: (this.alertsData.alerts || []).length, - icon: 'โš ๏ธ', - color: '#f59e0b', - id: 'stat-alerts' - } - ]; - - return E('div', { 'class': 'secubox-stats-grid' }, - stats.map(function(stat) { - return E('div', { - 'class': 'secubox-stat-card', - 'style': 'border-top: 3px solid ' + stat.color - }, [ - E('div', { 'class': 'secubox-stat-icon' }, stat.icon), - E('div', { 'class': 'secubox-stat-content' }, [ - E('div', { - 'class': 'secubox-stat-value', - 'id': stat.id, - 'style': 'color: ' + stat.color - }, stat.value), - E('div', { 'class': 'secubox-stat-label' }, stat.label) - ]) - ]); - }) - ); - }, - renderSystemHealth: function(health) { var cpu = health.cpu || {}; var memory = health.memory || {}; var disk = health.disk || {}; + var network = health.network || {}; - return E('div', { 'class': 'secubox-card' }, [ - E('h3', { 'class': 'secubox-card-title' }, '๐Ÿ“Š System Health'), + var section = E('div', { 'class': 'secubox-health-section' }, [ + E('h3', {}, '๐Ÿ“Š System Health'), E('div', { 'class': 'secubox-health-grid' }, [ - this.renderCircularGauge('CPU', cpu.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.total_kb || 0) * 1024), 'memory', '#22c55e'), - this.renderCircularGauge('Disk', disk.percent || 0, - API.formatBytes((disk.used_kb || 0) * 1024) + ' / ' + - API.formatBytes((disk.total_kb || 0) * 1024), 'disk', '#f59e0b') + this.renderGauge('CPU', cpu.percent || 0, '%', 'Load: ' + (cpu.load_1min || '0.00'), 'cpu'), + this.renderGauge('Memory', memory.percent || 0, '%', + API.formatBytes((memory.used_kb || 0) * 1024) + ' / ' + API.formatBytes((memory.total_kb || 0) * 1024), 'memory'), + this.renderGauge('Disk', disk.percent || 0, '%', + API.formatBytes((disk.used_kb || 0) * 1024) + ' / ' + API.formatBytes((disk.total_kb || 0) * 1024), 'disk'), + this.renderGauge('Network', 0, '', + 'RX: ' + API.formatBytes(network.rx_bytes || 0) + ' | TX: ' + API.formatBytes(network.tx_bytes || 0), 'network') ]) ]); + + return section; }, - renderCircularGauge: function(label, percent, details, id, baseColor) { + renderGauge: function(label, percent, unit, details, id) { 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-gauge-container' }, [ - E('div', { 'class': 'secubox-gauge' }, [ - E('svg', { 'viewBox': '0 0 120 120', 'class': 'secubox-gauge-svg' }, [ - // Background circle + return E('div', { 'class': 'secubox-gauge' }, [ + E('div', { 'class': 'secubox-gauge-label' }, label), + E('div', { 'class': 'secubox-gauge-chart' }, [ + E('svg', { 'width': '120', 'height': '120', 'viewBox': '0 0 120 120' }, [ E('circle', { - 'cx': '60', - 'cy': '60', - 'r': radius, - 'fill': 'none', - 'stroke': '#f1f5f9', - 'stroke-width': '10' + 'cx': '60', 'cy': '60', 'r': '54', + 'fill': 'none', 'stroke': '#1e293b', 'stroke-width': '12' }), - // Progress circle E('circle', { - 'id': 'gauge-' + id, - 'cx': '60', - 'cy': '60', - 'r': radius, - 'fill': 'none', - 'stroke': color, - 'stroke-width': '10', + 'id': 'gauge-circle-' + id, + 'cx': '60', 'cy': '60', 'r': '54', + 'fill': 'none', 'stroke': color, 'stroke-width': '12', + 'stroke-dasharray': (339.292 * percent / 100) + ' 339.292', '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) + 'transform': 'rotate(-90 60 60)' + }), + E('text', { + 'id': 'gauge-text-' + id, + 'x': '60', 'y': '65', 'text-anchor': 'middle', + 'font-size': '24', 'font-weight': 'bold', 'fill': color + }, Math.round(percent) + unit) ]) ]), - E('div', { - 'class': 'secubox-gauge-details', - 'id': 'gauge-' + id + '-details' - }, details) - ]); - }, - - renderActiveModules: function() { - var modules = this.dashboardData.modules || []; - var activeModules = modules.filter(function(m) { return m.installed; }); - - // Map module IDs to their dashboard paths - var modulePaths = { - 'crowdsec': 'admin/secubox/security/crowdsec', - 'netdata': 'admin/secubox/monitoring/netdata', - 'netifyd': 'admin/secubox/security/netifyd', - 'wireguard': 'admin/secubox/network/wireguard', - 'network_modes': 'admin/secubox/network/modes', - 'client_guardian': 'admin/secubox/security/guardian', - 'system_hub': 'admin/secubox/system/hub', - 'bandwidth_manager': 'admin/secubox/network/bandwidth', - 'auth_guardian': 'admin/secubox/security/auth', - 'media_flow': 'admin/secubox/network/media', - 'vhost_manager': 'admin/secubox/system/vhost', - 'traffic_shaper': 'admin/secubox/network/shaper', - 'cdn_cache': 'admin/secubox/network/cdn', - 'ksm_manager': 'admin/secubox/security/ksm' - }; - - var moduleCards = activeModules.map(function(module) { - var isRunning = module.running; - var statusClass = isRunning ? 'running' : 'stopped'; - var dashboardPath = modulePaths[module.id] || ('admin/secubox/' + module.id); - - return E('a', { - 'href': L.url(dashboardPath), - 'class': 'secubox-module-link secubox-module-' + statusClass - }, [ - E('div', { - 'class': 'secubox-module-mini-card', - 'style': 'border-left: 4px solid ' + (module.color || '#64748b') - }, [ - E('div', { 'class': 'secubox-module-mini-header' }, [ - E('span', { 'class': 'secubox-module-mini-icon' }, module.icon || '๐Ÿ“ฆ'), - E('span', { - 'class': 'secubox-status-dot secubox-status-' + statusClass, - 'title': isRunning ? 'Running' : 'Stopped' - }) - ]), - E('div', { 'class': 'secubox-module-mini-body' }, [ - E('div', { 'class': 'secubox-module-mini-name' }, module.name || module.id), - E('div', { 'class': 'secubox-module-mini-status' }, - isRunning ? 'โ— Running' : 'โ—‹ Stopped') - ]) - ]) - ]); - }); - - return E('div', { 'class': 'secubox-card' }, [ - E('h3', { 'class': 'secubox-card-title' }, '๐ŸŽฏ Active Modules (' + activeModules.length + ')'), - E('div', { 'class': 'secubox-modules-mini-grid' }, - moduleCards.length > 0 ? moduleCards : [ - E('p', { 'class': 'secubox-empty-state' }, 'No modules installed') - ] - ) + E('div', { 'class': 'secubox-gauge-details', 'id': 'gauge-details-' + id }, details || '') ]); }, renderQuickActions: function() { var self = this; var actions = [ - { name: 'restart_rpcd', label: 'RPCD', icon: '๐Ÿ”„', color: '#6366f1' }, - { name: 'restart_uhttpd', label: 'Web Server', icon: '๐ŸŒ', color: '#00ab44' }, - { name: 'restart_network', label: 'Network', icon: '๐Ÿ“ก', color: '#06b6d4' }, - { name: 'restart_firewall', label: 'Firewall', icon: '๐Ÿ›ก๏ธ', color: '#ef4444' }, - { name: 'clear_cache', label: 'Clear Cache', icon: '๐Ÿงน', color: '#f59e0b' }, - { name: 'backup_config', label: 'Backup', icon: '๐Ÿ’พ', color: '#8b5cf6' } + { name: 'restart_rpcd', label: 'Restart RPCD', icon: '๐Ÿ”„' }, + { name: 'restart_uhttpd', label: 'Restart uHTTPd', icon: '๐ŸŒ' }, + { name: 'clear_cache', label: 'Clear Cache', icon: '๐Ÿงน' }, + { name: 'backup_config', label: 'Backup Config', icon: '๐Ÿ’พ' }, + { name: 'restart_network', label: 'Restart Network', icon: '๐Ÿ“ก' }, + { name: 'restart_firewall', label: 'Restart Firewall', icon: '๐Ÿ›ก๏ธ' } ]; var buttons = actions.map(function(action) { return E('button', { - 'class': 'secubox-action-btn', - 'style': 'border-color: ' + action.color, + 'class': 'cbi-button cbi-button-action', 'click': function() { self.executeQuickAction(action.name, action.label); } - }, [ - E('span', { 'class': 'secubox-action-icon' }, action.icon), - E('span', { 'class': 'secubox-action-label' }, action.label) - ]); + }, action.icon + ' ' + action.label); }); - return E('div', { 'class': 'secubox-card' }, [ - E('h3', { 'class': 'secubox-card-title' }, 'โšก Quick Actions'), + return E('div', { 'class': 'secubox-quick-actions' }, [ + E('h3', {}, 'โšก Quick Actions'), E('div', { 'class': 'secubox-actions-grid' }, buttons) ]); }, @@ -333,46 +217,89 @@ return view.extend({ }, renderAlerts: function(alerts) { - if (!alerts || alerts.length === 0) { - return E('div', { 'class': 'secubox-card' }, [ - E('h3', { 'class': 'secubox-card-title' }, 'โœ“ System Status'), - E('div', { 'class': 'secubox-alert secubox-alert-success' }, [ - E('span', {}, 'โœ“ All systems operational') - ]) - ]); - } - var alertItems = alerts.slice(0, 5).map(function(alert) { var severityClass = 'secubox-alert-' + (alert.severity || 'info'); - var severityIcon = alert.severity === 'error' ? 'โœ—' : - alert.severity === 'warning' ? 'โš ๏ธ' : 'โ„น๏ธ'; return E('div', { 'class': 'secubox-alert ' + severityClass }, [ - E('span', { 'class': 'secubox-alert-icon' }, severityIcon), - E('div', { 'class': 'secubox-alert-content' }, [ - E('strong', {}, alert.module || 'System'), - E('span', {}, ': ' + alert.message) + E('strong', {}, (alert.module || 'System') + ': '), + E('span', {}, alert.message || '') + ]); + }); + + return E('div', { 'class': 'secubox-alerts-section' }, [ + E('h3', {}, 'โš ๏ธ Recent Alerts (' + alerts.length + ')'), + E('div', { 'class': 'secubox-alerts-list' }, alertItems), + alerts.length > 5 ? E('a', { + 'href': L.url('admin/secubox/alerts'), + 'class': 'cbi-button cbi-button-link', + 'style': 'margin-top: 12px; display: inline-block;' + }, 'View All Alerts โ†’') : null + ]); + }, + + renderModulesGrid: function(modules) { + // Map module IDs to their dashboard paths + var modulePaths = { + 'crowdsec': 'admin/secubox/security/crowdsec', + 'netdata': 'admin/secubox/monitoring/netdata', + 'netifyd': 'admin/secubox/security/netifyd', + 'wireguard': 'admin/secubox/network/wireguard', + 'network_modes': 'admin/secubox/network/modes', + 'client_guardian': 'admin/secubox/security/guardian', + 'system_hub': 'admin/secubox/system/hub', + 'bandwidth_manager': 'admin/secubox/network/bandwidth', + 'auth_guardian': 'admin/secubox/security/auth', + 'media_flow': 'admin/secubox/network/media', + 'vhost_manager': 'admin/secubox/services/vhost', + 'traffic_shaper': 'admin/secubox/network/shaper', + 'cdn_cache': 'admin/secubox/services/cdn', + 'ksm_manager': 'admin/secubox/security/ksm' + }; + + var moduleCards = modules.map(function(module) { + var statusClass = module.installed ? (module.running ? 'running' : 'stopped') : 'not-installed'; + var statusIcon = module.installed ? (module.running ? 'โœ“' : 'โœ—') : 'โ—‹'; + var statusColor = module.installed ? (module.running ? '#22c55e' : '#ef4444') : '#64748b'; + var dashboardPath = modulePaths[module.id] || ('admin/secubox/' + module.id); + + return E('div', { + 'class': 'secubox-module-card', + 'data-status': statusClass + }, [ + E('div', { 'class': 'secubox-module-header' }, [ + E('div', { + 'class': 'secubox-module-icon', + 'style': 'background-color: ' + (module.color || '#64748b') + }, module.icon || '๐Ÿ“ฆ'), + E('div', { + 'class': 'secubox-module-status', + 'style': 'color: ' + statusColor + }, statusIcon) + ]), + E('div', { 'class': 'secubox-module-body' }, [ + E('div', { 'class': 'secubox-module-name' }, module.name || module.id), + E('div', { 'class': 'secubox-module-description' }, module.description || ''), + E('div', { 'class': 'secubox-module-category' }, module.category || 'other') + ]), + E('div', { 'class': 'secubox-module-footer' }, [ + module.installed ? E('a', { + 'href': L.url(dashboardPath), + 'class': 'cbi-button cbi-button-link' + }, 'Open Dashboard') : E('span', { 'class': 'secubox-not-installed' }, 'Not Installed') ]) ]); }); - return E('div', { 'class': 'secubox-card' }, [ - E('h3', { 'class': 'secubox-card-title' }, - 'โš ๏ธ Alerts (' + alerts.length + ')'), - E('div', { 'class': 'secubox-alerts-list' }, alertItems), - alerts.length > 5 ? E('a', { - 'href': '#', - 'class': 'secubox-view-all', - 'click': function(ev) { - ev.preventDefault(); - window.location.hash = '#admin/secubox/alerts'; - } - }, 'View all alerts โ†’') : null + return E('div', { 'class': 'secubox-modules-section' }, [ + E('h3', {}, '๐ŸŽฏ Active Modules (' + modules.filter(function(m) { return m.installed; }).length + ')'), + E('div', { 'class': 'secubox-modules-grid' }, moduleCards) ]); }, updateDynamicElements: function() { // Update stats var counts = this.dashboardData.counts || {}; + var alerts = this.alertsData.alerts || []; + var totalEl = document.getElementById('stat-total'); var installedEl = document.getElementById('stat-installed'); var runningEl = document.getElementById('stat-running'); @@ -381,44 +308,39 @@ return view.extend({ if (totalEl) totalEl.textContent = counts.total || 0; if (installedEl) installedEl.textContent = counts.installed || 0; if (runningEl) runningEl.textContent = counts.running || 0; - if (alertsEl) alertsEl.textContent = (this.alertsData.alerts || []).length; + if (alertsEl) alertsEl.textContent = alerts.length || 0; - // Update health bars + // Update health gauges var health = this.healthData; - this.updateHealthBar('cpu', health.cpu); - this.updateHealthBar('memory', health.memory); - this.updateHealthBar('disk', health.disk); + this.updateGauge('cpu', health.cpu); + this.updateGauge('memory', health.memory); + this.updateGauge('disk', health.disk); }, - updateHealthBar: function(type, data) { + updateGauge: function(id, data) { if (!data) return; var percent = data.percent || 0; var color = percent < 70 ? '#22c55e' : percent < 85 ? '#f59e0b' : '#ef4444'; - var percentEl = document.getElementById('gauge-' + type + '-percent'); - var gaugeEl = document.getElementById('gauge-' + type); + var circleEl = document.getElementById('gauge-circle-' + id); + var textEl = document.getElementById('gauge-text-' + id); + var detailsEl = document.getElementById('gauge-details-' + id); - if (percentEl) { - percentEl.textContent = Math.round(percent) + '%'; - percentEl.style.color = color; + if (circleEl) { + circleEl.setAttribute('stroke', color); + circleEl.setAttribute('stroke-dasharray', (339.292 * percent / 100) + ' 339.292'); } - if (gaugeEl) { - var radius = 45; - var circumference = 2 * Math.PI * radius; - var offset = circumference - (percent / 100) * circumference; - gaugeEl.setAttribute('stroke-dashoffset', offset); - gaugeEl.setAttribute('stroke', color); + if (textEl) { + textEl.setAttribute('fill', color); + textEl.textContent = Math.round(percent) + (id === 'network' ? '' : '%'); } - - // Update details - var detailsEl = document.getElementById('gauge-' + type + '-details'); - if (detailsEl && type === 'cpu') { + if (detailsEl && id === 'cpu') { detailsEl.textContent = 'Load: ' + (data.load_1min || '0.00'); - } else if (detailsEl && type === 'memory') { + } else if (detailsEl && id === 'memory') { detailsEl.textContent = API.formatBytes((data.used_kb || 0) * 1024) + ' / ' + API.formatBytes((data.total_kb || 0) * 1024); - } else if (detailsEl && type === 'disk') { + } else if (detailsEl && id === 'disk') { detailsEl.textContent = API.formatBytes((data.used_kb || 0) * 1024) + ' / ' + API.formatBytes((data.total_kb || 0) * 1024); }