diff --git a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/client-guardian/nav.js b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/client-guardian/nav.js new file mode 100644 index 00000000..cc099c5e --- /dev/null +++ b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/client-guardian/nav.js @@ -0,0 +1,127 @@ +'use strict'; +'require baseclass'; + +/** + * Client Guardian Navigation + * SecuBox themed navigation tabs + */ + +var tabs = [ + { id: 'overview', icon: 'πŸ“Š', label: _('Overview'), path: ['admin', 'secubox', 'security', 'guardian', 'overview'] }, + { id: 'wizard', icon: 'πŸš€', label: _('Setup Wizard'), path: ['admin', 'secubox', 'security', 'guardian', 'wizard'] }, + { id: 'clients', icon: 'πŸ‘₯', label: _('Clients'), path: ['admin', 'secubox', 'security', 'guardian', 'clients'] }, + { id: 'zones', icon: '🏠', label: _('Zones'), path: ['admin', 'secubox', 'security', 'guardian', 'zones'] }, + { id: 'captive', icon: 'πŸšͺ', label: _('Captive Portal'), path: ['admin', 'secubox', 'security', 'guardian', 'captive'] }, + { id: 'portal', icon: '🎨', label: _('Portal Config'), path: ['admin', 'secubox', 'security', 'guardian', 'portal'] }, + { id: 'logs', icon: 'πŸ“œ', label: _('Logs'), path: ['admin', 'secubox', 'security', 'guardian', 'logs'] }, + { id: 'alerts', icon: 'πŸ””', label: _('Alerts'), path: ['admin', 'secubox', 'security', 'guardian', 'alerts'] }, + { id: 'parental', icon: 'πŸ‘¨β€πŸ‘©β€πŸ‘§', label: _('Parental'), path: ['admin', 'secubox', 'security', 'guardian', 'parental'] }, + { id: 'settings', icon: 'βš™οΈ', label: _('Settings'), path: ['admin', 'secubox', 'security', 'guardian', 'settings'] } +]; + +return baseclass.extend({ + getTabs: function() { + return tabs.slice(); + }, + + ensureLuCITabsHidden: function() { + if (typeof document === 'undefined') + return; + if (document.getElementById('guardian-tabstyle')) + return; + var style = document.createElement('style'); + style.id = 'guardian-tabstyle'; + style.textContent = ` +/* Hide default LuCI tabs for Client Guardian */ +body[data-page^="admin-secubox-security-guardian"] .tabs, +body[data-page^="admin-secubox-security-guardian"] #tabmenu, +body[data-page^="admin-secubox-security-guardian"] .cbi-tabmenu, +body[data-page^="admin-secubox-security-guardian"] .nav-tabs, +body[data-page^="admin-secubox-security-guardian"] ul.cbi-tabmenu { + display: none !important; +} + +/* Guardian Nav Tabs */ +.cg-nav-tabs { + display: flex; + gap: 4px; + margin-bottom: 24px; + padding: 6px; + background: var(--cg-bg-secondary, #151b23); + border-radius: 12px; + border: 1px solid var(--cg-border, #2a3444); + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +.cg-nav-tab { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 16px; + border-radius: 8px; + background: transparent; + border: none; + color: var(--cg-text-secondary, #8b949e); + font-weight: 500; + font-size: 13px; + cursor: pointer; + text-decoration: none; + transition: all 0.2s ease; + white-space: nowrap; +} + +.cg-nav-tab:hover { + color: var(--cg-text-primary, #e6edf3); + background: var(--cg-bg-tertiary, #1e2632); +} + +.cg-nav-tab.active { + color: var(--cg-accent, #6366f1); + background: var(--cg-bg-tertiary, #1e2632); + box-shadow: inset 0 -2px 0 var(--cg-accent, #6366f1); +} + +.cg-tab-icon { + font-size: 16px; + line-height: 1; +} + +.cg-tab-label { + font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; +} + +@media (max-width: 768px) { + .cg-nav-tabs { + padding: 4px; + } + .cg-nav-tab { + padding: 8px 12px; + font-size: 12px; + } + .cg-tab-label { + display: none; + } + .cg-tab-icon { + font-size: 18px; + } +} + `; + document.head && document.head.appendChild(style); + }, + + renderTabs: function(active) { + this.ensureLuCITabsHidden(); + return E('div', { 'class': 'cg-nav-tabs' }, + this.getTabs().map(function(tab) { + return E('a', { + 'class': 'cg-nav-tab' + (tab.id === active ? ' active' : ''), + 'href': L.url.apply(L, tab.path) + }, [ + E('span', { 'class': 'cg-tab-icon' }, tab.icon), + E('span', { 'class': 'cg-tab-label' }, tab.label) + ]); + }) + ); + } +}); diff --git a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/alerts.js b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/alerts.js index 0bacab72..ed5dfb95 100644 --- a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/alerts.js +++ b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/alerts.js @@ -1,12 +1,12 @@ 'use strict'; 'require view'; - 'require dom'; 'require poll'; 'require uci'; 'require rpc'; 'require ui'; 'require client-guardian/api as API'; +'require client-guardian/nav as CgNav'; return view.extend({ load: function() { @@ -23,7 +23,8 @@ return view.extend({ 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('alerts'), + // Email Configuration E('div', { 'class': 'cg-card' }, [ E('div', { 'class': 'cg-card-header' }, [ diff --git a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/clients.js b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/clients.js index 6ea3dab5..e96ce84e 100644 --- a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/clients.js +++ b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/clients.js @@ -4,6 +4,7 @@ 'require poll'; 'require ui'; 'require rpc'; +'require client-guardian/nav as CgNav'; var callGetClients = rpc.declare({ object: 'luci.client-guardian', @@ -78,6 +79,7 @@ return view.extend({ 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('clients'), E('div', { 'class': 'cg-header' }, [ E('div', { 'class': 'cg-logo' }, [ diff --git a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/debug.js b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/debug.js index 10d0f3b7..c3ac9094 100644 --- a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/debug.js +++ b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/debug.js @@ -1,11 +1,11 @@ 'use strict'; 'require view'; - 'require dom'; 'require ui'; 'require uci'; 'require rpc'; 'require client-guardian/debug as Debug'; +'require client-guardian/nav as CgNav'; var callGetLogs = rpc.declare({ object: 'luci.client-guardian', @@ -33,6 +33,7 @@ return view.extend({ return 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('debug'), E('div', { 'class': 'cg-header' }, [ E('div', { 'class': 'cg-logo' }, [ diff --git a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/logs.js b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/logs.js index 9b3557b0..27e03bd8 100644 --- a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/logs.js +++ b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/logs.js @@ -1,10 +1,10 @@ 'use strict'; 'require view'; - 'require dom'; 'require poll'; 'require ui'; 'require client-guardian/api as API'; +'require client-guardian/nav as CgNav'; return view.extend({ refreshInterval: 5000, @@ -20,7 +20,8 @@ return view.extend({ 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('logs'), + // Filters E('div', { 'class': 'cg-card' }, [ E('div', { 'class': 'cg-card-header' }, [ diff --git a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/overview.js b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/overview.js index 164b39bc..a4043ba6 100644 --- a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/overview.js +++ b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/overview.js @@ -5,6 +5,7 @@ 'require uci'; 'require ui'; 'require rpc'; +'require client-guardian/nav as CgNav'; var callGetStatus = rpc.declare({ object: 'luci.client-guardian', @@ -79,6 +80,7 @@ return view.extend({ 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('overview'), // Header E('div', { 'class': 'cg-header' }, [ diff --git a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/parental.js b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/parental.js index 2ed02ce9..4db950c3 100644 --- a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/parental.js +++ b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/parental.js @@ -3,6 +3,7 @@ 'require dom'; 'require ui'; 'require rpc'; +'require client-guardian/nav as CgNav'; var callGetParental = rpc.declare({ object: 'luci.client-guardian', @@ -22,6 +23,7 @@ return view.extend({ return 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'), E('div', { 'class': 'cg-header' }, [ E('div', { 'class': 'cg-logo' }, [ diff --git a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/settings.js b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/settings.js index 6e1ea20f..f60becc2 100644 --- a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/settings.js +++ b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/settings.js @@ -1,10 +1,10 @@ 'use strict'; 'require view'; - 'require form'; 'require ui'; 'require uci'; 'require client-guardian/api as API'; +'require client-guardian/nav as CgNav'; return view.extend({ load: function() { @@ -222,8 +222,10 @@ return view.extend({ rendered.insertBefore(infoBox, rendered.firstChild); - return E('div', {}, [ + return 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 ]); }); diff --git a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/wizard.js b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/wizard.js index d5869221..2d77f6c6 100644 --- a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/wizard.js +++ b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/wizard.js @@ -3,6 +3,7 @@ 'require dom'; 'require ui'; 'require rpc'; +'require client-guardian/nav as CgNav'; var callListProfiles = rpc.declare({ object: 'luci.client-guardian', @@ -30,6 +31,7 @@ return view.extend({ return 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('wizard'), E('div', { 'class': 'cg-wizard' }, [ E('div', { 'class': 'cg-wizard-header' }, [ @@ -304,7 +306,7 @@ return view.extend({ ]), 'success'); setTimeout(function() { - window.location.href = L.url('admin/secubox/security/client-guardian/zones'); + window.location.href = L.url('admin/secubox/security/guardian/zones'); }, 3000); } else { ui.addNotification(null, E('p', {}, 'Erreur: ' + (result.error || 'Γ‰chec de l\'application du profil')), 'error'); diff --git a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/zones.js b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/zones.js index c48387db..b09dc671 100644 --- a/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/zones.js +++ b/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/zones.js @@ -3,6 +3,7 @@ 'require dom'; 'require ui'; 'require rpc'; +'require client-guardian/nav as CgNav'; var callGetZones = rpc.declare({ object: 'luci.client-guardian', @@ -33,6 +34,7 @@ return view.extend({ return 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'), E('div', { 'class': 'cg-header' }, [ E('div', { 'class': 'cg-logo' }, [ diff --git a/package/secubox/luci-app-client-guardian/root/usr/share/luci/menu.d/luci-app-client-guardian.json b/package/secubox/luci-app-client-guardian/root/usr/share/luci/menu.d/luci-app-client-guardian.json index 3d0ff564..11189ba5 100644 --- a/package/secubox/luci-app-client-guardian/root/usr/share/luci/menu.d/luci-app-client-guardian.json +++ b/package/secubox/luci-app-client-guardian/root/usr/share/luci/menu.d/luci-app-client-guardian.json @@ -1,5 +1,5 @@ { - "admin/secubox/security/client-guardian": { + "admin/secubox/security/guardian": { "title": "Client Guardian", "order": 30, "action": { @@ -9,7 +9,7 @@ "acl": ["luci-app-client-guardian"] } }, - "admin/secubox/security/client-guardian/overview": { + "admin/secubox/security/guardian/overview": { "title": "Overview", "order": 10, "action": { @@ -17,7 +17,7 @@ "path": "client-guardian/overview" } }, - "admin/secubox/security/client-guardian/wizard": { + "admin/secubox/security/guardian/wizard": { "title": "Setup Wizard", "order": 15, "action": { @@ -25,7 +25,7 @@ "path": "client-guardian/wizard" } }, - "admin/secubox/security/client-guardian/clients": { + "admin/secubox/security/guardian/clients": { "title": "Clients", "order": 20, "action": { @@ -33,7 +33,7 @@ "path": "client-guardian/clients" } }, - "admin/secubox/security/client-guardian/zones": { + "admin/secubox/security/guardian/zones": { "title": "Network Zones", "order": 25, "action": { @@ -41,7 +41,7 @@ "path": "client-guardian/zones" } }, - "admin/secubox/security/client-guardian/captive": { + "admin/secubox/security/guardian/captive": { "title": "Captive Portal", "order": 30, "action": { @@ -49,7 +49,7 @@ "path": "client-guardian/captive" } }, - "admin/secubox/security/client-guardian/portal": { + "admin/secubox/security/guardian/portal": { "title": "Portal Config", "order": 35, "action": { @@ -57,7 +57,7 @@ "path": "client-guardian/portal" } }, - "admin/secubox/security/client-guardian/logs": { + "admin/secubox/security/guardian/logs": { "title": "Event Logs", "order": 40, "action": { @@ -65,7 +65,7 @@ "path": "client-guardian/logs" } }, - "admin/secubox/security/client-guardian/alerts": { + "admin/secubox/security/guardian/alerts": { "title": "Alerts & Notifications", "order": 50, "action": { @@ -73,7 +73,7 @@ "path": "client-guardian/alerts" } }, - "admin/secubox/security/client-guardian/parental": { + "admin/secubox/security/guardian/parental": { "title": "Parental Controls", "order": 60, "action": { @@ -81,7 +81,7 @@ "path": "client-guardian/parental" } }, - "admin/secubox/security/client-guardian/settings": { + "admin/secubox/security/guardian/settings": { "title": "Settings", "order": 90, "action": { @@ -89,7 +89,7 @@ "path": "client-guardian/settings" } }, - "admin/secubox/security/client-guardian/debug": { + "admin/secubox/security/guardian/debug": { "title": "Debug Console", "order": 95, "action": { @@ -97,4 +97,4 @@ "path": "client-guardian/debug" } } -} \ No newline at end of file +} diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/nav.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/nav.js new file mode 100644 index 00000000..ee79e4b7 --- /dev/null +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/nav.js @@ -0,0 +1,125 @@ +'use strict'; +'require baseclass'; + +/** + * CrowdSec Dashboard Navigation + * SecuBox themed navigation tabs + */ + +var tabs = [ + { id: 'wizard', icon: 'πŸš€', label: _('Setup Wizard'), path: ['admin', 'secubox', 'security', 'crowdsec', 'wizard'] }, + { id: 'overview', icon: 'πŸ“Š', label: _('Overview'), path: ['admin', 'secubox', 'security', 'crowdsec', 'overview'] }, + { id: 'decisions', icon: 'β›”', label: _('Decisions'), path: ['admin', 'secubox', 'security', 'crowdsec', 'decisions'] }, + { id: 'alerts', icon: '⚠️', label: _('Alerts'), path: ['admin', 'secubox', 'security', 'crowdsec', 'alerts'] }, + { id: 'bouncers', icon: 'πŸ›‘οΈ', label: _('Bouncers'), path: ['admin', 'secubox', 'security', 'crowdsec', 'bouncers'] }, + { id: 'waf', icon: 'πŸ”₯', label: _('WAF/AppSec'), path: ['admin', 'secubox', 'security', 'crowdsec', 'waf'] }, + { id: 'metrics', icon: 'πŸ“ˆ', label: _('Metrics'), path: ['admin', 'secubox', 'security', 'crowdsec', 'metrics'] }, + { id: 'settings', icon: 'βš™οΈ', label: _('Settings'), path: ['admin', 'secubox', 'security', 'crowdsec', 'settings'] } +]; + +return baseclass.extend({ + getTabs: function() { + return tabs.slice(); + }, + + ensureLuCITabsHidden: function() { + if (typeof document === 'undefined') + return; + if (document.getElementById('crowdsec-tabstyle')) + return; + var style = document.createElement('style'); + style.id = 'crowdsec-tabstyle'; + style.textContent = ` +/* Hide default LuCI tabs for CrowdSec */ +body[data-page^="admin-secubox-security-crowdsec"] .tabs, +body[data-page^="admin-secubox-security-crowdsec"] #tabmenu, +body[data-page^="admin-secubox-security-crowdsec"] .cbi-tabmenu, +body[data-page^="admin-secubox-security-crowdsec"] .nav-tabs, +body[data-page^="admin-secubox-security-crowdsec"] ul.cbi-tabmenu { + display: none !important; +} + +/* CrowdSec Nav Tabs */ +.cs-nav-tabs { + display: flex; + gap: 4px; + margin-bottom: 24px; + padding: 6px; + background: var(--cs-bg-secondary); + border-radius: var(--cs-radius-lg); + border: 1px solid var(--cs-border); + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +.cs-nav-tab { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 16px; + border-radius: var(--cs-radius); + background: transparent; + border: none; + color: var(--cs-text-secondary); + font-weight: 500; + font-size: 13px; + cursor: pointer; + text-decoration: none; + transition: all 0.2s ease; + white-space: nowrap; +} + +.cs-nav-tab:hover { + color: var(--cs-text-primary); + background: var(--cs-bg-tertiary); +} + +.cs-nav-tab.active { + color: var(--cs-accent-green); + background: var(--cs-bg-tertiary); + box-shadow: inset 0 -2px 0 var(--cs-accent-green); +} + +.cs-tab-icon { + font-size: 16px; + line-height: 1; +} + +.cs-tab-label { + font-family: var(--cs-font-sans); +} + +@media (max-width: 768px) { + .cs-nav-tabs { + padding: 4px; + } + .cs-nav-tab { + padding: 8px 12px; + font-size: 12px; + } + .cs-tab-label { + display: none; + } + .cs-tab-icon { + font-size: 18px; + } +} + `; + document.head && document.head.appendChild(style); + }, + + renderTabs: function(active) { + this.ensureLuCITabsHidden(); + return E('div', { 'class': 'cs-nav-tabs' }, + this.getTabs().map(function(tab) { + return E('a', { + 'class': 'cs-nav-tab' + (tab.id === active ? ' active' : ''), + 'href': L.url.apply(L, tab.path) + }, [ + E('span', { 'class': 'cs-tab-icon' }, tab.icon), + E('span', { 'class': 'cs-tab-label' }, tab.label) + ]); + }) + ); + } +}); diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/alerts.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/alerts.js index 754f3ace..38d1d82f 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/alerts.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/alerts.js @@ -5,6 +5,7 @@ 'require poll'; 'require ui'; 'require crowdsec-dashboard/api as api'; +'require crowdsec-dashboard/nav as CsNav'; /** * CrowdSec Dashboard - Alerts View @@ -262,6 +263,7 @@ return view.extend({ this.filterAlerts(); var view = E('div', { 'class': 'crowdsec-dashboard' }, [ + CsNav.renderTabs('alerts'), this.renderStats(), E('div', { 'class': 'cs-card' }, [ E('div', { 'class': 'cs-card-header' }, [ diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/bouncers.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/bouncers.js index 7d31526d..6b9e85b2 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/bouncers.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/bouncers.js @@ -5,9 +5,15 @@ 'require poll'; 'require ui'; 'require crowdsec-dashboard/api as API'; +'require crowdsec-dashboard/nav as CsNav'; return view.extend({ load: function() { + var cssLink = document.createElement('link'); + cssLink.rel = 'stylesheet'; + cssLink.href = L.resource('crowdsec-dashboard/dashboard.css'); + document.head.appendChild(cssLink); + return Promise.all([ API.getBouncers(), API.getStatus(), @@ -22,11 +28,8 @@ return view.extend({ var fwStatus = data[2] || {}; var nftStats = data[3] || {}; - var view = E('div', { 'class': 'cbi-map' }, [ - E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }), - E('h2', {}, _('CrowdSec Bouncers')), - E('div', { 'class': 'cbi-map-descr' }, - _('Bouncers are components that enforce CrowdSec decisions by blocking malicious IPs at various points (firewall, web server, etc.).')), + var view = E('div', { 'class': 'crowdsec-dashboard' }, [ + CsNav.renderTabs('bouncers'), // Status Card E('div', { 'class': 'cbi-section', 'style': 'background: ' + (status.crowdsec === 'running' ? '#d4edda' : '#f8d7da') + '; border-left: 4px solid ' + (status.crowdsec === 'running' ? '#28a745' : '#dc3545') + '; padding: 1em; margin-bottom: 1.5em;' }, [ diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/decisions.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/decisions.js index 0f7ef911..6007936a 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/decisions.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/decisions.js @@ -5,6 +5,7 @@ 'require poll'; 'require ui'; 'require crowdsec-dashboard/api as api'; +'require crowdsec-dashboard/nav as CsNav'; /** * CrowdSec Dashboard - Decisions View @@ -397,6 +398,7 @@ return view.extend({ this.filterDecisions(); var view = E('div', { 'class': 'crowdsec-dashboard' }, [ + CsNav.renderTabs('decisions'), E('div', { 'class': 'cs-card' }, [ E('div', { 'class': 'cs-card-header' }, [ E('div', { 'class': 'cs-card-title' }, [ diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/metrics.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/metrics.js index ba4019df..95d2e409 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/metrics.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/metrics.js @@ -5,6 +5,7 @@ 'require poll'; 'require ui'; 'require crowdsec-dashboard/api as api'; +'require crowdsec-dashboard/nav as CsNav'; /** * CrowdSec Dashboard - Metrics View @@ -330,13 +331,14 @@ return view.extend({ this.hub = data.hub || {}; var metricsConfig = data.metricsConfig || {}; - var view = E('div', { 'class': 'cyber-container crowdsec-metrics' }, [ + var view = E('div', { 'class': 'crowdsec-dashboard crowdsec-metrics' }, [ E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }), + CsNav.renderTabs('metrics'), // Page Header E('div', { 'style': 'margin-bottom: 1.5rem;' }, [ - E('h2', { 'style': 'color: var(--cyber-text-primary, #fff); margin: 0 0 0.5rem 0;' }, _('CrowdSec Metrics')), - E('p', { 'style': 'color: var(--cyber-text-secondary, #a0a0b0); margin: 0;' }, _('Detailed metrics and statistics from CrowdSec engine')) + E('h2', { 'style': 'color: var(--cs-text-primary, #e6edf3); margin: 0 0 0.5rem 0;' }, _('CrowdSec Metrics')), + E('p', { 'style': 'color: var(--cs-text-secondary, #8b949e); margin: 0;' }, _('Detailed metrics and statistics from CrowdSec engine')) ]), // Metrics Configuration diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/overview.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/overview.js index d2aeb93c..fd17b65b 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/overview.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/overview.js @@ -6,6 +6,7 @@ 'require ui'; 'require fs'; 'require crowdsec-dashboard/api as api'; +'require crowdsec-dashboard/nav as CsNav'; /** * CrowdSec Dashboard - Overview View @@ -500,8 +501,9 @@ return view.extend({ var self = this; this.data = payload[0] || {}; this.logs = (payload[1] && payload[1].entries) || []; - + var view = E('div', { 'class': 'crowdsec-dashboard' }, [ + CsNav.renderTabs('overview'), E('div', { 'id': 'cs-dashboard-content' }, this.renderContent(this.data)) ]); diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/settings.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/settings.js index db618b36..d95a86a3 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/settings.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/settings.js @@ -3,6 +3,7 @@ 'require secubox-theme/theme as Theme'; 'require ui'; 'require crowdsec-dashboard/api as API'; +'require crowdsec-dashboard/nav as CsNav'; return view.extend({ load: function() { @@ -23,10 +24,19 @@ return view.extend({ var collections = collectionsData.collections || []; if (collections.collections) collections = collections.collections; - var view = E('div', { 'class': 'cbi-map' }, [ + // Load CSS + var head = document.head || document.getElementsByTagName('head')[0]; + var cssLink = E('link', { + 'rel': 'stylesheet', + 'href': L.resource('crowdsec-dashboard/dashboard.css') + }); + head.appendChild(cssLink); + + var view = E('div', { 'class': 'crowdsec-dashboard' }, [ E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }), - E('h2', {}, _('CrowdSec Settings')), - E('div', { 'class': 'cbi-map-descr' }, + CsNav.renderTabs('settings'), + E('h2', { 'class': 'cs-page-title' }, _('CrowdSec Settings')), + E('p', { 'style': 'color: var(--cs-text-secondary); margin-bottom: 1.5rem;' }, _('Configure and manage your CrowdSec installation, machines, and collections.')), // Service Status diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/waf.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/waf.js index db7fa05e..4fb10d9a 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/waf.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/waf.js @@ -5,6 +5,7 @@ 'require poll'; 'require ui'; 'require crowdsec-dashboard/api as api'; +'require crowdsec-dashboard/nav as CsNav'; /** * CrowdSec Dashboard - WAF/AppSec View @@ -158,8 +159,9 @@ return view.extend({ (navigator.language ? navigator.language.split('-')[0] : 'en'); Theme.init({ language: lang }); - return E('div', { 'class': 'cs-dashboard' }, [ + return E('div', { 'class': 'crowdsec-dashboard' }, [ E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }), + CsNav.renderTabs('waf'), E('h2', { 'class': 'cs-page-title' }, _('CrowdSec WAF/AppSec')), E('div', { 'class': 'cs-grid' }, [ this.renderWAFStatus(), diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/wizard.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/wizard.js index 4a472cbc..6416607b 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/wizard.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/wizard.js @@ -5,7 +5,8 @@ 'require form'; 'require rpc'; 'require uci'; -'require crowdsec-dashboard.api as API'; +'require crowdsec-dashboard/api as API'; +'require crowdsec-dashboard/nav as CsNav'; return view.extend({ wizardData: { @@ -132,7 +133,10 @@ return view.extend({ }); head.appendChild(themeLink); - var container = E('div', { 'class': 'wizard-container' }); + var container = E('div', { 'class': 'crowdsec-dashboard wizard-container' }); + + // Add navigation tabs + container.appendChild(CsNav.renderTabs('wizard')); // Create stepper container.appendChild(this.createStepper());