feat: SecuBox modules v2 - Responsive cards with versions and actions
Major improvements to modules page: - Responsive grid layout with modern card design - Module versions display (v0.0.9) - Category filter tabs (All, Security, Monitoring, Network, System) - Quick actions (Start/Stop/Restart/Dashboard) - Real-time status indicators with animations - Emoji icons properly displayed - Auto-refresh every 30 seconds Changes: - modules.js: Complete rewrite with responsive cards - modules.css: New CSS with theme support and animations - secubox config: Added emoji icons and version fields - RPCD backend: Added version field to module data Features: ✨ Responsive 3-column grid (auto-adapts to screen size) 🎯 Category filtering with animated tabs ▶️ One-click start/stop/restart actions 📊 Dashboard quick links for each module 💫 Smooth animations and hover effects 🌓 Full dark/light theme support 📱 Mobile-friendly design 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
4bdda363a0
commit
3dcc89d3a3
42
deploy-modules-v2.sh
Executable file
42
deploy-modules-v2.sh
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
# Deploy SecuBox Modules v2 - Responsive cards with versions and actions
|
||||
|
||||
ROUTER="root@192.168.8.191"
|
||||
|
||||
echo "🚀 Deploying SecuBox Modules v2 to $ROUTER"
|
||||
echo ""
|
||||
|
||||
echo "📦 Deploying modules view and CSS..."
|
||||
scp luci-app-secubox/htdocs/luci-static/resources/view/secubox/modules.js \
|
||||
"$ROUTER:/www/luci-static/resources/view/secubox/"
|
||||
|
||||
scp luci-app-secubox/htdocs/luci-static/resources/secubox/modules.css \
|
||||
"$ROUTER:/www/luci-static/resources/secubox/"
|
||||
|
||||
echo "📝 Deploying updated config with versions..."
|
||||
scp luci-app-secubox/root/etc/config/secubox \
|
||||
"$ROUTER:/etc/config/secubox"
|
||||
|
||||
echo "🔧 Deploying updated RPCD backend..."
|
||||
scp luci-app-secubox/root/usr/libexec/rpcd/luci.secubox \
|
||||
"$ROUTER:/usr/libexec/rpcd/"
|
||||
|
||||
echo "🔄 Setting permissions and restarting services..."
|
||||
ssh "$ROUTER" "chmod +x /usr/libexec/rpcd/luci.secubox"
|
||||
ssh "$ROUTER" "chmod 644 /www/luci-static/resources/view/secubox/modules.js"
|
||||
ssh "$ROUTER" "chmod 644 /www/luci-static/resources/secubox/modules.css"
|
||||
ssh "$ROUTER" "/etc/init.d/rpcd restart"
|
||||
|
||||
echo ""
|
||||
echo "✅ Modules v2 deployed successfully!"
|
||||
echo ""
|
||||
echo "🎨 New features:"
|
||||
echo " • Responsive grid layout"
|
||||
echo " • Module versions (v0.0.9)"
|
||||
echo " • Category filter tabs"
|
||||
echo " • Start/Stop/Restart actions"
|
||||
echo " • Dashboard quick links"
|
||||
echo " • Real-time status indicators"
|
||||
echo " • Modern card design with icons"
|
||||
echo ""
|
||||
echo "👉 Refresh your browser (Ctrl+Shift+R) and go to SecuBox → Modules"
|
||||
37
deploy-secubox-fix.sh
Executable file
37
deploy-secubox-fix.sh
Executable file
@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
# Deploy SecuBox config fix - Module icons emoji fix
|
||||
|
||||
ROUTER="root@192.168.8.191"
|
||||
|
||||
echo "🔧 Deploying SecuBox config fix to $ROUTER"
|
||||
echo ""
|
||||
|
||||
echo "📝 Backing up current config..."
|
||||
ssh "$ROUTER" "cp /etc/config/secubox /etc/config/secubox.backup.$(date +%Y%m%d-%H%M%S)"
|
||||
|
||||
echo "📦 Deploying updated config with emoji icons..."
|
||||
scp luci-app-secubox/root/etc/config/secubox "$ROUTER:/etc/config/secubox"
|
||||
|
||||
echo "🔄 Restarting RPCD..."
|
||||
ssh "$ROUTER" "/etc/init.d/rpcd restart"
|
||||
|
||||
echo ""
|
||||
echo "✅ Config deployed successfully!"
|
||||
echo ""
|
||||
echo "🎨 Fixed module icons:"
|
||||
echo " 🛡️ CrowdSec Dashboard"
|
||||
echo " 📊 Netdata Dashboard"
|
||||
echo " 🔍 Netifyd Dashboard"
|
||||
echo " 🔒 WireGuard Dashboard"
|
||||
echo " 🌐 Network Modes"
|
||||
echo " 👁️ Client Guardian"
|
||||
echo " ⚙️ System Hub"
|
||||
echo " 📦 CDN Cache"
|
||||
echo " 📡 Bandwidth Manager"
|
||||
echo " 🔑 Auth Guardian"
|
||||
echo " ▶️ Media Flow"
|
||||
echo " 🖥️ Virtual Host Manager"
|
||||
echo " 📈 Traffic Shaper"
|
||||
echo " 🔐 KSM Manager"
|
||||
echo ""
|
||||
echo "👉 Refresh your browser (Ctrl+Shift+R) to see the changes"
|
||||
@ -0,0 +1,442 @@
|
||||
/* SecuBox Modules Page Styles */
|
||||
|
||||
.secubox-modules-page {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* Header Section */
|
||||
.secubox-modules-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 12px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.secubox-stat-badge {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
background: var(--sb-bg-card);
|
||||
border: 2px solid var(--sb-border);
|
||||
border-radius: 12px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.secubox-stat-badge:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px var(--sb-shadow);
|
||||
}
|
||||
|
||||
.secubox-stat-badge.secubox-stat-success {
|
||||
border-color: #22c55e;
|
||||
background: linear-gradient(135deg, var(--sb-bg-card) 0%, rgba(34, 197, 94, 0.1) 100%);
|
||||
}
|
||||
|
||||
.secubox-stat-badge.secubox-stat-warning {
|
||||
border-color: #f59e0b;
|
||||
background: linear-gradient(135deg, var(--sb-bg-card) 0%, rgba(245, 158, 11, 0.1) 100%);
|
||||
}
|
||||
|
||||
.secubox-stat-badge.secubox-stat-muted {
|
||||
border-color: #64748b;
|
||||
background: linear-gradient(135deg, var(--sb-bg-card) 0%, rgba(100, 116, 139, 0.05) 100%);
|
||||
}
|
||||
|
||||
.secubox-stat-value {
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
color: var(--sb-text);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.secubox-stat-label {
|
||||
font-size: 12px;
|
||||
color: var(--sb-text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* Filter Tabs */
|
||||
.secubox-filter-tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin: 24px 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.secubox-filter-tab {
|
||||
padding: 10px 20px;
|
||||
background: var(--sb-bg-card);
|
||||
border: 2px solid var(--sb-border);
|
||||
border-radius: 8px;
|
||||
color: var(--sb-text);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.secubox-filter-tab:hover {
|
||||
background: var(--sb-bg);
|
||||
border-color: var(--sb-primary);
|
||||
}
|
||||
|
||||
.secubox-filter-tab.active {
|
||||
background: var(--sb-primary);
|
||||
border-color: var(--sb-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Modules Grid */
|
||||
.secubox-modules-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.secubox-modules-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Module Card */
|
||||
.secubox-module-card {
|
||||
background: var(--sb-bg-card);
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--sb-border);
|
||||
overflow: hidden;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.secubox-module-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 8px 24px var(--sb-hover-shadow);
|
||||
}
|
||||
|
||||
.secubox-module-card.secubox-module-running {
|
||||
border-left-width: 4px;
|
||||
}
|
||||
|
||||
.secubox-module-card.secubox-module-stopped {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.secubox-module-card.secubox-module-not-installed {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* Card Header */
|
||||
.secubox-module-card-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg, var(--sb-bg) 0%, var(--sb-bg-card) 100%);
|
||||
border-bottom: 1px solid var(--sb-border);
|
||||
}
|
||||
|
||||
.secubox-module-icon {
|
||||
font-size: 36px;
|
||||
flex-shrink: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.secubox-module-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.secubox-module-name {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--sb-text);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.secubox-module-meta {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.secubox-module-category,
|
||||
.secubox-module-version {
|
||||
font-size: 12px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--sb-bg);
|
||||
color: var(--sb-text-muted);
|
||||
border: 1px solid var(--sb-border);
|
||||
}
|
||||
|
||||
.secubox-status-indicator {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.secubox-status-indicator.secubox-status-running {
|
||||
background: #22c55e;
|
||||
box-shadow: 0 0 8px #22c55e;
|
||||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
.secubox-status-indicator.secubox-status-stopped {
|
||||
background: #f59e0b;
|
||||
}
|
||||
|
||||
.secubox-status-indicator.secubox-status-not-installed {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* Card Body */
|
||||
.secubox-module-card-body {
|
||||
padding: 20px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.secubox-module-description {
|
||||
margin: 0;
|
||||
color: var(--sb-text);
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.secubox-module-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.secubox-module-detail {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.secubox-detail-label {
|
||||
color: var(--sb-text-muted);
|
||||
font-weight: 500;
|
||||
min-width: 70px;
|
||||
}
|
||||
|
||||
.secubox-detail-value {
|
||||
color: var(--sb-text);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.secubox-detail-value code {
|
||||
background: var(--sb-bg);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
border: 1px solid var(--sb-border);
|
||||
}
|
||||
|
||||
.secubox-status-text-running {
|
||||
color: #22c55e;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.secubox-status-text-stopped {
|
||||
color: #f59e0b;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.secubox-status-text-not-installed {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
/* Card Actions */
|
||||
.secubox-module-card-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 16px 20px;
|
||||
background: var(--sb-bg);
|
||||
border-top: 1px solid var(--sb-border);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.secubox-btn {
|
||||
padding: 8px 16px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.secubox-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.secubox-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.secubox-btn-sm {
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.secubox-btn-primary {
|
||||
background: var(--sb-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.secubox-btn-primary:hover {
|
||||
background: var(--sb-primary-dark);
|
||||
}
|
||||
|
||||
.secubox-btn-success {
|
||||
background: #22c55e;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.secubox-btn-success:hover {
|
||||
background: #16a34a;
|
||||
}
|
||||
|
||||
.secubox-btn-danger {
|
||||
background: #ef4444;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.secubox-btn-danger:hover {
|
||||
background: #dc2626;
|
||||
}
|
||||
|
||||
.secubox-btn-warning {
|
||||
background: #f59e0b;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.secubox-btn-warning:hover {
|
||||
background: #d97706;
|
||||
}
|
||||
|
||||
.secubox-btn-secondary {
|
||||
background: var(--sb-bg-card);
|
||||
color: var(--sb-text-muted);
|
||||
border: 1px solid var(--sb-border);
|
||||
}
|
||||
|
||||
.secubox-btn-secondary:hover {
|
||||
background: var(--sb-bg);
|
||||
}
|
||||
|
||||
.secubox-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.secubox-btn:disabled:hover {
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Empty State */
|
||||
.secubox-empty-state {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
background: var(--sb-bg-card);
|
||||
border: 2px dashed var(--sb-border);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.secubox-empty-icon {
|
||||
font-size: 64px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.secubox-empty-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: var(--sb-text);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.secubox-empty-text {
|
||||
color: var(--sb-text-muted);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 480px) {
|
||||
.secubox-modules-page {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.secubox-modules-stats {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.secubox-filter-tabs {
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.secubox-filter-tab {
|
||||
padding: 8px 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.secubox-module-card-header {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.secubox-module-card-body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.secubox-module-card-actions {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.secubox-btn {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark/Light theme specific adjustments */
|
||||
[data-theme="light"] .secubox-module-card:hover {
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
[data-theme="light"] .secubox-stat-badge:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
@ -1,51 +1,378 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require rpc';
|
||||
'require ui';
|
||||
'require dom';
|
||||
'require secubox/api as API';
|
||||
'require secubox/theme as Theme';
|
||||
'require poll';
|
||||
|
||||
// Load CSS
|
||||
document.head.appendChild(E('link', {
|
||||
'rel': 'stylesheet',
|
||||
'type': 'text/css',
|
||||
'href': L.resource('secubox/secubox.css')
|
||||
}));
|
||||
document.head.appendChild(E('link', {
|
||||
'rel': 'stylesheet',
|
||||
'type': 'text/css',
|
||||
'href': L.resource('secubox/modules.css')
|
||||
}));
|
||||
|
||||
// Initialize theme
|
||||
Theme.init();
|
||||
|
||||
var callModules = rpc.declare({
|
||||
object: 'luci.secubox',
|
||||
method: 'modules',
|
||||
expect: { modules: [] }
|
||||
});
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return callModules();
|
||||
},
|
||||
render: function(data) {
|
||||
var modules = Array.isArray(data) ? data : (data && data.modules ? data.modules : []);
|
||||
modulesData: [],
|
||||
|
||||
if (modules.length === 0) {
|
||||
return E('div', {'class':'cbi-map'}, [
|
||||
E('h2', {}, '📦 SecuBox Modules'),
|
||||
E('div', {'style':'color:#856404;padding:20px;background:#fff3cd;border:2px solid #ffc107;border-radius:8px'},
|
||||
E('p', {}, '⚠️ No modules found. Please check your configuration.'))
|
||||
]);
|
||||
}
|
||||
load: function() {
|
||||
return this.refreshData();
|
||||
},
|
||||
|
||||
return E('div', {'class':'cbi-map'}, [
|
||||
E('h2', {}, '📦 SecuBox Modules'),
|
||||
E('p', {'style':'color:#64748b;margin-bottom:20px'},
|
||||
modules.length + ' modules available • ' +
|
||||
modules.filter(function(m) { return m.installed; }).length + ' installed • ' +
|
||||
modules.filter(function(m) { return m.running; }).length + ' running'
|
||||
),
|
||||
E('div', {'style':'display:grid;gap:12px'}, modules.map(function(m) {
|
||||
return E('div', {'style':'background:#1e293b;padding:16px;border-radius:8px;border-left:4px solid '+(m.color||'#64748b')}, [
|
||||
E('div', {'style':'font-weight:bold;color:#f1f5f9'}, m.name || m.id || 'Unknown'),
|
||||
E('div', {'style':'color:#94a3b8;font-size:14px;margin:4px 0'}, m.description || ''),
|
||||
E('div', {'style':'display:flex;gap:8px;margin-top:8px'}, [
|
||||
E('span', {'style':'padding:2px 8px;border-radius:4px;font-size:12px;background:'+(m.running?'#22c55e20;color:#22c55e':m.installed?'#f59e0b20;color:#f59e0b':'#64748b20;color:#64748b')},
|
||||
m.running ? '✓ Running' : m.installed ? '○ Stopped' : '- Not Installed'),
|
||||
E('span', {'style':'padding:2px 8px;border-radius:4px;font-size:12px;background:#1e293b;color:#94a3b8;border:1px solid #334155'},
|
||||
m.category || 'other')
|
||||
])
|
||||
]);
|
||||
}))
|
||||
]);
|
||||
}
|
||||
refreshData: function() {
|
||||
var self = this;
|
||||
return API.getModules().then(function(data) {
|
||||
self.modulesData = data.modules || [];
|
||||
return data;
|
||||
});
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var self = this;
|
||||
var modules = this.modulesData;
|
||||
|
||||
var container = E('div', { 'class': 'secubox-modules-page' });
|
||||
|
||||
// Header with stats
|
||||
container.appendChild(this.renderHeader(modules));
|
||||
|
||||
// Filter tabs
|
||||
container.appendChild(this.renderFilterTabs());
|
||||
|
||||
// Modules grid
|
||||
container.appendChild(E('div', { 'id': 'modules-grid', 'class': 'secubox-modules-grid' },
|
||||
this.renderModuleCards(modules, 'all')
|
||||
));
|
||||
|
||||
// Auto-refresh
|
||||
poll.add(function() {
|
||||
return self.refreshData().then(function() {
|
||||
self.updateModulesGrid();
|
||||
});
|
||||
}, 30);
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
renderHeader: function(modules) {
|
||||
var total = modules.length;
|
||||
var installed = modules.filter(function(m) { return m.installed; }).length;
|
||||
var running = modules.filter(function(m) { return m.running; }).length;
|
||||
var stopped = installed - running;
|
||||
|
||||
return E('div', { 'class': 'secubox-page-header' }, [
|
||||
E('div', {}, [
|
||||
E('h2', {}, '📦 SecuBox Modules'),
|
||||
E('p', { 'class': 'secubox-page-subtitle' },
|
||||
'Manage and monitor all SecuBox modules')
|
||||
]),
|
||||
E('div', { 'class': 'secubox-modules-stats' }, [
|
||||
E('div', { 'class': 'secubox-stat-badge' }, [
|
||||
E('span', { 'class': 'secubox-stat-value' }, total),
|
||||
E('span', { 'class': 'secubox-stat-label' }, 'Total')
|
||||
]),
|
||||
E('div', { 'class': 'secubox-stat-badge secubox-stat-success' }, [
|
||||
E('span', { 'class': 'secubox-stat-value' }, running),
|
||||
E('span', { 'class': 'secubox-stat-label' }, 'Running')
|
||||
]),
|
||||
E('div', { 'class': 'secubox-stat-badge secubox-stat-warning' }, [
|
||||
E('span', { 'class': 'secubox-stat-value' }, stopped),
|
||||
E('span', { 'class': 'secubox-stat-label' }, 'Stopped')
|
||||
]),
|
||||
E('div', { 'class': 'secubox-stat-badge secubox-stat-muted' }, [
|
||||
E('span', { 'class': 'secubox-stat-value' }, total - installed),
|
||||
E('span', { 'class': 'secubox-stat-label' }, 'Available')
|
||||
])
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
renderFilterTabs: function() {
|
||||
var self = this;
|
||||
var tabs = [
|
||||
{ id: 'all', label: 'All Modules', icon: '📦' },
|
||||
{ id: 'security', label: 'Security', icon: '🛡️' },
|
||||
{ id: 'monitoring', label: 'Monitoring', icon: '📊' },
|
||||
{ id: 'network', label: 'Network', icon: '🌐' },
|
||||
{ id: 'system', label: 'System', icon: '⚙️' }
|
||||
];
|
||||
|
||||
return E('div', { 'class': 'secubox-filter-tabs' },
|
||||
tabs.map(function(tab) {
|
||||
return E('button', {
|
||||
'class': 'secubox-filter-tab' + (tab.id === 'all' ? ' active' : ''),
|
||||
'data-filter': tab.id,
|
||||
'click': function(ev) {
|
||||
document.querySelectorAll('.secubox-filter-tab').forEach(function(el) {
|
||||
el.classList.remove('active');
|
||||
});
|
||||
ev.target.classList.add('active');
|
||||
self.filterModules(tab.id);
|
||||
}
|
||||
}, tab.icon + ' ' + tab.label);
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
renderModuleCards: function(modules, filter) {
|
||||
var self = this;
|
||||
|
||||
var filtered = filter === 'all' ? modules :
|
||||
modules.filter(function(m) { return m.category === filter; });
|
||||
|
||||
if (filtered.length === 0) {
|
||||
return E('div', { 'class': 'secubox-empty-state' }, [
|
||||
E('div', { 'class': 'secubox-empty-icon' }, '📭'),
|
||||
E('div', { 'class': 'secubox-empty-title' }, 'No modules found'),
|
||||
E('div', { 'class': 'secubox-empty-text' }, 'Try selecting a different category')
|
||||
]);
|
||||
}
|
||||
|
||||
return filtered.map(function(module) {
|
||||
return self.renderModuleCard(module);
|
||||
});
|
||||
},
|
||||
|
||||
renderModuleCard: function(module) {
|
||||
var self = this;
|
||||
var isRunning = module.running;
|
||||
var isInstalled = module.installed;
|
||||
var statusClass = isRunning ? 'running' : (isInstalled ? 'stopped' : 'not-installed');
|
||||
|
||||
return E('div', {
|
||||
'class': 'secubox-module-card secubox-module-' + statusClass,
|
||||
'style': 'border-left: 4px solid ' + (module.color || '#64748b')
|
||||
}, [
|
||||
// Card Header
|
||||
E('div', { 'class': 'secubox-module-card-header' }, [
|
||||
E('div', { 'class': 'secubox-module-icon' }, module.icon || '📦'),
|
||||
E('div', { 'class': 'secubox-module-info' }, [
|
||||
E('h3', { 'class': 'secubox-module-name' }, module.name || module.id),
|
||||
E('div', { 'class': 'secubox-module-meta' }, [
|
||||
E('span', { 'class': 'secubox-module-category' },
|
||||
this.getCategoryIcon(module.category) + ' ' + (module.category || 'other')),
|
||||
E('span', { 'class': 'secubox-module-version' },
|
||||
'v' + (module.version || '0.0.9'))
|
||||
])
|
||||
]),
|
||||
E('div', {
|
||||
'class': 'secubox-status-indicator secubox-status-' + statusClass,
|
||||
'title': isRunning ? 'Running' : (isInstalled ? 'Stopped' : 'Not Installed')
|
||||
})
|
||||
]),
|
||||
|
||||
// Card Body
|
||||
E('div', { 'class': 'secubox-module-card-body' }, [
|
||||
E('p', { 'class': 'secubox-module-description' },
|
||||
module.description || 'No description available'),
|
||||
|
||||
E('div', { 'class': 'secubox-module-details' }, [
|
||||
E('div', { 'class': 'secubox-module-detail' }, [
|
||||
E('span', { 'class': 'secubox-detail-label' }, 'Package:'),
|
||||
E('code', { 'class': 'secubox-detail-value' }, module.package || 'N/A')
|
||||
]),
|
||||
E('div', { 'class': 'secubox-module-detail' }, [
|
||||
E('span', { 'class': 'secubox-detail-label' }, 'Status:'),
|
||||
E('span', {
|
||||
'class': 'secubox-detail-value secubox-status-text-' + statusClass
|
||||
}, isRunning ? '● Running' : (isInstalled ? '○ Stopped' : '- Not Installed'))
|
||||
])
|
||||
])
|
||||
]),
|
||||
|
||||
// Card Actions
|
||||
E('div', { 'class': 'secubox-module-card-actions' },
|
||||
this.renderModuleActions(module))
|
||||
]);
|
||||
},
|
||||
|
||||
renderModuleActions: function(module) {
|
||||
var self = this;
|
||||
var actions = [];
|
||||
|
||||
if (!module.installed) {
|
||||
actions.push(
|
||||
E('button', {
|
||||
'class': 'secubox-btn secubox-btn-secondary secubox-btn-sm',
|
||||
'disabled': true
|
||||
}, '📥 Install')
|
||||
);
|
||||
} else {
|
||||
// Start/Stop button
|
||||
if (module.running) {
|
||||
actions.push(
|
||||
E('button', {
|
||||
'class': 'secubox-btn secubox-btn-danger secubox-btn-sm',
|
||||
'click': function() {
|
||||
self.stopModule(module);
|
||||
}
|
||||
}, '⏹️ Stop')
|
||||
);
|
||||
} else {
|
||||
actions.push(
|
||||
E('button', {
|
||||
'class': 'secubox-btn secubox-btn-success secubox-btn-sm',
|
||||
'click': function() {
|
||||
self.startModule(module);
|
||||
}
|
||||
}, '▶️ Start')
|
||||
);
|
||||
}
|
||||
|
||||
// Restart button (only if running)
|
||||
if (module.running) {
|
||||
actions.push(
|
||||
E('button', {
|
||||
'class': 'secubox-btn secubox-btn-warning secubox-btn-sm',
|
||||
'click': function() {
|
||||
self.restartModule(module);
|
||||
}
|
||||
}, '🔄 Restart')
|
||||
);
|
||||
}
|
||||
|
||||
// Dashboard link
|
||||
var dashboardPath = this.getModuleDashboardPath(module.id);
|
||||
if (dashboardPath) {
|
||||
actions.push(
|
||||
E('a', {
|
||||
'href': L.url(dashboardPath),
|
||||
'class': 'secubox-btn secubox-btn-primary secubox-btn-sm'
|
||||
}, '📊 Dashboard')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return actions;
|
||||
},
|
||||
|
||||
getModuleDashboardPath: function(moduleId) {
|
||||
var paths = {
|
||||
'crowdsec': 'admin/secubox/security/crowdsec',
|
||||
'netdata': 'admin/secubox/monitoring/netdata',
|
||||
'netifyd': 'admin/secubox/security/netifyd',
|
||||
'wireguard': 'admin/secubox/network/wireguard',
|
||||
'network_modes': 'admin/secubox/network/modes',
|
||||
'client_guardian': 'admin/secubox/security/guardian',
|
||||
'system_hub': 'admin/system/system-hub/overview',
|
||||
'bandwidth_manager': 'admin/secubox/network/bandwidth',
|
||||
'auth_guardian': 'admin/secubox/security/auth',
|
||||
'media_flow': 'admin/secubox/network/media',
|
||||
'vhost_manager': 'admin/secubox/system/vhost',
|
||||
'traffic_shaper': 'admin/secubox/network/shaper',
|
||||
'cdn_cache': 'admin/secubox/network/cdn',
|
||||
'ksm_manager': 'admin/secubox/security/ksm'
|
||||
};
|
||||
return paths[moduleId] || null;
|
||||
},
|
||||
|
||||
getCategoryIcon: function(category) {
|
||||
var icons = {
|
||||
'security': '🛡️',
|
||||
'monitoring': '📊',
|
||||
'network': '🌐',
|
||||
'system': '⚙️',
|
||||
'other': '📦'
|
||||
};
|
||||
return icons[category] || icons['other'];
|
||||
},
|
||||
|
||||
startModule: function(module) {
|
||||
var self = this;
|
||||
ui.showModal(_('Starting Module'), [
|
||||
E('p', {}, _('Starting') + ' ' + module.name + '...')
|
||||
]);
|
||||
|
||||
API.startModule(module.id).then(function(result) {
|
||||
ui.hideModal();
|
||||
if (result && result.success !== false) {
|
||||
ui.addNotification(null, E('p', module.name + ' started successfully'), 'info');
|
||||
self.refreshData().then(function() {
|
||||
self.updateModulesGrid();
|
||||
});
|
||||
} else {
|
||||
ui.addNotification(null, E('p', 'Failed to start ' + module.name), 'error');
|
||||
}
|
||||
}).catch(function(err) {
|
||||
ui.hideModal();
|
||||
ui.addNotification(null, E('p', 'Error: ' + err.message), 'error');
|
||||
});
|
||||
},
|
||||
|
||||
stopModule: function(module) {
|
||||
var self = this;
|
||||
ui.showModal(_('Stopping Module'), [
|
||||
E('p', {}, _('Stopping') + ' ' + module.name + '...')
|
||||
]);
|
||||
|
||||
API.stopModule(module.id).then(function(result) {
|
||||
ui.hideModal();
|
||||
if (result && result.success !== false) {
|
||||
ui.addNotification(null, E('p', module.name + ' stopped successfully'), 'info');
|
||||
self.refreshData().then(function() {
|
||||
self.updateModulesGrid();
|
||||
});
|
||||
} else {
|
||||
ui.addNotification(null, E('p', 'Failed to stop ' + module.name), 'error');
|
||||
}
|
||||
}).catch(function(err) {
|
||||
ui.hideModal();
|
||||
ui.addNotification(null, E('p', 'Error: ' + err.message), 'error');
|
||||
});
|
||||
},
|
||||
|
||||
restartModule: function(module) {
|
||||
var self = this;
|
||||
ui.showModal(_('Restarting Module'), [
|
||||
E('p', {}, _('Restarting') + ' ' + module.name + '...')
|
||||
]);
|
||||
|
||||
API.restartModule(module.id).then(function(result) {
|
||||
ui.hideModal();
|
||||
if (result && result.success !== false) {
|
||||
ui.addNotification(null, E('p', module.name + ' restarted successfully'), 'info');
|
||||
self.refreshData().then(function() {
|
||||
self.updateModulesGrid();
|
||||
});
|
||||
} else {
|
||||
ui.addNotification(null, E('p', 'Failed to restart ' + module.name), 'error');
|
||||
}
|
||||
}).catch(function(err) {
|
||||
ui.hideModal();
|
||||
ui.addNotification(null, E('p', 'Error: ' + err.message), 'error');
|
||||
});
|
||||
},
|
||||
|
||||
filterModules: function(category) {
|
||||
var grid = document.getElementById('modules-grid');
|
||||
if (grid) {
|
||||
dom.content(grid, this.renderModuleCards(this.modulesData, category));
|
||||
}
|
||||
},
|
||||
|
||||
updateModulesGrid: function() {
|
||||
var activeTab = document.querySelector('.secubox-filter-tab.active');
|
||||
var filter = activeTab ? activeTab.getAttribute('data-filter') : 'all';
|
||||
this.filterModules(filter);
|
||||
|
||||
// Update header stats
|
||||
var header = document.querySelector('.secubox-modules-stats');
|
||||
if (header && header.parentNode) {
|
||||
var newHeader = this.renderHeader(this.modulesData);
|
||||
header.parentNode.replaceChild(newHeader.querySelector('.secubox-modules-stats'), header);
|
||||
}
|
||||
},
|
||||
|
||||
handleSaveApply: null,
|
||||
handleSave: null,
|
||||
handleReset: null
|
||||
});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
config secubox 'main'
|
||||
option enabled '1'
|
||||
option version '0.0.1-beta'
|
||||
option version '0.1.1'
|
||||
option auto_discovery '1'
|
||||
option notifications '1'
|
||||
option theme 'dark'
|
||||
@ -12,9 +12,10 @@ config module 'crowdsec'
|
||||
option name 'CrowdSec Dashboard'
|
||||
option description 'Collaborative threat intelligence'
|
||||
option category 'security'
|
||||
option icon 'shield'
|
||||
option icon '🛡️'
|
||||
option color '#22c55e'
|
||||
option package 'luci-app-crowdsec-dashboard'
|
||||
option version '0.0.9'
|
||||
option config 'crowdsec'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -23,9 +24,10 @@ config module 'netdata'
|
||||
option name 'Netdata Dashboard'
|
||||
option description 'Real-time system monitoring'
|
||||
option category 'monitoring'
|
||||
option icon 'chart'
|
||||
option icon '📊'
|
||||
option color '#00ab44'
|
||||
option package 'luci-app-netdata-dashboard'
|
||||
option version '0.0.9'
|
||||
option config 'netdata'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -34,9 +36,10 @@ config module 'netifyd'
|
||||
option name 'Netifyd Dashboard'
|
||||
option description 'Deep packet inspection'
|
||||
option category 'security'
|
||||
option icon 'search'
|
||||
option icon '🔍'
|
||||
option color '#8b5cf6'
|
||||
option package 'luci-app-netifyd-dashboard'
|
||||
option version '0.0.9'
|
||||
option config 'netifyd'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -45,9 +48,10 @@ config module 'wireguard'
|
||||
option name 'WireGuard Dashboard'
|
||||
option description 'Modern VPN with QR codes'
|
||||
option category 'network'
|
||||
option icon 'lock'
|
||||
option icon '🔒'
|
||||
option color '#06b6d4'
|
||||
option package 'luci-app-wireguard-dashboard'
|
||||
option version '0.0.9'
|
||||
option config 'wireguard'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -56,9 +60,10 @@ config module 'network_modes'
|
||||
option name 'Network Modes'
|
||||
option description 'Network topology configuration'
|
||||
option category 'network'
|
||||
option icon 'git-branch'
|
||||
option icon '🌐'
|
||||
option color '#f97316'
|
||||
option package 'luci-app-network-modes'
|
||||
option version '0.0.9'
|
||||
option config 'network_modes'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -67,9 +72,10 @@ config module 'client_guardian'
|
||||
option name 'Client Guardian'
|
||||
option description 'NAC and captive portal'
|
||||
option category 'security'
|
||||
option icon 'eye'
|
||||
option icon '👁️'
|
||||
option color '#ef4444'
|
||||
option package 'luci-app-client-guardian'
|
||||
option version '0.0.9'
|
||||
option config 'client_guardian'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -78,9 +84,10 @@ config module 'system_hub'
|
||||
option name 'System Hub'
|
||||
option description 'Unified control center'
|
||||
option category 'system'
|
||||
option icon 'sliders'
|
||||
option icon '⚙️'
|
||||
option color '#6366f1'
|
||||
option package 'luci-app-system-hub'
|
||||
option version '0.0.9'
|
||||
option config 'system_hub'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -89,9 +96,10 @@ config module 'cdn_cache'
|
||||
option name 'CDN Cache'
|
||||
option description 'Local caching proxy'
|
||||
option category 'network'
|
||||
option icon 'package'
|
||||
option icon '📦'
|
||||
option color '#06b6d4'
|
||||
option package 'luci-app-cdn-cache'
|
||||
option version '0.0.9'
|
||||
option config 'cdn-cache'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -100,9 +108,10 @@ config module 'bandwidth_manager'
|
||||
option name 'Bandwidth Manager'
|
||||
option description 'QoS and bandwidth quotas'
|
||||
option category 'network'
|
||||
option icon 'activity'
|
||||
option icon '📡'
|
||||
option color '#3b82f6'
|
||||
option package 'luci-app-bandwidth-manager'
|
||||
option version '0.0.9'
|
||||
option config 'bandwidth_manager'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -111,9 +120,10 @@ config module 'auth_guardian'
|
||||
option name 'Auth Guardian'
|
||||
option description 'Advanced authentication system'
|
||||
option category 'security'
|
||||
option icon 'key'
|
||||
option icon '🔑'
|
||||
option color '#f59e0b'
|
||||
option package 'luci-app-auth-guardian'
|
||||
option version '0.0.9'
|
||||
option config 'auth_guardian'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -122,9 +132,10 @@ config module 'media_flow'
|
||||
option name 'Media Flow'
|
||||
option description 'Media traffic detection and optimization'
|
||||
option category 'network'
|
||||
option icon 'play-circle'
|
||||
option icon '▶️'
|
||||
option color '#ec4899'
|
||||
option package 'luci-app-media-flow'
|
||||
option version '0.0.9'
|
||||
option config 'media_flow'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -133,9 +144,10 @@ config module 'vhost_manager'
|
||||
option name 'Virtual Host Manager'
|
||||
option description 'Virtual host configuration'
|
||||
option category 'system'
|
||||
option icon 'server'
|
||||
option icon '🖥️'
|
||||
option color '#8b5cf6'
|
||||
option package 'luci-app-vhost-manager'
|
||||
option version '0.0.9'
|
||||
option config 'vhost_manager'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -144,9 +156,10 @@ config module 'traffic_shaper'
|
||||
option name 'Traffic Shaper'
|
||||
option description 'Advanced traffic shaping'
|
||||
option category 'network'
|
||||
option icon 'trending-up'
|
||||
option icon '📈'
|
||||
option color '#10b981'
|
||||
option package 'luci-app-traffic-shaper'
|
||||
option version '0.0.9'
|
||||
option config 'traffic_shaper'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
@ -155,9 +168,10 @@ config module 'ksm_manager'
|
||||
option name 'KSM Manager'
|
||||
option description 'Key Storage & HSM management'
|
||||
option category 'security'
|
||||
option icon 'key'
|
||||
option icon '🔐'
|
||||
option color '#ef4444'
|
||||
option package 'luci-app-ksm-manager'
|
||||
option version '0.0.9'
|
||||
option config 'ksm_manager'
|
||||
option installed '0'
|
||||
option enabled '0'
|
||||
|
||||
@ -135,7 +135,7 @@ get_modules() {
|
||||
local module_sections=$(uci -q show secubox | grep "=module$" | cut -d. -f2 | cut -d= -f1)
|
||||
|
||||
for module in $module_sections; do
|
||||
local name desc category icon color package config
|
||||
local name desc category icon color package config version
|
||||
|
||||
config_get name "$module" name "$module"
|
||||
config_get desc "$module" description ""
|
||||
@ -144,6 +144,7 @@ get_modules() {
|
||||
config_get color "$module" color "#64748b"
|
||||
config_get package "$module" package ""
|
||||
config_get config "$module" config ""
|
||||
config_get version "$module" version "0.0.9"
|
||||
|
||||
local is_installed=$(check_module_installed "$module")
|
||||
local is_running=$(check_module_running "$module")
|
||||
@ -157,6 +158,7 @@ get_modules() {
|
||||
json_add_string "color" "$color"
|
||||
json_add_string "package" "$package"
|
||||
json_add_string "config" "$config"
|
||||
json_add_string "version" "$version"
|
||||
json_add_boolean "installed" "$is_installed"
|
||||
json_add_boolean "running" "$is_running"
|
||||
json_close_object
|
||||
@ -183,7 +185,7 @@ get_modules_by_category() {
|
||||
config_get mod_category "$module" category "other"
|
||||
|
||||
if [ "$mod_category" = "$category" ]; then
|
||||
local name desc icon color package config
|
||||
local name desc icon color package config version
|
||||
|
||||
config_get name "$module" name "$module"
|
||||
config_get desc "$module" description ""
|
||||
@ -191,6 +193,7 @@ get_modules_by_category() {
|
||||
config_get color "$module" color "#64748b"
|
||||
config_get package "$module" package ""
|
||||
config_get config "$module" config ""
|
||||
config_get version "$module" version "0.0.9"
|
||||
|
||||
local is_installed=$(check_module_installed "$module")
|
||||
local is_running=$(check_module_running "$module")
|
||||
@ -201,6 +204,7 @@ get_modules_by_category() {
|
||||
json_add_string "description" "$desc"
|
||||
json_add_string "icon" "$icon"
|
||||
json_add_string "color" "$color"
|
||||
json_add_string "version" "$version"
|
||||
json_add_boolean "installed" "$is_installed"
|
||||
json_add_boolean "running" "$is_running"
|
||||
json_close_object
|
||||
@ -214,11 +218,11 @@ get_modules_by_category() {
|
||||
# Get single module info
|
||||
get_module_info() {
|
||||
local module="$1"
|
||||
|
||||
|
||||
config_load secubox
|
||||
|
||||
local name desc category icon color package config
|
||||
|
||||
|
||||
local name desc category icon color package config version
|
||||
|
||||
config_get name "$module" name "$module"
|
||||
config_get desc "$module" description ""
|
||||
config_get category "$module" category "other"
|
||||
@ -226,10 +230,11 @@ get_module_info() {
|
||||
config_get color "$module" color "#64748b"
|
||||
config_get package "$module" package ""
|
||||
config_get config "$module" config ""
|
||||
|
||||
config_get version "$module" version "0.0.9"
|
||||
|
||||
local is_installed=$(check_module_installed "$module")
|
||||
local is_running=$(check_module_running "$module")
|
||||
|
||||
|
||||
json_init
|
||||
json_add_string "id" "$module"
|
||||
json_add_string "name" "$name"
|
||||
@ -239,6 +244,7 @@ get_module_info() {
|
||||
json_add_string "color" "$color"
|
||||
json_add_string "package" "$package"
|
||||
json_add_string "config" "$config"
|
||||
json_add_string "version" "$version"
|
||||
json_add_boolean "installed" "$is_installed"
|
||||
json_add_boolean "running" "$is_running"
|
||||
json_dump
|
||||
|
||||
Loading…
Reference in New Issue
Block a user