secubox-openwrt/luci-app-netdata-dashboard/htdocs/luci-static/resources/view/netdata-dashboard/dashboard.js
CyberMind-FR cf39eb6e1d fix: resolve validation issues across all modules
- Fixed minified RPC declaration in secubox/modules.js that caused false positive in validation
- Added 30 missing menu entries across 10 modules:
  * bandwidth-manager: clients, schedules
  * client-guardian: zones, portal, logs, alerts, parental
  * crowdsec-dashboard: metrics
  * netdata-dashboard: system, processes, realtime, network
  * netifyd-dashboard: talkers, risks, devices
  * network-modes: router, accesspoint, relay, sniffer
  * secubox: settings
  * system-hub: components, diagnostics, health, remote, settings
  * vhost-manager: internal, ssl, redirects
  * wireguard-dashboard: traffic, config
- All modules now pass comprehensive validation (0 errors, 0 warnings)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-25 09:01:06 +01:00

275 lines
9.5 KiB
JavaScript

'use strict';
'require view';
'require dom';
'require ui';
'require poll';
'require netdata-dashboard/api as API';
return view.extend({
load: function() {
return Promise.all([
API.getNetdataStatus(),
API.getNetdataAlarms(),
API.getStats()
]);
},
render: function(data) {
var netdataStatus = data[0] || {};
var alarms = data[1] || {};
var stats = data[2] || {};
var isRunning = netdataStatus.running || false;
var netdataUrl = netdataStatus.url || 'http://127.0.0.1:19999';
// Count active alarms
var alarmCount = 0;
if (alarms.alarms && typeof alarms.alarms === 'object') {
Object.keys(alarms.alarms).forEach(function(key) {
var alarm = alarms.alarms[key];
if (alarm.status && alarm.status !== 'CLEAR') {
alarmCount++;
}
});
}
var view = E('div', { 'class': 'cbi-map' }, [
E('h2', {}, _('Netdata Dashboard')),
E('div', { 'class': 'cbi-map-descr' },
_('Real-time system monitoring and performance metrics powered by Netdata.')),
// Control Panel
E('div', { 'class': 'cbi-section', 'style': 'margin-bottom: 1em;' }, [
E('div', { 'style': 'display: grid; grid-template-columns: 2fr 1fr; gap: 1em;' }, [
// Status Card
E('div', {
'style': 'background: ' + (isRunning ? '#d4edda' : '#f8d7da') + '; border-left: 4px solid ' + (isRunning ? '#28a745' : '#dc3545') + '; padding: 1em; border-radius: 4px;'
}, [
E('div', { 'style': 'display: flex; justify-content: space-between; align-items: center;' }, [
E('div', {}, [
E('div', { 'style': 'font-size: 0.9em; color: #666; margin-bottom: 0.25em;' }, _('Service Status')),
E('div', { 'style': 'font-size: 1.5em; font-weight: bold; color: ' + (isRunning ? '#155724' : '#721c24') + ';' },
isRunning ? _('RUNNING') : _('STOPPED'))
]),
E('div', { 'style': 'text-align: right;' }, [
E('div', { 'style': 'font-size: 0.9em; color: #666; margin-bottom: 0.25em;' }, _('Version')),
E('div', { 'style': 'font-size: 1.1em; font-weight: bold;' }, netdataStatus.version || 'Unknown')
]),
E('div', { 'style': 'text-align: right;' }, [
E('div', { 'style': 'font-size: 0.9em; color: #666; margin-bottom: 0.25em;' }, _('Port')),
E('div', { 'style': 'font-size: 1.1em; font-weight: bold;' }, (netdataStatus.port || 19999).toString())
])
])
]),
// Control Buttons
E('div', { 'style': 'display: flex; flex-direction: column; gap: 0.5em;' }, [
E('button', {
'class': 'cbi-button cbi-button-action',
'click': L.bind(this.handleStart, this),
'disabled': isRunning,
'style': 'flex: 1;'
}, _('Start Netdata')),
E('button', {
'class': 'cbi-button cbi-button-reset',
'click': L.bind(this.handleRestart, this),
'disabled': !isRunning,
'style': 'flex: 1;'
}, _('Restart Netdata')),
E('button', {
'class': 'cbi-button cbi-button-negative',
'click': L.bind(this.handleStop, this),
'disabled': !isRunning,
'style': 'flex: 1;'
}, _('Stop Netdata'))
])
])
]),
// Alarms Card
alarmCount > 0 ? E('div', {
'class': 'cbi-section',
'style': 'background: #fff3cd; border-left: 4px solid #ffc107; padding: 1em; margin-bottom: 1em;'
}, [
E('div', { 'style': 'display: flex; align-items: center; gap: 1em;' }, [
E('div', { 'style': 'font-size: 2em;' }, '⚠️'),
E('div', { 'style': 'flex: 1;' }, [
E('strong', {}, _('Active Alarms: %d').format(alarmCount)),
E('p', { 'style': 'margin: 0.25em 0 0 0; color: #666;' },
_('Netdata has detected %d active alarm(s). Check the dashboard for details.').format(alarmCount))
]),
E('a', {
'href': netdataUrl + '#menu_alarms',
'target': '_blank',
'class': 'cbi-button cbi-button-action'
}, _('View Alarms'))
])
]) : null,
// Quick Stats Preview
E('div', { 'class': 'cbi-section', 'style': 'margin-bottom: 1em;' }, [
E('h3', { 'style': 'margin-top: 0;' }, _('Quick Stats')),
E('div', { 'style': 'display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1em;' }, [
this.renderStatCard(_('CPU'), stats.cpu_percent + '%', '#0088cc'),
this.renderStatCard(_('Memory'), stats.memory_percent + '%', '#17a2b8'),
this.renderStatCard(_('Disk'), stats.disk_percent + '%', '#6610f2'),
this.renderStatCard(_('Load'), stats.load || '0.00', '#e83e8c'),
this.renderStatCard(_('Temp'), stats.temperature + '°C', '#fd7e14'),
this.renderStatCard(_('Uptime'), API.formatUptime(stats.uptime || 0), '#28a745')
])
]),
// Netdata Dashboard Iframe
isRunning ? E('div', { 'class': 'cbi-section' }, [
E('h3', { 'style': 'margin-top: 0;' }, _('Netdata Real-Time Dashboard')),
E('div', {
'style': 'position: relative; width: 100%; height: 0; padding-bottom: 75%; background: #f5f5f5; border-radius: 4px; overflow: hidden;'
}, [
E('iframe', {
'src': netdataUrl,
'style': 'position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none;',
'frameborder': '0',
'allow': 'fullscreen'
})
]),
E('div', { 'style': 'margin-top: 1em; padding: 0.75em; background: #e8f4f8; border-radius: 4px;' }, [
E('strong', {}, _('Tip:')),
' ',
_('Use the Netdata interface above for detailed real-time monitoring. Click '),
E('a', { 'href': netdataUrl, 'target': '_blank' }, _('here')),
_(' to open in a new window.')
])
]) : E('div', { 'class': 'cbi-section' }, [
E('div', {
'style': 'text-align: center; padding: 3em; background: #f8d7da; border-radius: 4px; border-left: 4px solid #dc3545;'
}, [
E('div', { 'style': 'font-size: 3em; margin-bottom: 0.5em;' }, '⚠️'),
E('h3', {}, _('Netdata is not running')),
E('p', { 'style': 'color: #666; margin-bottom: 1.5em;' },
_('Start the Netdata service to access real-time monitoring dashboards.')),
E('button', {
'class': 'cbi-button cbi-button-action',
'style': 'font-size: 1.1em; padding: 0.75em 2em;',
'click': L.bind(this.handleStart, this)
}, _('Start Netdata Now'))
])
])
]);
// Setup auto-refresh
poll.add(L.bind(function() {
return Promise.all([
API.getNetdataStatus(),
API.getStats()
]).then(L.bind(function(refreshData) {
// Could update stats display here
}, this));
}, this), 5);
return view;
},
renderStatCard: function(label, value, color) {
return E('div', {
'style': 'background: white; border-left: 4px solid ' + color + '; padding: 1em; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);'
}, [
E('div', { 'style': 'font-size: 0.85em; color: #666; margin-bottom: 0.25em;' }, label),
E('div', { 'style': 'font-size: 1.5em; font-weight: bold; color: ' + color + ';' }, value)
]);
},
handleStart: function(ev) {
var btn = ev.target;
btn.disabled = true;
btn.textContent = _('Starting...');
API.startNetdata().then(function(result) {
if (result.success) {
ui.addNotification(null, E('p', result.message || _('Netdata started successfully')), 'info');
setTimeout(function() {
window.location.reload();
}, 2000);
} else {
ui.addNotification(null, E('p', result.error || _('Failed to start Netdata')), 'error');
btn.disabled = false;
btn.textContent = _('Start Netdata');
}
}).catch(function(err) {
ui.addNotification(null, E('p', _('Error: %s').format(err.message || err)), 'error');
btn.disabled = false;
btn.textContent = _('Start Netdata');
});
},
handleStop: function(ev) {
ui.showModal(_('Stop Netdata'), [
E('p', {}, _('Are you sure you want to stop Netdata monitoring?')),
E('p', { 'style': 'color: #856404; background: #fff3cd; padding: 0.75em; border-radius: 4px;' },
_('This will stop all real-time monitoring and data collection.')),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
'click': ui.hideModal
}, _('Cancel')),
' ',
E('button', {
'class': 'btn cbi-button-negative',
'click': L.bind(function() {
ui.hideModal();
this.doStop(ev.target);
}, this)
}, _('Stop Netdata'))
])
]);
},
doStop: function(btn) {
btn.disabled = true;
btn.textContent = _('Stopping...');
API.stopNetdata().then(function(result) {
if (result.success) {
ui.addNotification(null, E('p', result.message || _('Netdata stopped')), 'info');
setTimeout(function() {
window.location.reload();
}, 1500);
} else {
ui.addNotification(null, E('p', result.error || _('Failed to stop Netdata')), 'error');
btn.disabled = false;
btn.textContent = _('Stop Netdata');
}
}).catch(function(err) {
ui.addNotification(null, E('p', _('Error: %s').format(err.message || err)), 'error');
btn.disabled = false;
btn.textContent = _('Stop Netdata');
});
},
handleRestart: function(ev) {
var btn = ev.target;
btn.disabled = true;
btn.textContent = _('Restarting...');
API.restartNetdata().then(function(result) {
if (result.success) {
ui.addNotification(null, E('p', result.message || _('Netdata restarted successfully')), 'info');
setTimeout(function() {
window.location.reload();
}, 3000);
} else {
ui.addNotification(null, E('p', result.error || _('Failed to restart Netdata')), 'error');
btn.disabled = false;
btn.textContent = _('Restart Netdata');
}
}).catch(function(err) {
ui.addNotification(null, E('p', _('Error: %s').format(err.message || err)), 'error');
btn.disabled = false;
btn.textContent = _('Restart Netdata');
});
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});