feat: Add SecuBox portal header to all Network Modes views

Add unified SecuBox header navigation to all 12 Network Modes views
for consistent portal integration when accessed from SecuBox Portal:
- overview.js, router.js, accesspoint.js, doublenat.js
- multiwan.js, relay.js, sniffer.js, travel.js
- vpnrelay.js, dmz.js, wizard.js, settings.js

Pattern: Wrap view content with secubox-page-wrapper and prepend
SbHeader.render() to hide LuCI sidebar when in portal context.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-01-09 15:39:13 +01:00
parent 7df952c2a7
commit 3eacc6c4e7
12 changed files with 75 additions and 13 deletions

View File

@ -5,6 +5,7 @@
'require network-modes.api as api'; 'require network-modes.api as api';
'require network-modes.helpers as helpers'; 'require network-modes.helpers as helpers';
'require secubox-theme/theme as Theme'; 'require secubox-theme/theme as Theme';
'require secubox-portal/header as SbHeader';
var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) || var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) ||
(document.documentElement && document.documentElement.getAttribute('lang')) || (document.documentElement && document.documentElement.getAttribute('lang')) ||
@ -148,7 +149,11 @@ return view.extend({
}); });
this.bindAccessPointActions(container); this.bindAccessPointActions(container);
return container;
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
wrapper.appendChild(container);
return wrapper;
}, },
bindAccessPointActions: function(container) { bindAccessPointActions: function(container) {

View File

@ -5,6 +5,7 @@
'require network-modes.api as api'; 'require network-modes.api as api';
'require network-modes.helpers as helpers'; 'require network-modes.helpers as helpers';
'require secubox-theme/theme as Theme'; 'require secubox-theme/theme as Theme';
'require secubox-portal/header as SbHeader';
var lang = (typeof L !== 'undefined' && L.env && L.env.lang) || var lang = (typeof L !== 'undefined' && L.env && L.env.lang) ||
(document.documentElement && document.documentElement.getAttribute('lang')) || (document.documentElement && document.documentElement.getAttribute('lang')) ||
@ -158,7 +159,11 @@ return view.extend({
}); });
this.bindActions(container); this.bindActions(container);
return container;
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
wrapper.appendChild(container);
return wrapper;
}, },
bindActions: function(container) { bindActions: function(container) {

View File

@ -4,6 +4,7 @@
'require network-modes.api as api'; 'require network-modes.api as api';
'require network-modes.helpers as helpers'; 'require network-modes.helpers as helpers';
'require secubox-theme/theme as Theme'; 'require secubox-theme/theme as Theme';
'require secubox-portal/header as SbHeader';
var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) || var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) ||
(document.documentElement && document.documentElement.getAttribute('lang')) || (document.documentElement && document.documentElement.getAttribute('lang')) ||
@ -56,7 +57,11 @@ return view.extend({
}); });
this.bindActions(container); this.bindActions(container);
return container;
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
wrapper.appendChild(container);
return wrapper;
}, },
renderWanSection: function(wan) { renderWanSection: function(wan) {

View File

@ -4,6 +4,7 @@
'require network-modes.api as api'; 'require network-modes.api as api';
'require network-modes.helpers as helpers'; 'require network-modes.helpers as helpers';
'require secubox-theme/theme as Theme'; 'require secubox-theme/theme as Theme';
'require secubox-portal/header as SbHeader';
var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) || var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) ||
(document.documentElement && document.documentElement.getAttribute('lang')) || (document.documentElement && document.documentElement.getAttribute('lang')) ||
@ -63,7 +64,11 @@ return view.extend({
}); });
this.bindActions(container); this.bindActions(container);
return container;
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
wrapper.appendChild(container);
return wrapper;
}, },
renderLinkStatus: function(links, candidates) { renderLinkStatus: function(links, candidates) {

View File

@ -6,6 +6,7 @@
'require network-modes.helpers as helpers'; 'require network-modes.helpers as helpers';
'require secubox/help as Help'; 'require secubox/help as Help';
'require secubox-theme/theme as Theme'; 'require secubox-theme/theme as Theme';
'require secubox-portal/header as SbHeader';
// Initialize global theme respecting LuCI preferences // Initialize global theme respecting LuCI preferences
var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) || var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) ||
@ -61,6 +62,10 @@ return view.extend({
var modesData = (data.modes || {}).modes || []; var modesData = (data.modes || {}).modes || [];
var currentMode = status.current_mode || 'router'; var currentMode = status.current_mode || 'router';
// Main wrapper with SecuBox header
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
// Build a full mode map using backend data + fallbacks // Build a full mode map using backend data + fallbacks
var baseOrder = ['router', 'doublenat', 'multiwan', 'vpnrelay', 'bridge', 'accesspoint', 'relay', 'travel', 'sniffer']; var baseOrder = ['router', 'doublenat', 'multiwan', 'vpnrelay', 'bridge', 'accesspoint', 'relay', 'travel', 'sniffer'];
var modeInfos = {}; var modeInfos = {};
@ -361,8 +366,9 @@ return view.extend({
// Include CSS // Include CSS
var cssLink = E('link', { 'rel': 'stylesheet', 'href': L.resource('network-modes/dashboard.css') }); var cssLink = E('link', { 'rel': 'stylesheet', 'href': L.resource('network-modes/dashboard.css') });
document.head.appendChild(cssLink); document.head.appendChild(cssLink);
return view; wrapper.appendChild(view);
return wrapper;
}, },
renderHeader: function(status, currentModeInfo) { renderHeader: function(status, currentModeInfo) {

View File

@ -5,6 +5,7 @@
'require network-modes.api as api'; 'require network-modes.api as api';
'require network-modes.helpers as helpers'; 'require network-modes.helpers as helpers';
'require secubox-theme/theme as Theme'; 'require secubox-theme/theme as Theme';
'require secubox-portal/header as SbHeader';
var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) || var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) ||
(document.documentElement && document.documentElement.getAttribute('lang')) || (document.documentElement && document.documentElement.getAttribute('lang')) ||
@ -181,7 +182,11 @@ return view.extend({
}); });
this.bindRelayActions(container); this.bindRelayActions(container);
return container;
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
wrapper.appendChild(container);
return wrapper;
}, },
bindRelayActions: function(container) { bindRelayActions: function(container) {

View File

@ -5,6 +5,7 @@
'require network-modes.api as api'; 'require network-modes.api as api';
'require network-modes.helpers as helpers'; 'require network-modes.helpers as helpers';
'require secubox-theme/theme as Theme'; 'require secubox-theme/theme as Theme';
'require secubox-portal/header as SbHeader';
var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) || var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) ||
(document.documentElement && document.documentElement.getAttribute('lang')) || (document.documentElement && document.documentElement.getAttribute('lang')) ||
@ -47,6 +48,10 @@ return view.extend({
var frontendConfig = config.https_frontend || {}; var frontendConfig = config.https_frontend || {};
var vhosts = config.virtual_hosts || []; var vhosts = config.virtual_hosts || [];
// Main wrapper with SecuBox header
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
var heroActions = [ var heroActions = [
E('button', { 'class': 'nm-btn nm-btn-primary', 'type': 'button', 'data-action': 'router-save' }, ['💾 ', _('Save & Apply')]), E('button', { 'class': 'nm-btn nm-btn-primary', 'type': 'button', 'data-action': 'router-save' }, ['💾 ', _('Save & Apply')]),
E('button', { 'class': 'nm-btn', 'type': 'button', 'data-action': 'router-config' }, ['📝 ', _('Preview Config')]), E('button', { 'class': 'nm-btn', 'type': 'button', 'data-action': 'router-config' }, ['📝 ', _('Preview Config')]),
@ -261,7 +266,8 @@ return view.extend({
}); });
this.bindRouterActions(container); this.bindRouterActions(container);
return container; wrapper.appendChild(container);
return wrapper;
}, },
bindRouterActions: function(container) { bindRouterActions: function(container) {

View File

@ -5,6 +5,7 @@
'require uci'; 'require uci';
'require network-modes/api as api'; 'require network-modes/api as api';
'require network-modes.helpers as helpers'; 'require network-modes.helpers as helpers';
'require secubox-portal/header as SbHeader';
return view.extend({ return view.extend({
load: function() { load: function() {
@ -255,13 +256,18 @@ return view.extend({
}; };
return m.render().then(function(formEl) { return m.render().then(function(formEl) {
return E('div', { 'class': 'network-modes-dashboard nm-settings' }, [ var container = E('div', { 'class': 'network-modes-dashboard nm-settings' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }), E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
E('link', { 'rel': 'stylesheet', 'href': L.resource('network-modes/common.css') }), E('link', { 'rel': 'stylesheet', 'href': L.resource('network-modes/common.css') }),
E('link', { 'rel': 'stylesheet', 'href': L.resource('network-modes/dashboard.css') }), E('link', { 'rel': 'stylesheet', 'href': L.resource('network-modes/dashboard.css') }),
helpers.createNavigationTabs('settings'), helpers.createNavigationTabs('settings'),
formEl formEl
]); ]);
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
wrapper.appendChild(container);
return wrapper;
}); });
} }
}); });

View File

@ -5,6 +5,7 @@
'require network-modes.api as api'; 'require network-modes.api as api';
'require network-modes.helpers as helpers'; 'require network-modes.helpers as helpers';
'require secubox-theme/theme as Theme'; 'require secubox-theme/theme as Theme';
'require secubox-portal/header as SbHeader';
var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) || var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) ||
(document.documentElement && document.documentElement.getAttribute('lang')) || (document.documentElement && document.documentElement.getAttribute('lang')) ||
@ -114,7 +115,11 @@ return view.extend({
}); });
this.bindSnifferActions(container); this.bindSnifferActions(container);
return container;
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
wrapper.appendChild(container);
return wrapper;
}, },
bindSnifferActions: function(container) { bindSnifferActions: function(container) {

View File

@ -6,6 +6,7 @@
'require network-modes.helpers as helpers'; 'require network-modes.helpers as helpers';
'require secubox/help as Help'; 'require secubox/help as Help';
'require secubox-theme/theme as Theme'; 'require secubox-theme/theme as Theme';
'require secubox-portal/header as SbHeader';
var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) || var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) ||
(document.documentElement && document.documentElement.getAttribute('lang')) || (document.documentElement && document.documentElement.getAttribute('lang')) ||
@ -136,7 +137,11 @@ return view.extend({
]); ]);
this.bindTravelActions(container); this.bindTravelActions(container);
return container;
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
wrapper.appendChild(container);
return wrapper;
}, },
renderSelectField: function(label, id, options, selected) { renderSelectField: function(label, id, options, selected) {

View File

@ -4,6 +4,7 @@
'require network-modes.api as api'; 'require network-modes.api as api';
'require network-modes.helpers as helpers'; 'require network-modes.helpers as helpers';
'require secubox-theme/theme as Theme'; 'require secubox-theme/theme as Theme';
'require secubox-portal/header as SbHeader';
var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) || var nmLang = (typeof L !== 'undefined' && L.env && L.env.lang) ||
(document.documentElement && document.documentElement.getAttribute('lang')) || (document.documentElement && document.documentElement.getAttribute('lang')) ||
@ -55,7 +56,11 @@ return view.extend({
}); });
this.bindActions(container); this.bindActions(container);
return container;
var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
wrapper.appendChild(container);
return wrapper;
}, },
renderVpnSection: function(vpn, cfg) { renderVpnSection: function(vpn, cfg) {

View File

@ -7,6 +7,7 @@
'require network-modes.helpers as helpers'; 'require network-modes.helpers as helpers';
'require network-modes/api as API'; 'require network-modes/api as API';
'require secubox-theme/theme as Theme'; 'require secubox-theme/theme as Theme';
'require secubox-portal/header as SbHeader';
var callGetAvailableModes = rpc.declare({ var callGetAvailableModes = rpc.declare({
object: 'luci.network-modes', object: 'luci.network-modes',
@ -113,7 +114,10 @@ return view.extend({
this.startRollbackPoll(); this.startRollbackPoll();
} }
return container; var wrapper = E('div', { 'class': 'secubox-page-wrapper' });
wrapper.appendChild(SbHeader.render());
wrapper.appendChild(container);
return wrapper;
}, },
renderStatusBadges: function(status, currentMode) { renderStatusBadges: function(status, currentMode) {