feat: Add SecuBox portal header to Client Guardian, Media Flow, and Netdata views

Adds the unified SecuBox portal header navigation to:
- Client Guardian: overview, clients, zones, logs, alerts, parental, settings
- Media Flow: dashboard
- Netdata Dashboard: dashboard, settings

This hides the LuCI sidebar and provides consistent SecuBox navigation
across all dashboards when accessed from the SecuBox Portal.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-01-09 15:33:14 +01:00
parent 56ec6f4483
commit 7df952c2a7
10 changed files with 76 additions and 10 deletions

View File

@ -7,6 +7,7 @@
'require ui';
'require client-guardian/api as API';
'require client-guardian/nav as CgNav';
'require secubox-portal/header as SbHeader';
return view.extend({
load: function() {
@ -20,6 +21,10 @@ return view.extend({
var alerts = data[0];
var logs = data[1].logs || [];
// Main wrapper with SecuBox header
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
var view = E('div', { 'class': 'client-guardian-dashboard' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
E('link', { 'rel': 'stylesheet', 'href': L.resource('client-guardian/dashboard.css') }),
@ -164,7 +169,8 @@ return view.extend({
])
]);
return view;
wrapper.appendChild(view);
return wrapper;
},
renderToggle: function(icon, label, desc, enabled) {

View File

@ -5,6 +5,7 @@
'require ui';
'require rpc';
'require client-guardian/nav as CgNav';
'require secubox-portal/header as SbHeader';
var callGetClients = rpc.declare({
object: 'luci.client-guardian',
@ -76,6 +77,10 @@ return view.extend({
var zones = Array.isArray(data[1]) ? data[1] : (data[1].zones || []);
var self = this;
// Main wrapper with SecuBox header
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
var view = E('div', { 'class': 'client-guardian-dashboard' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
E('link', { 'rel': 'stylesheet', 'href': L.resource('client-guardian/dashboard.css') }),
@ -121,7 +126,8 @@ return view.extend({
])
]);
return view;
wrapper.appendChild(view);
return wrapper;
},
renderFilterTab: function(filter, label, count, active) {

View File

@ -5,6 +5,7 @@
'require ui';
'require client-guardian/api as API';
'require client-guardian/nav as CgNav';
'require secubox-portal/header as SbHeader';
return view.extend({
refreshInterval: 5000,
@ -17,6 +18,10 @@ return view.extend({
var logs = data.logs || [];
var self = this;
// Main wrapper with SecuBox header
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
var view = E('div', { 'class': 'client-guardian-dashboard' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
E('link', { 'rel': 'stylesheet', 'href': L.resource('client-guardian/dashboard.css') }),
@ -119,7 +124,8 @@ return view.extend({
// Setup auto-refresh
poll.add(L.bind(this.pollLogs, this), this.refreshInterval);
return view;
wrapper.appendChild(view);
return wrapper;
},
renderLogs: function(logs) {

View File

@ -6,6 +6,7 @@
'require ui';
'require rpc';
'require client-guardian/nav as CgNav';
'require secubox-portal/header as SbHeader';
var callGetStatus = rpc.declare({
object: 'luci.client-guardian',
@ -77,6 +78,10 @@ return view.extend({
var quarantineClients = clients.filter(function(c) { return c.status === 'unknown' || c.zone === 'quarantine'; });
var bannedClients = clients.filter(function(c) { return c.status === 'banned'; });
// Main wrapper with SecuBox header
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
var view = E('div', { 'class': 'client-guardian-dashboard' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
E('link', { 'rel': 'stylesheet', 'href': L.resource('client-guardian/dashboard.css') }),
@ -150,7 +155,8 @@ return view.extend({
}, this), refreshInterval);
}
return view;
wrapper.appendChild(view);
return wrapper;
},
renderStatCard: function(icon, value, label) {

View File

@ -4,6 +4,7 @@
'require ui';
'require rpc';
'require client-guardian/nav as CgNav';
'require secubox-portal/header as SbHeader';
var callGetParental = rpc.declare({
object: 'luci.client-guardian',
@ -20,7 +21,11 @@ return view.extend({
var filters = data.filters || [];
var urlLists = data.url_lists || [];
return E('div', { 'class': 'client-guardian-dashboard' }, [
// Main wrapper with SecuBox header
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
var view = E('div', { 'class': 'client-guardian-dashboard' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
E('link', { 'rel': 'stylesheet', 'href': L.resource('client-guardian/dashboard.css') }),
CgNav.renderTabs('parental'),
@ -246,6 +251,9 @@ return view.extend({
])
])
]);
wrapper.appendChild(view);
return wrapper;
},
renderScheduleDay: function(name, active) {

View File

@ -5,6 +5,7 @@
'require uci';
'require client-guardian/api as API';
'require client-guardian/nav as CgNav';
'require secubox-portal/header as SbHeader';
return view.extend({
load: function() {
@ -222,12 +223,19 @@ return view.extend({
rendered.insertBefore(infoBox, rendered.firstChild);
return E('div', { 'class': 'client-guardian-dashboard' }, [
// Main wrapper with SecuBox header
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
var view = E('div', { 'class': 'client-guardian-dashboard' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
E('link', { 'rel': 'stylesheet', 'href': L.resource('client-guardian/dashboard.css') }),
CgNav.renderTabs('settings'),
rendered
]);
wrapper.appendChild(view);
return wrapper;
});
},

View File

@ -4,6 +4,7 @@
'require ui';
'require rpc';
'require client-guardian/nav as CgNav';
'require secubox-portal/header as SbHeader';
var callGetZones = rpc.declare({
object: 'luci.client-guardian',
@ -31,7 +32,11 @@ return view.extend({
var zones = Array.isArray(data) ? data : (data.zones || []);
var self = this;
return E('div', { 'class': 'client-guardian-dashboard' }, [
// Main wrapper with SecuBox header
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
var view = E('div', { 'class': 'client-guardian-dashboard' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
E('link', { 'rel': 'stylesheet', 'href': L.resource('client-guardian/dashboard.css') }),
CgNav.renderTabs('zones'),
@ -59,6 +64,9 @@ return view.extend({
zones.map(L.bind(this.renderZoneCard, this))
)
]);
wrapper.appendChild(view);
return wrapper;
},
renderZoneCard: function(zone) {

View File

@ -3,6 +3,7 @@
'require poll';
'require ui';
'require media-flow/api as API';
'require secubox-portal/header as SbHeader';
return view.extend({
title: _('Media Flow Dashboard'),
@ -36,6 +37,10 @@ return view.extend({
var streams = streamsData.streams || [];
var flowCount = streamsData.flow_count || status.active_flows || 0;
// Main wrapper with SecuBox header
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
// Inject CSS
var css = `
.mf-dashboard { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: #e4e4e7; }
@ -241,7 +246,8 @@ return view.extend({
}, this));
}, this), this.pollInterval);
return view;
wrapper.appendChild(view);
return wrapper;
},
handleSaveApply: null,

View File

@ -5,6 +5,7 @@
'require poll';
'require netdata-dashboard/api as API';
'require secubox-theme/theme as Theme';
'require secubox-portal/header as SbHeader';
var lang = (typeof L !== 'undefined' && L.env && L.env.lang) ||
(document.documentElement && document.documentElement.getAttribute('lang')) ||
@ -33,6 +34,10 @@ return view.extend({
var netdataUrl = 'http://' + window.location.hostname + ':' + netdataPort;
var alarmCount = this.countAlarms(alarms);
// Main wrapper with SecuBox header
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
var view = E('div', { 'class': 'netdata-dashboard secubox-netdata' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
E('link', { 'rel': 'stylesheet', 'href': L.resource('netdata-dashboard/dashboard.css') }),
@ -55,7 +60,8 @@ return view.extend({
}, this));
}, this), 5);
return view;
wrapper.appendChild(view);
return wrapper;
},
countAlarms: function(alarms) {

View File

@ -3,6 +3,7 @@
'require secubox-theme/theme as Theme';
'require ui';
'require netdata-dashboard/api as API';
'require secubox-portal/header as SbHeader';
return view.extend({
load: function() {
@ -27,6 +28,10 @@ return view.extend({
var thStyle = 'padding: 0.75rem 1rem; text-align: left; font-weight: 600; width: 200px; background: #161b22; border-bottom: 1px solid #30363d;';
var tdStyle = 'padding: 0.75rem 1rem; border-bottom: 1px solid #30363d;';
// Main wrapper with SecuBox header
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
var view = E('div', { 'class': 'cbi-map' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
E('h2', {}, _('Netdata Settings')),
@ -227,7 +232,8 @@ return view.extend({
])
]);
return view;
wrapper.appendChild(view);
return wrapper;
},
handleSaveApply: null,