secubox-openwrt/luci-app-system-hub/htdocs/luci-static/resources/view/system-hub/logs.js
CyberMind-FR 5902ac500a release: v0.1.1 - Unified Theme System with Dark/Light Mode Support
Major Features:
• Centralized theme system across SecuBox and System Hub
• Three theme modes: dark (default), light, and system (auto-detect)
• Single theme setting in SecuBox controls both plugins
• Real-time theme switching with OS preference detection

SecuBox Changes:
• Added theme.js manager for centralized theme control
• Implemented CSS variables for dark/light mode (secubox.css)
• Fixed hardcoded colors in dashboard.css, alerts.css, monitoring.css
• Integrated theme.js in all 7 views (dashboard, modules, alerts, monitoring, settings, etc.)
• Added get_theme RPC method to luci.secubox backend
• Updated ACL permissions to include get_theme (read access)
• Version updated to 0.1.1

System Hub Changes:
• Added theme.js manager using SecuBox theme API
• Implemented CSS variables for dark/light mode (dashboard.css)
• Integrated theme.js in all 9 views (overview, health, services, logs, backup, components, remote, settings, diagnostics)
• Version updated to 0.1.1
• README updated with maintainer info

Theme System Architecture:
• Configuration: /etc/config/secubox (option theme: dark|light|system)
• RPCD Backend: luci.secubox/get_theme method
• Frontend: theme.js modules (secubox/theme.js, system-hub/theme.js)
• CSS Variables: --sb-bg, --sb-bg-card, --sb-border, --sb-text, --sb-text-muted, --sb-shadow
• Auto-detection: prefers-color-scheme media query for system mode

Documentation:
• Added LUCI_DEVELOPMENT_REFERENCE.md with comprehensive LuCI development patterns
• Documented ubus/RPC types, baseclass.extend() patterns, ACL structure
• Common errors and solutions from implementation experience

Bug Fixes:
• Fixed SecuBox theme not applying visually (CSS variables now used)
• Fixed missing secubox.css in view imports
• Fixed ACL access denied for get_theme method
• Fixed hardcoded colors preventing theme switching

Testing:
• Verified theme switching works in all SecuBox tabs
• Verified theme switching works in all System Hub tabs
• Verified dark/light/system modes function correctly
• Verified single setting controls both plugins

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

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

112 lines
2.9 KiB
JavaScript

'use strict';
'require view';
'require ui';
'require system-hub/api as API';
'require system-hub/theme as Theme';
// Load CSS
document.head.appendChild(E('link', {
'rel': 'stylesheet',
'type': 'text/css',
'href': L.resource('system-hub/dashboard.css')
}));
// Initialize theme
Theme.init();
return L.view.extend({
load: function() {
return API.getLogs(100, '');
},
render: function(logs) {
var v = E('div', { 'class': 'cbi-map' }, [
E('h2', {}, _('System Logs')),
E('div', { 'class': 'cbi-map-descr' }, _('View and filter system logs'))
]);
var section = E('div', { 'class': 'cbi-section' });
// Filter controls
var controlsDiv = E('div', { 'style': 'margin-bottom: 15px; display: flex; gap: 10px; align-items: center;' });
var filterInput = E('input', {
'type': 'text',
'class': 'cbi-input-text',
'placeholder': _('Filter logs...'),
'style': 'flex: 1;'
});
var linesSelect = E('select', { 'class': 'cbi-input-select' }, [
E('option', { 'value': '50' }, '50 lines'),
E('option', { 'value': '100', 'selected': '' }, '100 lines'),
E('option', { 'value': '200' }, '200 lines'),
E('option', { 'value': '500' }, '500 lines'),
E('option', { 'value': '1000' }, '1000 lines')
]);
var refreshBtn = E('button', {
'class': 'cbi-button cbi-button-action',
'click': L.bind(function() {
this.refreshLogs(filterInput.value, parseInt(linesSelect.value));
}, this)
}, _('Refresh'));
var clearBtn = E('button', {
'class': 'cbi-button cbi-button-neutral',
'click': function() {
filterInput.value = '';
}
}, _('Clear Filter'));
controlsDiv.appendChild(filterInput);
controlsDiv.appendChild(linesSelect);
controlsDiv.appendChild(refreshBtn);
controlsDiv.appendChild(clearBtn);
section.appendChild(controlsDiv);
// Log display
var logContainer = E('div', { 'id': 'log-container' });
section.appendChild(logContainer);
// Initial render
this.renderLogs(logContainer, logs);
v.appendChild(section);
return v;
},
renderLogs: function(container, logs) {
var logsText = logs.length > 0 ? logs.join('\n') : _('No logs available');
L.dom.content(container, [
E('pre', {
'style': 'background: #000; color: #0f0; padding: 15px; overflow: auto; max-height: 600px; font-size: 11px; font-family: monospace; border-radius: 5px;'
}, logsText)
]);
},
refreshLogs: function(filter, lines) {
ui.showModal(_('Loading Logs'), [
E('p', { 'class': 'spinning' }, _('Fetching logs...'))
]);
API.getLogs(lines, filter).then(L.bind(function(logs) {
ui.hideModal();
var container = document.getElementById('log-container');
if (container) {
this.renderLogs(container, logs);
}
}, this)).catch(function(err) {
ui.hideModal();
ui.addNotification(null, E('p', _('Failed to load logs: ') + err.message), 'error');
});
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});