Major structural reorganization and feature additions: ## Folder Reorganization - Move 17 luci-app-* packages to package/secubox/ (except luci-app-secubox core hub) - Update all tooling to support new structure: - secubox-tools/quick-deploy.sh: search both locations - secubox-tools/validate-modules.sh: validate both directories - secubox-tools/fix-permissions.sh: fix permissions in both locations - .github/workflows/test-validate.yml: build from both paths - Update README.md links to new package/secubox/ paths ## AppStore Migration (Complete) - Add catalog entries for all remaining luci-app packages: - network-tweaks.json: Network optimization tools - secubox-bonus.json: Documentation & demos hub - Total: 24 apps in AppStore catalog (22 existing + 2 new) - New category: 'documentation' for docs/demos/tutorials ## VHost Manager v2.0 Enhancements - Add profile activation system for Internal Services and Redirects - Implement createVHost() API wrapper for template-based deployment - Fix Virtual Hosts view rendering with proper LuCI patterns - Fix RPCD backend shell script errors (remove invalid local declarations) - Extend backend validation for nginx return directives (redirect support) - Add section_id parameter for named VHost profiles - Add Remove button to Redirects page for feature parity - Update README to v2.0 with comprehensive feature documentation ## Network Tweaks Dashboard - Close button added to component details modal Files changed: 340+ (336 renames with preserved git history) Packages affected: 19 luci-app, 2 secubox-app, 1 theme, 4 tools 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
133 lines
4.6 KiB
JavaScript
133 lines
4.6 KiB
JavaScript
'use strict';
|
|
'require view';
|
|
'require secubox-theme/theme as Theme';
|
|
'require dom';
|
|
'require ui';
|
|
'require wireguard-dashboard.api as api';
|
|
|
|
return view.extend({
|
|
title: _('WireGuard Configuration'),
|
|
|
|
load: function() {
|
|
return api.getConfig();
|
|
},
|
|
|
|
render: function(data) {
|
|
var interfaces = (data || {}).interfaces || [];
|
|
|
|
var view = E('div', { 'class': 'wireguard-dashboard' }, [
|
|
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
|
|
// Header
|
|
E('div', { 'class': 'wg-header' }, [
|
|
E('div', { 'class': 'wg-logo' }, [
|
|
E('div', { 'class': 'wg-logo-icon' }, '⚙️'),
|
|
E('div', { 'class': 'wg-logo-text' }, ['Config', E('span', {}, 'uration')])
|
|
])
|
|
]),
|
|
|
|
// Configuration cards
|
|
interfaces.length > 0 ?
|
|
interfaces.map(function(iface) {
|
|
return E('div', { 'class': 'wg-card', 'style': 'margin-bottom: 20px' }, [
|
|
E('div', { 'class': 'wg-card-header' }, [
|
|
E('div', { 'class': 'wg-card-title' }, [
|
|
E('span', { 'class': 'wg-card-title-icon' }, '🌐'),
|
|
'Interface: ' + iface.name
|
|
]),
|
|
E('div', { 'class': 'wg-card-badge' }, (iface.peers || []).length + ' peers')
|
|
]),
|
|
E('div', { 'class': 'wg-card-body' }, [
|
|
// Interface config block
|
|
E('div', { 'class': 'wg-config-block' }, [
|
|
E('div', {}, [
|
|
E('span', { 'class': 'wg-config-section' }, '[Interface]')
|
|
]),
|
|
E('div', {}, [
|
|
E('span', { 'class': 'wg-config-key' }, 'PublicKey'),
|
|
E('span', { 'class': 'wg-config-value' }, ' = ' + (iface.public_key || 'N/A'))
|
|
]),
|
|
E('div', {}, [
|
|
E('span', { 'class': 'wg-config-key' }, 'ListenPort'),
|
|
E('span', { 'class': 'wg-config-value' }, ' = ' + (iface.listen_port || 'N/A'))
|
|
]),
|
|
iface.uci_addresses ? E('div', {}, [
|
|
E('span', { 'class': 'wg-config-key' }, 'Address'),
|
|
E('span', { 'class': 'wg-config-value' }, ' = ' + iface.uci_addresses)
|
|
]) : ''
|
|
]),
|
|
|
|
// Peers config
|
|
(iface.peers || []).length > 0 ? E('div', { 'style': 'margin-top: 20px' },
|
|
(iface.peers || []).map(function(peer, idx) {
|
|
return E('div', { 'class': 'wg-config-block', 'style': idx > 0 ? 'margin-top: 12px' : '' }, [
|
|
E('div', {}, [
|
|
E('span', { 'class': 'wg-config-section' }, '[Peer]')
|
|
]),
|
|
E('div', {}, [
|
|
E('span', { 'class': 'wg-config-key' }, 'PublicKey'),
|
|
E('span', { 'class': 'wg-config-value' }, ' = ' + peer.public_key)
|
|
]),
|
|
peer.endpoint && peer.endpoint !== '(none)' ? E('div', {}, [
|
|
E('span', { 'class': 'wg-config-key' }, 'Endpoint'),
|
|
E('span', { 'class': 'wg-config-value' }, ' = ' + peer.endpoint)
|
|
]) : '',
|
|
E('div', {}, [
|
|
E('span', { 'class': 'wg-config-key' }, 'AllowedIPs'),
|
|
E('span', { 'class': 'wg-config-value' }, ' = ' + (peer.allowed_ips || '0.0.0.0/0'))
|
|
]),
|
|
peer.keepalive > 0 ? E('div', {}, [
|
|
E('span', { 'class': 'wg-config-key' }, 'PersistentKeepalive'),
|
|
E('span', { 'class': 'wg-config-value' }, ' = ' + peer.keepalive)
|
|
]) : ''
|
|
]);
|
|
})
|
|
) : ''
|
|
])
|
|
]);
|
|
}) :
|
|
E('div', { 'class': 'wg-card' }, [
|
|
E('div', { 'class': 'wg-card-body' }, [
|
|
E('div', { 'class': 'wg-empty' }, [
|
|
E('div', { 'class': 'wg-empty-icon' }, '⚙️'),
|
|
E('div', { 'class': 'wg-empty-text' }, 'No WireGuard interfaces configured'),
|
|
E('p', {}, 'Create a WireGuard interface in Network > Interfaces')
|
|
])
|
|
])
|
|
]),
|
|
|
|
// Tunnel visualization
|
|
interfaces.length > 0 ? E('div', { 'class': 'wg-card' }, [
|
|
E('div', { 'class': 'wg-card-header' }, [
|
|
E('div', { 'class': 'wg-card-title' }, [
|
|
E('span', { 'class': 'wg-card-title-icon' }, '🔗'),
|
|
'Tunnel Visualization'
|
|
])
|
|
]),
|
|
E('div', { 'class': 'wg-card-body' }, [
|
|
E('div', { 'class': 'wg-tunnel-viz' }, [
|
|
E('div', { 'class': 'wg-tunnel-node' }, [
|
|
E('div', { 'class': 'wg-tunnel-node-icon' }, '🏠'),
|
|
E('div', { 'class': 'wg-tunnel-node-label' }, 'This Router')
|
|
]),
|
|
E('div', { 'class': 'wg-tunnel-line wg-tunnel-active' }),
|
|
E('div', { 'class': 'wg-tunnel-node' }, [
|
|
E('div', { 'class': 'wg-tunnel-node-icon' }, '🌐'),
|
|
E('div', { 'class': 'wg-tunnel-node-label' }, 'Remote Peers')
|
|
])
|
|
])
|
|
])
|
|
]) : ''
|
|
]);
|
|
|
|
// Include CSS
|
|
var cssLink = E('link', { 'rel': 'stylesheet', 'href': L.resource('wireguard-dashboard/dashboard.css') });
|
|
document.head.appendChild(cssLink);
|
|
|
|
return view;
|
|
},
|
|
|
|
handleSaveApply: null,
|
|
handleSave: null,
|
|
handleReset: null
|
|
});
|