secubox-openwrt/luci-app-system-hub/htdocs/luci-static/resources/view/system-hub/services.js
CyberMind-FR 34fe2dc26a feat: complete System Hub implementation - central control dashboard
Implements comprehensive system control and monitoring dashboard with health
metrics, service management, system logs, and backup/restore functionality.

Features:
- Real-time system monitoring with visual gauges (CPU, RAM, Disk)
- Comprehensive system information (hostname, model, uptime, kernel)
- Health metrics with temperature monitoring and storage breakdown
- Service management with start/stop/restart/enable/disable actions
- System log viewer with filtering and configurable line count
- Configuration backup creation and download (base64 encoded)
- Configuration restore from backup file
- System reboot functionality with confirmation

Components:
- RPCD backend (luci.system-hub): 10 ubus methods
  * status, get_system_info, get_health
  * list_services, service_action
  * get_logs, backup_config, restore_config
  * reboot, get_storage
- 4 JavaScript views: overview, services, logs, backup
- ACL with read/write permissions segregation
- Comprehensive README with API documentation

Technical implementation:
- System info from /proc filesystem and sysinfo
- Health metrics: CPU load, memory breakdown, disk usage, temperature
- Service control via /etc/init.d scripts
- Log retrieval via logread with filtering
- Backup/restore using sysupgrade with base64 encoding
- Visual gauges with SVG circular progress indicators
- Color-coded health status (green/orange/red)

Dashboard Features:
- Circular gauges for CPU, Memory, Disk (120px with 10px stroke)
- System information cards with detailed metrics
- Temperature monitoring with thermal zone detection
- Storage table for all mount points with progress bars
- Service table with inline action buttons
- Terminal-style log display (black bg, green text)
- File upload for backup restore
- Modal confirmations for destructive actions

Architecture follows SecuBox standards:
- RPCD naming convention (luci. prefix)
- Menu paths match view file structure
- All JavaScript in strict mode
- Form-based configuration management
- Comprehensive error handling

Dependencies: coreutils, coreutils-base64

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-24 11:02:07 +01:00

128 lines
3.7 KiB
JavaScript

'use strict';
'require view';
'require ui';
'require system-hub/api as API';
return L.view.extend({
load: function() {
return API.listServices();
},
render: function(services) {
var v = E('div', { 'class': 'cbi-map' }, [
E('h2', {}, _('System Services')),
E('div', { 'class': 'cbi-map-descr' }, _('Manage system services: start, stop, restart, enable, or disable'))
]);
var section = E('div', { 'class': 'cbi-section' }, [
E('h3', {}, _('Service List'))
]);
if (services.length === 0) {
section.appendChild(E('p', { 'style': 'text-align: center; font-style: italic; padding: 20px;' },
_('No services found')));
v.appendChild(section);
return v;
}
var table = E('table', { 'class': 'table' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th' }, _('Service Name')),
E('th', { 'class': 'th' }, _('Status')),
E('th', { 'class': 'th' }, _('Autostart')),
E('th', { 'class': 'th' }, _('Actions'))
])
]);
services.forEach(L.bind(function(service) {
var statusColor = service.running ? 'green' : 'red';
var statusText = service.running ? '● Running' : '○ Stopped';
var enabledText = service.enabled ? '✓ Enabled' : '✗ Disabled';
var actionsDiv = E('div', { 'style': 'display: flex; gap: 5px;' });
// Start button
if (!service.running) {
actionsDiv.appendChild(E('button', {
'class': 'cbi-button cbi-button-positive',
'click': L.bind(function(service_name, ev) {
this.performAction(service_name, 'start');
}, this, service.name)
}, _('Start')));
}
// Stop button
if (service.running) {
actionsDiv.appendChild(E('button', {
'class': 'cbi-button cbi-button-negative',
'click': L.bind(function(service_name, ev) {
this.performAction(service_name, 'stop');
}, this, service.name)
}, _('Stop')));
}
// Restart button
actionsDiv.appendChild(E('button', {
'class': 'cbi-button cbi-button-action',
'click': L.bind(function(service_name, ev) {
this.performAction(service_name, 'restart');
}, this, service.name)
}, _('Restart')));
// Enable/Disable button
if (service.enabled) {
actionsDiv.appendChild(E('button', {
'class': 'cbi-button cbi-button-neutral',
'click': L.bind(function(service_name, ev) {
this.performAction(service_name, 'disable');
}, this, service.name)
}, _('Disable')));
} else {
actionsDiv.appendChild(E('button', {
'class': 'cbi-button cbi-button-apply',
'click': L.bind(function(service_name, ev) {
this.performAction(service_name, 'enable');
}, this, service.name)
}, _('Enable')));
}
table.appendChild(E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td' }, E('strong', {}, service.name)),
E('td', { 'class': 'td' }, [
E('span', { 'style': 'color: ' + statusColor + '; font-weight: bold;' }, statusText)
]),
E('td', { 'class': 'td' }, enabledText),
E('td', { 'class': 'td' }, actionsDiv)
]));
}, this));
section.appendChild(table);
v.appendChild(section);
return v;
},
performAction: function(service, action) {
ui.showModal(_('Performing Action'), [
E('p', { 'class': 'spinning' }, _('Executing %s on service %s...').format(action, service))
]);
API.serviceAction(service, action).then(function(result) {
ui.hideModal();
if (result.success) {
ui.addNotification(null, E('p', '✓ ' + result.message), 'info');
window.location.reload();
} else {
ui.addNotification(null, E('p', '✗ ' + result.message), 'error');
}
}).catch(function(err) {
ui.hideModal();
ui.addNotification(null, E('p', _('Action failed: ') + err.message), 'error');
});
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});