From fec4b5a12817e664992eb2bbe88a76b9f46a6da2 Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Fri, 9 Jan 2026 15:57:26 +0100 Subject: [PATCH] feat: Add Apps section to SecuBox portal navigation - Add "Apps" tab to header navigation for extended applications - Create apps.js view showing app categories: Administration, Services, IoT - Include SecuBox Admin, Cyber Dashboard, vHost Manager, Zigbee2MQTT, MagicMirror, and MQTT Bridge - Move ndpid and netifyd detection to Monitoring section - Add menu entry for /admin/secubox/apps Co-Authored-By: Claude Opus 4.5 --- .../resources/secubox-portal/header.js | 10 +- .../resources/view/secubox-portal/apps.js | 296 ++++++++++++++++++ .../luci/menu.d/luci-app-secubox-portal.json | 8 + 3 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 package/secubox/luci-app-secubox-portal/htdocs/luci-static/resources/view/secubox-portal/apps.js diff --git a/package/secubox/luci-app-secubox-portal/htdocs/luci-static/resources/secubox-portal/header.js b/package/secubox/luci-app-secubox-portal/htdocs/luci-static/resources/secubox-portal/header.js index fca7537f..2ddfab71 100644 --- a/package/secubox/luci-app-secubox-portal/htdocs/luci-static/resources/secubox-portal/header.js +++ b/package/secubox/luci-app-secubox-portal/htdocs/luci-static/resources/secubox-portal/header.js @@ -227,7 +227,8 @@ var sections = [ { id: 'security', name: 'Security', icon: '\ud83d\udee1\ufe0f', path: 'admin/secubox/security' }, { id: 'network', name: 'Network', icon: '\ud83c\udf10', path: 'admin/secubox/network' }, { id: 'monitoring', name: 'Monitoring', icon: '\ud83d\udcca', path: 'admin/secubox/monitoring' }, - { id: 'system', name: 'System', icon: '\u2699\ufe0f', path: 'admin/secubox/system' } + { id: 'system', name: 'System', icon: '\u2699\ufe0f', path: 'admin/secubox/system' }, + { id: 'apps', name: 'Apps', icon: '\ud83d\udce6', path: 'admin/secubox/apps' } ]; function injectCSS() { @@ -278,7 +279,14 @@ function detectActiveSection() { if (path.indexOf('/secubox/security') !== -1) return 'security'; if (path.indexOf('/secubox/network') !== -1) return 'network'; if (path.indexOf('/secubox/monitoring') !== -1) return 'monitoring'; + if (path.indexOf('/secubox/ndpid') !== -1) return 'monitoring'; + if (path.indexOf('/secubox/netifyd') !== -1) return 'monitoring'; if (path.indexOf('/secubox/system') !== -1) return 'system'; + if (path.indexOf('/secubox/apps') !== -1) return 'apps'; + if (path.indexOf('/secubox/admin') !== -1) return 'apps'; + if (path.indexOf('/secubox/services') !== -1) return 'apps'; + if (path.indexOf('/secubox/iot') !== -1) return 'apps'; + if (path.indexOf('/secubox/zigbee2mqtt') !== -1) return 'apps'; return 'dashboard'; } diff --git a/package/secubox/luci-app-secubox-portal/htdocs/luci-static/resources/view/secubox-portal/apps.js b/package/secubox/luci-app-secubox-portal/htdocs/luci-static/resources/view/secubox-portal/apps.js new file mode 100644 index 00000000..e46b01e6 --- /dev/null +++ b/package/secubox/luci-app-secubox-portal/htdocs/luci-static/resources/view/secubox-portal/apps.js @@ -0,0 +1,296 @@ +'use strict'; +'require view'; +'require dom'; +'require ui'; +'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')) || + (navigator.language ? navigator.language.split('-')[0] : 'en'); +Theme.init({ language: lang }); + +// Extended Apps catalog - apps not in main nav sections +var appCategories = [ + { + id: 'admin', + name: 'Administration', + icon: '\ud83d\udee0\ufe0f', + description: 'SecuBox administration and app management', + apps: [ + { id: 'secubox-admin', name: 'SecuBox Admin', icon: '\ud83d\udcbb', path: 'admin/secubox/admin', desc: 'App catalog, updates, and system configuration' }, + { id: 'cyber-dashboard', name: 'Cyber Dashboard', icon: '\ud83d\udcca', path: 'admin/secubox/admin/cyber-dashboard', desc: 'Advanced analytics and insights' } + ] + }, + { + id: 'services', + name: 'Services', + icon: '\ud83d\udd27', + description: 'Server and service management', + apps: [ + { id: 'vhost-manager', name: 'Virtual Hosts', icon: '\ud83c\udf10', path: 'admin/secubox/services/vhosts', desc: 'Web server virtual hosts and SSL certificates' } + ] + }, + { + id: 'iot', + name: 'IoT & Smart Home', + icon: '\ud83c\udfe0', + description: 'Internet of Things and home automation', + apps: [ + { id: 'zigbee2mqtt', name: 'Zigbee2MQTT', icon: '\ud83d\udca1', path: 'admin/secubox/zigbee2mqtt', desc: 'Zigbee device bridge for smart home' }, + { id: 'magicmirror', name: 'MagicMirror', icon: '\ud83e\ude9e', path: 'admin/secubox/iot/magicmirror', desc: 'Smart mirror display management' }, + { id: 'mqtt-bridge', name: 'MQTT Bridge', icon: '\ud83d\udd17', path: 'admin/secubox/network/mqtt-bridge', desc: 'MQTT message broker and bridge' } + ] + } +]; + +return view.extend({ + render: function() { + // Main wrapper with SecuBox header + var wrapper = E('div', { 'class': 'secubox-page-wrapper' }); + wrapper.appendChild(SbHeader.render()); + + var container = E('div', { 'class': 'sb-apps-view' }, [ + E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }), + E('style', {}, this.getStyles()), + this.renderHeader(), + this.renderAppGrid() + ]); + + wrapper.appendChild(container); + return wrapper; + }, + + renderHeader: function() { + return E('div', { 'class': 'sb-apps-header' }, [ + E('div', { 'class': 'sb-apps-title-row' }, [ + E('h1', { 'class': 'sb-apps-title' }, [ + E('span', { 'class': 'sb-apps-icon' }, '\ud83d\udce6'), + _('Extended Apps') + ]), + E('span', { 'class': 'sb-apps-badge' }, appCategories.reduce(function(sum, cat) { + return sum + cat.apps.length; + }, 0) + ' ' + _('apps')) + ]), + E('p', { 'class': 'sb-apps-subtitle' }, + _('Additional SecuBox applications for administration, IoT, and advanced features')) + ]); + }, + + renderAppGrid: function() { + var self = this; + return E('div', { 'class': 'sb-apps-categories' }, + appCategories.map(function(category) { + return self.renderCategory(category); + }) + ); + }, + + renderCategory: function(category) { + var self = this; + return E('div', { 'class': 'sb-apps-category' }, [ + E('div', { 'class': 'sb-apps-category-header' }, [ + E('span', { 'class': 'sb-apps-category-icon' }, category.icon), + E('div', {}, [ + E('h2', { 'class': 'sb-apps-category-title' }, category.name), + E('p', { 'class': 'sb-apps-category-desc' }, category.description) + ]) + ]), + E('div', { 'class': 'sb-apps-grid' }, + category.apps.map(function(app) { + return self.renderAppCard(app); + }) + ) + ]); + }, + + renderAppCard: function(app) { + return E('a', { + 'class': 'sb-app-card', + 'href': L.url(app.path) + }, [ + E('div', { 'class': 'sb-app-card-icon' }, app.icon), + E('div', { 'class': 'sb-app-card-content' }, [ + E('h3', { 'class': 'sb-app-card-name' }, app.name), + E('p', { 'class': 'sb-app-card-desc' }, app.desc) + ]), + E('div', { 'class': 'sb-app-card-arrow' }, '\u2192') + ]); + }, + + getStyles: function() { + return ` +.sb-apps-view { + min-height: 100vh; + background: #0a0a0f; + color: #fafafa; + padding: 20px; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; +} + +.sb-apps-header { + margin-bottom: 32px; + padding: 24px; + background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%); + border: 1px solid rgba(102, 126, 234, 0.2); + border-radius: 16px; +} + +.sb-apps-title-row { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 12px; +} + +.sb-apps-title { + display: flex; + align-items: center; + gap: 12px; + margin: 0; + font-size: 1.75rem; + font-weight: 700; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.sb-apps-icon { + font-size: 2rem; + -webkit-text-fill-color: initial; +} + +.sb-apps-badge { + padding: 6px 14px; + background: rgba(102, 126, 234, 0.2); + border: 1px solid rgba(102, 126, 234, 0.3); + border-radius: 20px; + font-size: 0.8rem; + font-weight: 600; + color: #a5b4fc; +} + +.sb-apps-subtitle { + margin: 8px 0 0 0; + color: #a0a0b0; + font-size: 0.95rem; +} + +.sb-apps-categories { + display: flex; + flex-direction: column; + gap: 32px; +} + +.sb-apps-category { + background: #12121a; + border: 1px solid #2a2a35; + border-radius: 16px; + padding: 24px; +} + +.sb-apps-category-header { + display: flex; + align-items: flex-start; + gap: 16px; + margin-bottom: 20px; + padding-bottom: 16px; + border-bottom: 1px solid #2a2a35; +} + +.sb-apps-category-icon { + font-size: 2rem; + line-height: 1; +} + +.sb-apps-category-title { + margin: 0 0 4px 0; + font-size: 1.25rem; + font-weight: 600; + color: #fafafa; +} + +.sb-apps-category-desc { + margin: 0; + font-size: 0.85rem; + color: #71717a; +} + +.sb-apps-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 16px; +} + +.sb-app-card { + display: flex; + align-items: center; + gap: 16px; + padding: 16px 20px; + background: #1a1a24; + border: 1px solid #2a2a35; + border-radius: 12px; + text-decoration: none; + color: inherit; + transition: all 0.2s ease; +} + +.sb-app-card:hover { + background: #1f1f2a; + border-color: #667eea; + transform: translateY(-2px); + box-shadow: 0 8px 24px rgba(102, 126, 234, 0.15); +} + +.sb-app-card-icon { + font-size: 2rem; + line-height: 1; + flex-shrink: 0; +} + +.sb-app-card-content { + flex: 1; + min-width: 0; +} + +.sb-app-card-name { + margin: 0 0 4px 0; + font-size: 1rem; + font-weight: 600; + color: #fafafa; +} + +.sb-app-card-desc { + margin: 0; + font-size: 0.8rem; + color: #71717a; + line-height: 1.4; +} + +.sb-app-card-arrow { + font-size: 1.25rem; + color: #667eea; + opacity: 0; + transform: translateX(-8px); + transition: all 0.2s ease; +} + +.sb-app-card:hover .sb-app-card-arrow { + opacity: 1; + transform: translateX(0); +} + +@media (max-width: 640px) { + .sb-apps-grid { + grid-template-columns: 1fr; + } + + .sb-apps-title { + font-size: 1.5rem; + } +} +`; + } +}); diff --git a/package/secubox/luci-app-secubox-portal/root/usr/share/luci/menu.d/luci-app-secubox-portal.json b/package/secubox/luci-app-secubox-portal/root/usr/share/luci/menu.d/luci-app-secubox-portal.json index fad02a62..50cb18dd 100644 --- a/package/secubox/luci-app-secubox-portal/root/usr/share/luci/menu.d/luci-app-secubox-portal.json +++ b/package/secubox/luci-app-secubox-portal/root/usr/share/luci/menu.d/luci-app-secubox-portal.json @@ -15,6 +15,14 @@ "path": "secubox-portal/index" } }, + "admin/secubox/apps": { + "title": "Apps", + "order": 60, + "action": { + "type": "view", + "path": "secubox-portal/apps" + } + }, "admin/secubox-home": { "title": "SecuBox Home", "order": 0,