feat: Add help system integration and fix menu structure
- Created help system (help.js, help.css) for all modules - Integrated help button in network-modes module - Fixed menu structure: removed empty Network Management category - Fixed all dashboard and modules page links - Added website deployment script - Created comprehensive documentation New Files: - DOCS/HELP_INTEGRATION_PLAN.md - DOCS/WEBSITE_DEPLOYMENT_GUIDE.md - EXAMPLES/help-button-integration.js - luci-app-secubox/htdocs/luci-static/resources/secubox/help.js - luci-app-secubox/htdocs/luci-static/resources/secubox/help.css - secubox-tools/deploy-website.sh Modified: - luci-app-network-modes: Added help button integration - luci-app-secubox: Fixed menu paths and module links 🤖 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
41947c5ae0
commit
6314884f00
@ -1,164 +1,59 @@
|
||||
# SecuBox Project Context for Claude AI
|
||||
# SecuBox Context
|
||||
|
||||
## 🎯 Project Identity
|
||||
## What SecuBox OpenWrt Suite Is
|
||||
SecuBox is a suite of LuCI applications that ship advanced security, monitoring, and automation dashboards for OpenWrt routers. Each `luci-app-*` package combines LuCI JavaScript views, RPCD backends, UCI integration, ACL policies, and shared CSS built on the SecuBox design system (dark-first palette, Inter + JetBrains Mono). GitHub Actions builds the packages for every supported architecture (`x86`, `ARM`, `MIPS`) and the repo also carries tooling for validation, repair, deployment, and firmware image creation.
|
||||
|
||||
**Name**: SecuBox
|
||||
**Type**: Modular security suite for OpenWrt routers
|
||||
**Version**: 1.0.0
|
||||
**Author**: CyberMind.fr (Gandalf)
|
||||
**License**: Apache-2.0
|
||||
## Repository Layout
|
||||
- `.claude/` – authoritative assistant guidance, prompts, and settings
|
||||
- `.github/workflows/` – CI definitions (package build matrix, validation, firmware images)
|
||||
- `luci-app-*/` – one directory per LuCI module (Makefile, README, `htdocs/`, `root/`)
|
||||
- `secubox-tools/` – validation/build/deploy helpers (`local-build.sh`, `validate-modules.sh`, etc.)
|
||||
- `templates/` – scaffolding for new LuCI packages
|
||||
- Root docs: `README.md`, `QUICK-START.md`, `DEVELOPMENT-GUIDELINES.md`, `CLAUDE.md`, `DOCUMENTATION-INDEX.md`, `CODE-TEMPLATES.md`, `FEATURE-REGENERATION-PROMPTS.md`, `MODULE_STATUS.md`, `PERMISSIONS-GUIDE.md`, `VALIDATION-GUIDE.md`, etc.
|
||||
- Deploy scripts: `deploy-module-template.sh`, `deploy-*.sh` (system hub, secubox, beta releases, etc.)
|
||||
- Test fixtures: `test-direct.js`, `test-modules-simple.js`
|
||||
|
||||
## 🏗️ Architecture Overview
|
||||
## Module Map (Purpose & Entry Points)
|
||||
Each module follows the same structure: `Makefile`, module-specific README, JavaScript views under `htdocs/luci-static/resources/view/<module>/`, API helpers under `htdocs/luci-static/resources/<module>/api.js`, CSS in the same folder, RPCD backend in `root/usr/libexec/rpcd/luci.<module>`, menu JSON under `root/usr/share/luci/menu.d/`, and ACL JSON under `root/usr/share/rpcd/acl.d/`.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ LuCI Web Interface │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ View.js │ │ View.js │ │ View.js │ │ View.js │ ... │
|
||||
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
|
||||
│ │ │ │ │ │
|
||||
│ └───────────┴─────┬─────┴───────────┘ │
|
||||
│ │ JSON-RPC │
|
||||
├─────────────────────────┼───────────────────────────────────┤
|
||||
│ RPCD Daemon │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ Script │ │ Script │ │ Script │ │ Script │ ... │
|
||||
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
|
||||
│ │ │ │ │ │
|
||||
├───────┼───────────┼───────────┼───────────┼─────────────────┤
|
||||
│ │ UCI │ Shell │ System │ │
|
||||
│ │ Config │ Commands │ Services │ │
|
||||
└───────┴───────────┴───────────┴───────────┴─────────────────┘
|
||||
```
|
||||
| Module | Purpose | Primary Views (JS) |
|
||||
|--------|---------|--------------------|
|
||||
| `luci-app-secubox` | Central SecuBox hub (module launcher, dashboard, dev status) | `secubox/dashboard.js`, `modules.js`, `modules-minimal.js`, `dev-status.js`, `alerts.js`, `monitoring.js`, `settings.js`
|
||||
| `luci-app-system-hub` | System control center (health, services, diagnostics, remote) | `system-hub/overview.js`, `health.js`, `services.js`, `components.js`, `logs.js`, `backup.js`, `diagnostics.js`, `remote.js`, `settings.js`, `dev-status.js`
|
||||
| `luci-app-crowdsec-dashboard` | CrowdSec decision, alerts, bouncer management | `crowdsec-dashboard/overview.js`, `alerts.js`, `decisions.js`, `bouncers.js`, `metrics.js`, `settings.js`
|
||||
| `luci-app-netdata-dashboard` | Netdata monitoring integration | `netdata-dashboard/dashboard.js`, `system.js`, `network.js`, `processes.js`, `realtime.js`, `settings.js`
|
||||
| `luci-app-netifyd-dashboard` | DPI / application intelligence | `netifyd-dashboard/overview.js`, `applications.js`, `devices.js`, `flows.js`, `risks.js`, `talkers.js`, `settings.js`
|
||||
| `luci-app-network-modes` | Switch router/AP/bridge/sniffer modes | `network-modes/overview.js`, `wizard.js`, `sniffer.js`, `accesspoint.js`, `relay.js`, `router.js`, `settings.js`
|
||||
| `luci-app-wireguard-dashboard` | WireGuard VPN monitoring/config | `wireguard-dashboard/overview.js`, `peers.js`, `traffic.js`, `config.js`, `settings.js`, `qrcodes.js`
|
||||
| `luci-app-client-guardian` | NAC + captive portal + parental controls | `client-guardian/overview.js`, `clients.js`, `zones.js`, `portal.js`, `captive.js`, `alerts.js`, `parental.js`, `settings.js`, `logs.js`
|
||||
| `luci-app-auth-guardian` | Authentication/voucher/OAuth portal | `auth-guardian/overview.js`, `sessions.js`, `vouchers.js`, `oauth.js`, `splash.js`, `bypass.js`
|
||||
| `luci-app-bandwidth-manager` | QoS, quotas, priority classes | `bandwidth-manager/overview.js`, `classes.js`, `rules.js`, `schedules.js`, `media.js`, `clients.js`, `usage.js`, `quotas.js`, `settings.js`
|
||||
| `luci-app-media-flow` | Streaming/media traffic analytics | `media-flow/dashboard.js`, `services.js`, `clients.js`, `history.js`, `alerts.js`
|
||||
| `luci-app-cdn-cache` | Local CDN cache policies & stats | `cdn-cache/overview.js`, `policies.js`, `cache.js`, `statistics.js`, `maintenance.js`, `settings.js`
|
||||
| `luci-app-vhost-manager` | Virtual hosts & SSL orchestration | `vhost-manager/overview.js`, `vhosts.js`, `internal.js`, `redirects.js`, `ssl.js`, `certificates.js`, `logs.js`
|
||||
| `luci-app-traffic-shaper` | Advanced traffic shaping presets | `traffic-shaper/overview.js`, `classes.js`, `rules.js`, `stats.js`, `presets.js`
|
||||
| `luci-app-ksm-manager` | Secure key/certificate management | `ksm-manager/overview.js`, `keys.js`, `secrets.js`, `certificates.js`, `ssh.js`, `hsm.js`, `audit.js`, `settings.js`
|
||||
|
||||
## 📁 Module Structure Template
|
||||
(Modules not listed explicitly above share the same structure; inspect each `luci-app-*/htdocs/luci-static/resources/view/<module>/` directory for the definitive entrypoints.)
|
||||
|
||||
```
|
||||
luci-app-{module-name}/
|
||||
├── Makefile # OpenWrt package definition
|
||||
├── README.md # Module documentation
|
||||
├── htdocs/
|
||||
│ └── luci-static/
|
||||
│ └── resources/
|
||||
│ └── view/
|
||||
│ └── {module_name}/ # Underscore version
|
||||
│ ├── main.js # Main view
|
||||
│ └── {subview}.js # Optional subviews
|
||||
└── root/
|
||||
├── etc/
|
||||
│ ├── config/
|
||||
│ │ └── {module_name} # UCI configuration
|
||||
│ ├── init.d/
|
||||
│ │ └── {module_name} # Service init script (optional)
|
||||
│ └── uci-defaults/
|
||||
│ └── 99-{module_name} # First-run setup
|
||||
└── usr/
|
||||
├── libexec/
|
||||
│ └── rpcd/
|
||||
│ └── {module-name} # Hyphen version - RPCD backend
|
||||
└── share/
|
||||
├── luci/
|
||||
│ └── menu.d/
|
||||
│ └── luci-app-{module-name}.json
|
||||
└── rpcd/
|
||||
└── acl.d/
|
||||
└── luci-app-{module-name}.json
|
||||
```
|
||||
## Stack & Integration Points
|
||||
- **Frontend**: LuCI JavaScript views (`view.extend`) + SecuBox design system CSS. Every view imports the per-module `api.js` module for ubus calls and includes shared styles like `system-hub/common.css`.
|
||||
- **Backend**: RPCD shell scripts under `root/usr/libexec/rpcd/luci.<module>` expose ubus methods (`status`, `get_*`, `set_*`, etc.). Modules often also ship helper scripts under `/usr/libexec/secubox/` and UCI defaults under `root/etc/uci-defaults/`.
|
||||
- **UBus / RPC**: JavaScript uses `rpc.declare` with `object: 'luci.<module>'`. RPCD `list` and `call` cases must mirror these names.
|
||||
- **Menu/ACL**: JSON files in `root/usr/share/luci/menu.d/` and `root/usr/share/rpcd/acl.d/` keep navigation and permissions consistent with the views and RPCD backend.
|
||||
- **Packaging**: OpenWrt LuCI package Makefiles include `luci.mk`, define `PKG_FILE_MODES` for executable scripts (typically RPCD 755), and mark packages as `LUCI_PKGARCH:=all` because they are script-only.
|
||||
|
||||
## 📋 Naming Conventions
|
||||
|
||||
| Context | Format | Example |
|
||||
|---------|--------|---------|
|
||||
| Package name | luci-app-{module-name} | luci-app-vhost-manager |
|
||||
| RPCD script | {module-name} | vhost-manager |
|
||||
| UCI config | {module_name} | vhost_manager |
|
||||
| View path | {module_name}/ | vhost_manager/ |
|
||||
| ubus object | luci.{module-name} | luci.vhost-manager |
|
||||
| Menu path | admin/services/{module_name} | admin/services/vhost_manager |
|
||||
|
||||
## 🔧 Code Standards
|
||||
|
||||
### Makefile Template
|
||||
|
||||
```makefile
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-{module-name}
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=1
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
|
||||
|
||||
LUCI_TITLE:=LuCI - {Module Title}
|
||||
LUCI_DESCRIPTION:={Description}
|
||||
LUCI_DEPENDS:=+luci-base +rpcd {+other-deps}
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
```
|
||||
|
||||
### RPCD Script Template
|
||||
|
||||
```sh
|
||||
#!/bin/sh
|
||||
# RPCD backend for {module-name}
|
||||
|
||||
. /lib/functions.sh
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
json_init
|
||||
|
||||
case "$1" in
|
||||
list)
|
||||
# MUST list all available methods
|
||||
json_add_object "status"
|
||||
json_close_object
|
||||
json_add_object "get_config"
|
||||
json_close_object
|
||||
json_add_object "set_config"
|
||||
json_add_string "config" "object"
|
||||
json_close_object
|
||||
# Add more methods here
|
||||
json_dump
|
||||
;;
|
||||
|
||||
call)
|
||||
case "$2" in
|
||||
status)
|
||||
# MUST implement status method
|
||||
json_add_string "module" "{module-name}"
|
||||
json_add_string "version" "2.0.0"
|
||||
json_add_boolean "enabled" 1
|
||||
json_add_string "status" "running"
|
||||
json_dump
|
||||
;;
|
||||
|
||||
get_config)
|
||||
# Read from UCI
|
||||
json_add_object "config"
|
||||
# config_load "{module_name}"
|
||||
json_close_object
|
||||
json_dump
|
||||
;;
|
||||
|
||||
set_config)
|
||||
read -r input
|
||||
json_load "$input"
|
||||
# Apply to UCI
|
||||
json_init
|
||||
json_add_boolean "success" 1
|
||||
json_dump
|
||||
;;
|
||||
|
||||
*)
|
||||
json_add_int "error" -32601
|
||||
json_add_string "message" "Method not found"
|
||||
json_dump
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
```
|
||||
## Glossary
|
||||
- **LuCI** – OpenWrt web interface framework (Lua backend + JS frontend)
|
||||
- **RPCD** – Daemon providing ubus RPC endpoints; modules drop scripts in `/usr/libexec/rpcd/`
|
||||
- **ubus** – OpenWrt message bus used for remote procedure calls
|
||||
- **UCI** – Unified Configuration Interface (files in `/etc/config/`)
|
||||
- **ACL** – RPCD permission JSON files in `/usr/share/rpcd/acl.d/`
|
||||
- **PKG_FILE_MODES** – Makefile variable forcing specific permissions for installed files
|
||||
- **SecuBox Design System** – Shared CSS variables (`--sh-*`) and components defined in `system-hub/common.css`
|
||||
- **Validation suite** – `./secubox-tools/validate-modules.sh`, `validate-module-generation.sh`, `pre-push-validation.sh`
|
||||
- **Deploy script** – `deploy-module-template.sh` (backup, copy JS/CSS/RPCD/menu/ACL, fix perms, restart services)
|
||||
- **Fix permissions** – Toujours lancer `./secubox-tools/fix-permissions.sh --local` avant commit et `--remote <routeur>` après déploiement pour garantir `644` sur CSS/JS et `755` sur scripts exécutables
|
||||
|
||||
### ACL File Template
|
||||
|
||||
|
||||
@ -53,3 +53,4 @@ Each module follows the same structure: `Makefile`, module-specific README, Java
|
||||
- **SecuBox Design System** – Shared CSS variables (`--sh-*`) and components defined in `system-hub/common.css`
|
||||
- **Validation suite** – `./secubox-tools/validate-modules.sh`, `validate-module-generation.sh`, `pre-push-validation.sh`
|
||||
- **Deploy script** – `deploy-module-template.sh` (backup, copy JS/CSS/RPCD/menu/ACL, fix perms, restart services)
|
||||
- **Fix permissions** – Always run `./secubox-tools/fix-permissions.sh --local` before committing and `--remote <router>` after deploying to enforce `644` web assets / `755` executables
|
||||
|
||||
441
DOCS/HELP_INTEGRATION_PLAN.md
Normal file
441
DOCS/HELP_INTEGRATION_PLAN.md
Normal file
@ -0,0 +1,441 @@
|
||||
# SecuBox Website Help/Info Button Integration Plan
|
||||
|
||||
**Version:** 1.0
|
||||
**Date:** 2025-12-28
|
||||
**Status:** Planning Phase
|
||||
|
||||
## Overview
|
||||
|
||||
This document outlines the strategy for integrating the SecuBox marketing/documentation website with the OpenWrt LuCI modules, providing seamless access to help documentation via help/info buttons in each module.
|
||||
|
||||
## Current Architecture
|
||||
|
||||
### Website Location
|
||||
- **Remote URL:** `https://secubox.cybermood.eu/`
|
||||
- **Local Router Path:** `/www/luci-static/secubox/`
|
||||
- **Access URL:** `http://[router-ip]/luci-static/secubox/`
|
||||
|
||||
### Module Structure
|
||||
All SecuBox modules follow a consistent pattern:
|
||||
```
|
||||
luci-app-{module-name}/
|
||||
├── htdocs/luci-static/resources/
|
||||
│ ├── view/{module-name}/
|
||||
│ │ ├── overview.js (main dashboard)
|
||||
│ │ └── *.js (other views)
|
||||
│ └── {module-name}/
|
||||
│ ├── api.js
|
||||
│ ├── theme.js (optional)
|
||||
│ └── *.css
|
||||
```
|
||||
|
||||
### Key Modules
|
||||
1. **luci-app-secubox** - Central control hub
|
||||
2. **luci-app-system-hub** - System monitoring
|
||||
3. **luci-app-network-modes** - Network configuration
|
||||
4. **luci-app-client-guardian** - Client management
|
||||
5. **luci-app-bandwidth-manager** - Traffic shaping
|
||||
6. **luci-app-cdn-cache** - CDN caching
|
||||
7. **luci-app-traffic-shaper** - QoS management
|
||||
8. **luci-app-wireguard-dashboard** - VPN management
|
||||
9. **luci-app-crowdsec-dashboard** - Security monitoring
|
||||
10. **luci-app-netdata-dashboard** - Performance metrics
|
||||
|
||||
## Integration Strategy
|
||||
|
||||
### Phase 1: Shared Help Utilities (RECOMMENDED)
|
||||
|
||||
Create a centralized help button library that all modules can use.
|
||||
|
||||
#### Implementation Steps
|
||||
|
||||
1. **Create Shared Help Module**
|
||||
```javascript
|
||||
// Location: luci-app-secubox/htdocs/luci-static/resources/secubox/help.js
|
||||
|
||||
'use strict';
|
||||
'require baseclass';
|
||||
|
||||
return baseclass.extend({
|
||||
/**
|
||||
* Create a help button element
|
||||
* @param {string} moduleName - Module identifier (e.g., 'network-modes')
|
||||
* @param {string} position - Button position: 'header', 'footer', 'floating'
|
||||
* @param {object} options - Custom options
|
||||
*/
|
||||
createHelpButton: function(moduleName, position, options) {
|
||||
var opts = options || {};
|
||||
var helpUrl = this.getHelpUrl(moduleName);
|
||||
var buttonClass = 'sb-help-btn sb-help-' + position;
|
||||
|
||||
return E('a', {
|
||||
'class': buttonClass,
|
||||
'href': helpUrl,
|
||||
'target': opts.target || '_blank',
|
||||
'title': opts.title || _('View Help & Documentation')
|
||||
}, [
|
||||
E('span', { 'class': 'sb-help-icon' }, opts.icon || '❓'),
|
||||
opts.showLabel !== false ? E('span', { 'class': 'sb-help-label' }, opts.label || _('Help')) : null
|
||||
]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get help URL for a module
|
||||
* @param {string} moduleName - Module identifier
|
||||
*/
|
||||
getHelpUrl: function(moduleName) {
|
||||
var baseUrl = '/luci-static/secubox/';
|
||||
var moduleMap = {
|
||||
'secubox': 'index.html#modules',
|
||||
'system-hub': 'demo-secubox-hub.html',
|
||||
'network-modes': 'demo-network-modes.html',
|
||||
'client-guardian': 'demo-client-guardian.html',
|
||||
'bandwidth-manager': 'demo-bandwidth.html',
|
||||
'cdn-cache': 'demo-cdn-cache.html',
|
||||
'traffic-shaper': 'demo-traffic-shaper.html',
|
||||
'wireguard-dashboard': 'demo-wireguard.html',
|
||||
'crowdsec-dashboard': 'demo-crowdsec.html',
|
||||
'netdata-dashboard': 'demo-netdata.html',
|
||||
'netifyd-dashboard': 'demo-netifyd.html',
|
||||
'auth-guardian': 'demo-auth.html',
|
||||
'vhost-manager': 'demo-vhost.html',
|
||||
'ksm-manager': 'demo-ksm-manager.html',
|
||||
'media-flow': 'demo-media.html'
|
||||
};
|
||||
|
||||
return baseUrl + (moduleMap[moduleName] || 'index.html');
|
||||
},
|
||||
|
||||
/**
|
||||
* Open help in modal (for inline help)
|
||||
* @param {string} moduleName - Module identifier
|
||||
*/
|
||||
openHelpModal: function(moduleName) {
|
||||
var helpUrl = this.getHelpUrl(moduleName);
|
||||
var iframe = E('iframe', {
|
||||
'src': helpUrl,
|
||||
'style': 'width: 100%; height: 70vh; border: none; border-radius: 8px;'
|
||||
});
|
||||
|
||||
ui.showModal(_('Help & Documentation'), [
|
||||
E('div', { 'style': 'min-height: 70vh;' }, [iframe]),
|
||||
E('div', { 'class': 'right', 'style': 'margin-top: 1rem;' }, [
|
||||
E('button', {
|
||||
'class': 'btn',
|
||||
'click': ui.hideModal
|
||||
}, _('Close'))
|
||||
])
|
||||
]);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
2. **Create Common CSS Styles**
|
||||
```css
|
||||
/* Location: luci-app-secubox/htdocs/luci-static/resources/secubox/help.css */
|
||||
|
||||
/* Base Help Button Styles */
|
||||
.sb-help-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
border: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sb-help-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.sb-help-icon {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
/* Header Position */
|
||||
.sb-help-header {
|
||||
margin-left: auto;
|
||||
padding: 0.4rem 0.8rem;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
/* Footer Position */
|
||||
.sb-help-footer {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
/* Floating Button (bottom-right) */
|
||||
.sb-help-floating {
|
||||
position: fixed;
|
||||
bottom: 2rem;
|
||||
right: 2rem;
|
||||
z-index: 1000;
|
||||
border-radius: 50%;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
padding: 0;
|
||||
justify-content: center;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.sb-help-floating .sb-help-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sb-help-floating .sb-help-icon {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
/* Dark theme adjustments */
|
||||
[data-theme="dark"] .sb-help-btn {
|
||||
background: linear-gradient(135deg, #4c51bf 0%, #553c9a 100%);
|
||||
}
|
||||
```
|
||||
|
||||
3. **Update Each Module**
|
||||
|
||||
**Example: luci-app-network-modes/htdocs/luci-static/resources/view/network-modes/overview.js**
|
||||
```javascript
|
||||
'use strict';
|
||||
'require view';
|
||||
'require dom';
|
||||
'require ui';
|
||||
'require network-modes.api as api';
|
||||
'require secubox/help as Help'; // ADD THIS
|
||||
|
||||
return view.extend({
|
||||
title: _('Network Modes'),
|
||||
|
||||
load: function() {
|
||||
return api.getAllData();
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var self = this;
|
||||
// ... existing code ...
|
||||
|
||||
var view = E('div', { 'class': 'network-modes-dashboard' }, [
|
||||
// Load help CSS
|
||||
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox/help.css') }),
|
||||
|
||||
// Header with help button
|
||||
E('div', { 'class': 'nm-header' }, [
|
||||
E('div', { 'class': 'nm-logo' }, [
|
||||
E('div', { 'class': 'nm-logo-icon' }, '🌐'),
|
||||
E('div', { 'class': 'nm-logo-text' }, ['Network ', E('span', {}, 'Configuration')])
|
||||
]),
|
||||
E('div', { 'class': 'nm-mode-badge ' + currentMode }, [
|
||||
E('span', { 'class': 'nm-mode-dot' }),
|
||||
currentModeInfo ? currentModeInfo.name : currentMode
|
||||
]),
|
||||
// ADD HELP BUTTON
|
||||
Help.createHelpButton('network-modes', 'header', {
|
||||
icon: '📖',
|
||||
label: _('Help')
|
||||
})
|
||||
]),
|
||||
|
||||
// ... rest of the UI ...
|
||||
]);
|
||||
|
||||
return view;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Phase 2: Alternative Approaches
|
||||
|
||||
#### Approach A: Floating Help Button
|
||||
Add a global floating help button that appears on all SecuBox module pages.
|
||||
|
||||
**Pros:**
|
||||
- Non-intrusive
|
||||
- Consistent UX across all modules
|
||||
- Easy to implement globally
|
||||
|
||||
**Cons:**
|
||||
- May overlap with other floating elements
|
||||
- Less discoverable
|
||||
|
||||
#### Approach B: Header Integration
|
||||
Add help buttons to the header of each module dashboard.
|
||||
|
||||
**Pros:**
|
||||
- Highly visible
|
||||
- Natural placement
|
||||
- Follows common UI patterns
|
||||
|
||||
**Cons:**
|
||||
- Requires modifications to each module
|
||||
- May clutter header on small screens
|
||||
|
||||
#### Approach C: Quick Actions Integration
|
||||
Add help as a quick action in modules that have action panels (like SecuBox dashboard).
|
||||
|
||||
**Pros:**
|
||||
- Fits existing UI pattern
|
||||
- Grouped with other utilities
|
||||
- Consistent with current design
|
||||
|
||||
**Cons:**
|
||||
- Only works for modules with action panels
|
||||
- Less prominent
|
||||
|
||||
## Recommended Implementation Plan
|
||||
|
||||
### Step 1: Create Foundation (Week 1)
|
||||
1. Create `secubox/help.js` utility module
|
||||
2. Create `secubox/help.css` stylesheet
|
||||
3. Deploy to test router
|
||||
4. Verify accessibility
|
||||
|
||||
### Step 2: Integrate Core Modules (Week 2)
|
||||
Update these critical modules first:
|
||||
1. `luci-app-secubox` (main dashboard)
|
||||
2. `luci-app-system-hub`
|
||||
3. `luci-app-network-modes`
|
||||
|
||||
Test on production router.
|
||||
|
||||
### Step 3: Roll Out to All Modules (Week 3)
|
||||
Update remaining modules:
|
||||
1. `luci-app-client-guardian`
|
||||
2. `luci-app-bandwidth-manager`
|
||||
3. `luci-app-cdn-cache`
|
||||
4. `luci-app-traffic-shaper`
|
||||
5. `luci-app-wireguard-dashboard`
|
||||
6. `luci-app-crowdsec-dashboard`
|
||||
7. `luci-app-netdata-dashboard`
|
||||
8. Other modules
|
||||
|
||||
### Step 4: User Testing & Refinement (Week 4)
|
||||
1. Gather user feedback
|
||||
2. Adjust positioning/styling
|
||||
3. Add localization if needed
|
||||
4. Document for end users
|
||||
|
||||
## Module-to-Help Page Mapping
|
||||
|
||||
| Module | Help Page | Status |
|
||||
|--------|-----------|--------|
|
||||
| secubox | index.html#modules | Available |
|
||||
| system-hub | demo-secubox-hub.html | Available |
|
||||
| network-modes | demo-network-modes.html | Available |
|
||||
| client-guardian | demo-client-guardian.html | Available |
|
||||
| bandwidth-manager | demo-bandwidth.html | Available |
|
||||
| cdn-cache | demo-cdn-cache.html | Available |
|
||||
| traffic-shaper | demo-traffic-shaper.html | Available |
|
||||
| wireguard-dashboard | demo-wireguard.html | Available |
|
||||
| crowdsec-dashboard | demo-crowdsec.html | Available |
|
||||
| netdata-dashboard | demo-netdata.html | Available |
|
||||
| netifyd-dashboard | demo-netifyd.html | Available |
|
||||
| auth-guardian | demo-auth.html | Available |
|
||||
| vhost-manager | demo-vhost.html | Available |
|
||||
| ksm-manager | demo-ksm-manager.html | Available |
|
||||
| media-flow | demo-media.html | Available |
|
||||
|
||||
## Deployment Workflow
|
||||
|
||||
### Website Updates
|
||||
```bash
|
||||
# From secubox-openwrt directory
|
||||
./secubox-tools/deploy-website.sh root@192.168.8.191 ../secubox-website
|
||||
```
|
||||
|
||||
### Module Updates with Help Integration
|
||||
```bash
|
||||
# Build and deploy individual module
|
||||
./secubox-tools/deploy-network-modes.sh root@192.168.8.191
|
||||
|
||||
# Or build all modules
|
||||
./secubox-tools/local-build.sh build-all
|
||||
```
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] Help button appears in module header
|
||||
- [ ] Help button links to correct documentation page
|
||||
- [ ] Help page opens in new tab (or modal if configured)
|
||||
- [ ] Styling is consistent across all modules
|
||||
- [ ] Button is responsive on mobile devices
|
||||
- [ ] Dark/light theme support
|
||||
- [ ] Localization support (if applicable)
|
||||
- [ ] No JavaScript errors in console
|
||||
- [ ] Works on both local router and remote deployment
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Enhanced Features
|
||||
1. **Context-Sensitive Help**
|
||||
- Different help URLs based on current page/section
|
||||
- Deep linking to specific documentation sections
|
||||
|
||||
2. **Inline Help Tooltips**
|
||||
- Hover tooltips for specific UI elements
|
||||
- Quick tips without leaving page
|
||||
|
||||
3. **Help Search**
|
||||
- Search box in help modal
|
||||
- Full-text search across documentation
|
||||
|
||||
4. **Interactive Tutorials**
|
||||
- Step-by-step walkthroughs
|
||||
- Guided tours for new users
|
||||
|
||||
5. **Changelog Integration**
|
||||
- Show "What's New" on version updates
|
||||
- Link to release notes
|
||||
|
||||
## Technical Considerations
|
||||
|
||||
### Performance
|
||||
- Help resources are static files (no API calls)
|
||||
- Minimal JavaScript overhead (~2KB)
|
||||
- CSS loaded only when needed
|
||||
- No impact on module core functionality
|
||||
|
||||
### Compatibility
|
||||
- Works with LuCI 18.06+
|
||||
- Compatible with all modern browsers
|
||||
- Graceful degradation for older browsers
|
||||
|
||||
### Security
|
||||
- All help content served from same origin
|
||||
- No external dependencies
|
||||
- No XSS risks (static HTML/CSS/JS)
|
||||
|
||||
### Maintenance
|
||||
- Centralized help utility (single point of update)
|
||||
- Module changes are minimal (1-3 lines per module)
|
||||
- Website updates independent of module updates
|
||||
|
||||
## References
|
||||
|
||||
- **Deployment Script:** `secubox-tools/deploy-website.sh`
|
||||
- **Module Template:** `secubox-tools/deploy-module-template.sh`
|
||||
- **Website Repository:** `/home/reepost/CyberMindStudio/_files/secubox-website/`
|
||||
- **Current Deployment:** `http://192.168.8.191/luci-static/secubox/`
|
||||
|
||||
## Questions & Decisions Needed
|
||||
|
||||
1. **Button Position:** Header, Floating, or both?
|
||||
2. **Modal vs New Tab:** Should help open in modal or new tab?
|
||||
3. **Mobile UX:** How should help button behave on small screens?
|
||||
4. **Localization:** Support multiple languages for help content?
|
||||
5. **Analytics:** Track help usage (privacy-respecting)?
|
||||
|
||||
## Approval Status
|
||||
|
||||
- [ ] Technical approach approved
|
||||
- [ ] UI/UX design approved
|
||||
- [ ] Implementation timeline approved
|
||||
- [ ] Testing plan approved
|
||||
- [ ] Deployment strategy approved
|
||||
@ -150,8 +150,8 @@
|
||||
- **Use Cases**: Traffic analysis, bandwidth optimization, security monitoring
|
||||
|
||||
#### luci-app-network-modes
|
||||
- **Version**: 0.3.1-1
|
||||
- **Status**: ✅ In Heavily Development Stage
|
||||
- **Version**: 0.3.5-1
|
||||
- **Status**: ✅ Production Ready
|
||||
- **Description**: Dynamic network mode switching and configuration
|
||||
- **Views**: 7 (overview, wizard, router, relay, accesspoint, sniffer, settings)
|
||||
- **JavaScript Lines**: 2,104
|
||||
@ -171,8 +171,8 @@
|
||||
- DHCP server/client mode switching
|
||||
- Interface bridging automation
|
||||
- **Recent Updates**:
|
||||
- v0.3.1: Enhanced mode switching logic
|
||||
- Improved configuration persistence
|
||||
- v0.3.5: Auto-deploy proxies (Squid/TinyProxy/Privoxy), DoH, nginx vhosts, and Let’s Encrypt certificates
|
||||
- Auto-apply advanced WiFi (802.11r/k/v, band steering) and tcpdump packet capture per mode
|
||||
- **Integration**: network, firewall, DHCP, hostapd/wpa_supplicant
|
||||
|
||||
---
|
||||
|
||||
361
DOCS/WEBSITE_DEPLOYMENT_GUIDE.md
Normal file
361
DOCS/WEBSITE_DEPLOYMENT_GUIDE.md
Normal file
@ -0,0 +1,361 @@
|
||||
# SecuBox Website Deployment Guide
|
||||
|
||||
**Version:** 1.0
|
||||
**Date:** 2025-12-28
|
||||
|
||||
## Overview
|
||||
|
||||
This guide explains how to deploy the SecuBox marketing/documentation website to an OpenWrt router, making it accessible locally for help and documentation purposes.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- OpenWrt router with SSH access
|
||||
- SecuBox website files (from `secubox-website` repository)
|
||||
- Network connectivity to router
|
||||
- Sufficient storage space on router (approx. 1-2 MB)
|
||||
|
||||
## Deployment Script
|
||||
|
||||
### Location
|
||||
```
|
||||
secubox-openwrt/secubox-tools/deploy-website.sh
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
#### Basic Deployment
|
||||
```bash
|
||||
# Deploy to default router (192.168.1.1)
|
||||
./secubox-tools/deploy-website.sh
|
||||
|
||||
# Deploy to specific router
|
||||
./secubox-tools/deploy-website.sh root@192.168.8.191
|
||||
|
||||
# Deploy from specific website directory
|
||||
./secubox-tools/deploy-website.sh root@192.168.8.191 /path/to/secubox-website
|
||||
```
|
||||
|
||||
#### Full Example
|
||||
```bash
|
||||
cd /home/reepost/CyberMindStudio/_files/secubox-openwrt
|
||||
|
||||
# Deploy website to router at 192.168.8.191
|
||||
./secubox-tools/deploy-website.sh root@192.168.8.191 ../secubox-website
|
||||
```
|
||||
|
||||
### What the Script Does
|
||||
|
||||
1. **Prepares Files** - Creates compressed archive excluding:
|
||||
- `.git` directory
|
||||
- `.claude` directory
|
||||
- Markdown files (*.md)
|
||||
- README and LICENSE files
|
||||
|
||||
2. **Creates Backup** - Backs up existing website if present
|
||||
|
||||
3. **Deploys Files** - Uploads and extracts to `/www/luci-static/secubox/`
|
||||
|
||||
4. **Sets Permissions** - Ensures proper file permissions:
|
||||
- Directories: 755
|
||||
- HTML files: 644
|
||||
- JavaScript files: 644
|
||||
- CSS files: 644
|
||||
|
||||
5. **Cleanup** - Removes temporary files
|
||||
|
||||
## Website Structure on Router
|
||||
|
||||
### Directory Layout
|
||||
```
|
||||
/www/luci-static/secubox/
|
||||
├── index.html (main landing page)
|
||||
├── campaign.html
|
||||
├── demo-*.html (module demos)
|
||||
├── dev-status-widget.js
|
||||
├── i18n.js
|
||||
├── i18n/
|
||||
│ └── *.json (language files)
|
||||
└── blog/
|
||||
└── *.html (blog posts)
|
||||
```
|
||||
|
||||
### Access URLs
|
||||
|
||||
After deployment, the website is accessible at:
|
||||
|
||||
- **Local Router:** `http://[router-ip]/luci-static/secubox/`
|
||||
- **Example:** `http://192.168.8.191/luci-static/secubox/`
|
||||
|
||||
#### Individual Pages
|
||||
- Main: `http://192.168.8.191/luci-static/secubox/index.html`
|
||||
- System Hub: `http://192.168.8.191/luci-static/secubox/demo-secubox-hub.html`
|
||||
- Network Modes: `http://192.168.8.191/luci-static/secubox/demo-network-modes.html`
|
||||
- Client Guardian: `http://192.168.8.191/luci-static/secubox/demo-client-guardian.html`
|
||||
- etc.
|
||||
|
||||
## Deployment Workflow
|
||||
|
||||
### 1. Update Website Content
|
||||
|
||||
```bash
|
||||
# Navigate to website directory
|
||||
cd /home/reepost/CyberMindStudio/_files/secubox-website
|
||||
|
||||
# Edit files as needed
|
||||
# Test locally if possible
|
||||
```
|
||||
|
||||
### 2. Deploy to Router
|
||||
|
||||
```bash
|
||||
# Navigate to OpenWrt directory
|
||||
cd /home/reepost/CyberMindStudio/_files/secubox-openwrt
|
||||
|
||||
# Deploy
|
||||
./secubox-tools/deploy-website.sh root@192.168.8.191
|
||||
```
|
||||
|
||||
### 3. Verify Deployment
|
||||
|
||||
```bash
|
||||
# Check files on router
|
||||
ssh root@192.168.8.191 "ls -la /www/luci-static/secubox/"
|
||||
|
||||
# Test access via browser
|
||||
curl http://192.168.8.191/luci-static/secubox/index.html
|
||||
```
|
||||
|
||||
## Manual Deployment (Alternative)
|
||||
|
||||
If the script doesn't work, you can deploy manually:
|
||||
|
||||
```bash
|
||||
# 1. Create tarball
|
||||
cd /path/to/secubox-website
|
||||
tar czf /tmp/secubox-website.tar.gz \
|
||||
--exclude='.git' \
|
||||
--exclude='.claude' \
|
||||
--exclude='*.md' \
|
||||
.
|
||||
|
||||
# 2. Upload to router
|
||||
scp /tmp/secubox-website.tar.gz root@192.168.8.191:/tmp/
|
||||
|
||||
# 3. Extract on router
|
||||
ssh root@192.168.8.191 << 'EOF'
|
||||
mkdir -p /www/luci-static/secubox
|
||||
cd /www/luci-static/secubox
|
||||
tar xzf /tmp/secubox-website.tar.gz
|
||||
chmod 755 .
|
||||
find . -type d -exec chmod 755 {} \;
|
||||
find . -type f -name "*.html" -exec chmod 644 {} \;
|
||||
find . -type f -name "*.js" -exec chmod 644 {} \;
|
||||
rm /tmp/secubox-website.tar.gz
|
||||
EOF
|
||||
|
||||
# 4. Cleanup
|
||||
rm /tmp/secubox-website.tar.gz
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: "No route to host"
|
||||
**Solution:** Verify router IP address is correct
|
||||
```bash
|
||||
ping 192.168.8.191
|
||||
```
|
||||
|
||||
### Issue: "Permission denied"
|
||||
**Solution:** Ensure SSH access is configured
|
||||
```bash
|
||||
# Test SSH connection
|
||||
ssh root@192.168.8.191 "echo 'Connected'"
|
||||
```
|
||||
|
||||
### Issue: "Not enough space"
|
||||
**Solution:** Check available storage
|
||||
```bash
|
||||
ssh root@192.168.8.191 "df -h /www"
|
||||
|
||||
# If needed, clear cache
|
||||
ssh root@192.168.8.191 "rm -rf /tmp/luci-*"
|
||||
```
|
||||
|
||||
### Issue: "Files not accessible via HTTP"
|
||||
**Solution:** Check web server status
|
||||
```bash
|
||||
ssh root@192.168.8.191 "/etc/init.d/uhttpd status"
|
||||
ssh root@192.168.8.191 "/etc/init.d/uhttpd restart"
|
||||
```
|
||||
|
||||
### Issue: "404 Not Found"
|
||||
**Solution:** Verify files exist and check permissions
|
||||
```bash
|
||||
ssh root@192.168.8.191 "ls -la /www/luci-static/secubox/ | head -20"
|
||||
```
|
||||
|
||||
## Integration with Modules
|
||||
|
||||
Once deployed, modules can link to the help pages:
|
||||
|
||||
```javascript
|
||||
// Example: Link to help in a module
|
||||
var helpUrl = '/luci-static/secubox/demo-network-modes.html';
|
||||
var helpButton = E('a', {
|
||||
'href': helpUrl,
|
||||
'target': '_blank',
|
||||
'class': 'btn'
|
||||
}, 'Help');
|
||||
```
|
||||
|
||||
See `HELP_INTEGRATION_PLAN.md` for detailed integration guide.
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Updating Website
|
||||
|
||||
To update the website after making changes:
|
||||
|
||||
```bash
|
||||
# 1. Edit files in secubox-website/
|
||||
cd /home/reepost/CyberMindStudio/_files/secubox-website
|
||||
# ... make changes ...
|
||||
|
||||
# 2. Redeploy
|
||||
cd ../secubox-openwrt
|
||||
./secubox-tools/deploy-website.sh root@192.168.8.191
|
||||
```
|
||||
|
||||
### Rollback
|
||||
|
||||
If deployment fails, restore from backup:
|
||||
|
||||
```bash
|
||||
ssh root@192.168.8.191 << 'EOF'
|
||||
# Find latest backup
|
||||
BACKUP=$(ls -t /tmp/secubox-website-backup-* | head -1)
|
||||
if [ -n "$BACKUP" ]; then
|
||||
rm -rf /www/luci-static/secubox/*
|
||||
cp -a $BACKUP/* /www/luci-static/secubox/
|
||||
echo "Restored from $BACKUP"
|
||||
fi
|
||||
EOF
|
||||
```
|
||||
|
||||
### Remove Website
|
||||
|
||||
To completely remove the website:
|
||||
|
||||
```bash
|
||||
ssh root@192.168.8.191 "rm -rf /www/luci-static/secubox"
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Enable Compression (Optional)
|
||||
|
||||
Configure uhttpd to serve compressed content:
|
||||
|
||||
```bash
|
||||
ssh root@192.168.8.191 << 'EOF'
|
||||
# Add gzip compression to uhttpd config
|
||||
uci set uhttpd.main.compression='1'
|
||||
uci commit uhttpd
|
||||
/etc/init.d/uhttpd restart
|
||||
EOF
|
||||
```
|
||||
|
||||
### Cache Headers (Optional)
|
||||
|
||||
Add cache headers for static assets:
|
||||
|
||||
```bash
|
||||
ssh root@192.168.8.191 << 'EOF'
|
||||
# Create .htaccess-like configuration for caching
|
||||
# (requires additional uhttpd configuration)
|
||||
EOF
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Access Control
|
||||
|
||||
The website is publicly accessible on the router's LAN. To restrict access:
|
||||
|
||||
```bash
|
||||
# Option 1: Firewall rules (restrict to specific IPs)
|
||||
ssh root@192.168.8.191 << 'EOF'
|
||||
# Add firewall rules as needed
|
||||
EOF
|
||||
|
||||
# Option 2: HTTP authentication (requires uhttpd configuration)
|
||||
```
|
||||
|
||||
### Content Security
|
||||
|
||||
- Website contains only static HTML/CSS/JavaScript
|
||||
- No server-side execution
|
||||
- No database connections
|
||||
- No sensitive data exposure
|
||||
|
||||
## Automated Deployment
|
||||
|
||||
### Cron Job (Optional)
|
||||
|
||||
To auto-deploy on schedule:
|
||||
|
||||
```bash
|
||||
# Add to router crontab
|
||||
ssh root@192.168.8.191 "crontab -e"
|
||||
|
||||
# Add line (example: deploy daily at 3 AM):
|
||||
# 0 3 * * * cd /tmp && wget http://server/secubox-website.tar.gz && tar xzf secubox-website.tar.gz -C /www/luci-static/secubox/
|
||||
```
|
||||
|
||||
### Git Hook (Advanced)
|
||||
|
||||
Deploy automatically on git push:
|
||||
|
||||
```bash
|
||||
# In secubox-website/.git/hooks/post-commit
|
||||
#!/bin/bash
|
||||
cd /home/reepost/CyberMindStudio/_files/secubox-openwrt
|
||||
./secubox-tools/deploy-website.sh root@192.168.8.191
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Check Deployment Status
|
||||
|
||||
```bash
|
||||
# Verify files
|
||||
ssh root@192.168.8.191 "find /www/luci-static/secubox -type f | wc -l"
|
||||
|
||||
# Check disk usage
|
||||
ssh root@192.168.8.191 "du -sh /www/luci-static/secubox"
|
||||
|
||||
# View access logs (if logging enabled)
|
||||
ssh root@192.168.8.191 "logread | grep uhttpd"
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- **Help Integration:** `HELP_INTEGRATION_PLAN.md`
|
||||
- **Module Development:** `LUCI_DEVELOPMENT_REFERENCE.md`
|
||||
- **Deployment Scripts:** `secubox-tools/deploy-*.sh`
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
1. Check troubleshooting section above
|
||||
2. Review router logs: `ssh root@router "logread"`
|
||||
3. Test network connectivity
|
||||
4. Verify file permissions
|
||||
|
||||
## Changelog
|
||||
|
||||
### v1.0 (2025-12-28)
|
||||
- Initial deployment script
|
||||
- Documentation created
|
||||
- Tested on router 192.168.8.191
|
||||
- Supports automatic website directory detection
|
||||
140
EXAMPLES/README.md
Normal file
140
EXAMPLES/README.md
Normal file
@ -0,0 +1,140 @@
|
||||
# SecuBox Code Examples
|
||||
|
||||
This directory contains practical code examples for SecuBox module development and integration.
|
||||
|
||||
## Available Examples
|
||||
|
||||
### help-button-integration.js
|
||||
Comprehensive examples for integrating help/documentation buttons into SecuBox modules.
|
||||
|
||||
**What's Included:**
|
||||
- Shared help utility module
|
||||
- Module integration examples
|
||||
- Multiple UI patterns (header, floating, quick actions)
|
||||
- Context-sensitive help
|
||||
- CSS styling examples
|
||||
|
||||
**Use Cases:**
|
||||
- Adding help buttons to module dashboards
|
||||
- Linking to website documentation
|
||||
- Creating consistent help UX across modules
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- **Integration Plan:** `../DOCS/HELP_INTEGRATION_PLAN.md`
|
||||
- **Deployment Guide:** `../DOCS/WEBSITE_DEPLOYMENT_GUIDE.md`
|
||||
- **LuCI Development:** `../DOCS/LUCI_DEVELOPMENT_REFERENCE.md`
|
||||
|
||||
## How to Use Examples
|
||||
|
||||
1. **Review the example code** to understand the pattern
|
||||
2. **Copy relevant sections** to your module
|
||||
3. **Customize** module names, URLs, and styling
|
||||
4. **Test** on development router
|
||||
5. **Deploy** using deployment scripts
|
||||
|
||||
## Integration Workflow
|
||||
|
||||
```bash
|
||||
# 1. Deploy website to router
|
||||
./secubox-tools/deploy-website.sh root@192.168.8.191
|
||||
|
||||
# 2. Add help button code to your module
|
||||
# (see help-button-integration.js)
|
||||
|
||||
# 3. Build and deploy module
|
||||
./secubox-tools/local-build.sh build luci-app-your-module
|
||||
./secubox-tools/deploy-network-modes.sh root@192.168.8.191
|
||||
|
||||
# 4. Test in browser
|
||||
open http://192.168.8.191/cgi-bin/luci/admin/secubox/your-module
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Pattern 1: Header Help Button
|
||||
```javascript
|
||||
'require secubox/help as Help';
|
||||
|
||||
E('div', { 'class': 'header' }, [
|
||||
E('h2', {}, 'Module Title'),
|
||||
Help.createHelpButton('module-name', 'header')
|
||||
])
|
||||
```
|
||||
|
||||
### Pattern 2: Floating Help Button
|
||||
```javascript
|
||||
E('a', {
|
||||
'class': 'sb-help-floating',
|
||||
'href': '/luci-static/secubox/demo-module.html',
|
||||
'target': '_blank'
|
||||
}, [E('span', {}, '❓')])
|
||||
```
|
||||
|
||||
### Pattern 3: Quick Action
|
||||
```javascript
|
||||
buttons.push(
|
||||
E('button', {
|
||||
'class': 'action-btn',
|
||||
'click': function() {
|
||||
window.open('/luci-static/secubox/demo-module.html', '_blank');
|
||||
}
|
||||
}, ['📖 Help'])
|
||||
)
|
||||
```
|
||||
|
||||
## Module-Specific Examples
|
||||
|
||||
Each module can have different help button placements:
|
||||
|
||||
| Module | Recommended Position | Example File |
|
||||
|--------|---------------------|--------------|
|
||||
| SecuBox Dashboard | Quick Actions | help-button-integration.js (Ex 3) |
|
||||
| System Hub | Header Badge | help-button-integration.js (Ex 4) |
|
||||
| Network Modes | Header Button | help-button-integration.js (Ex 2) |
|
||||
| Other Modules | Floating Button | help-button-integration.js (Ex 5) |
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] Help button is visible
|
||||
- [ ] Clicking opens correct documentation page
|
||||
- [ ] Styling matches module theme
|
||||
- [ ] Works in dark/light mode
|
||||
- [ ] Responsive on mobile
|
||||
- [ ] No console errors
|
||||
- [ ] Accessible via keyboard
|
||||
|
||||
## Contributing Examples
|
||||
|
||||
To add new examples:
|
||||
|
||||
1. Create descriptive JavaScript file
|
||||
2. Include clear comments
|
||||
3. Show complete, working code
|
||||
4. Update this README
|
||||
5. Test on actual router
|
||||
|
||||
## Support
|
||||
|
||||
For questions about examples:
|
||||
- Review related documentation in `DOCS/`
|
||||
- Check module source code in `luci-app-*/`
|
||||
- Test on development router first
|
||||
|
||||
## Quick Reference
|
||||
|
||||
**Website Base URL:** `/luci-static/secubox/`
|
||||
|
||||
**Module Help Pages:**
|
||||
- secubox → `index.html#modules`
|
||||
- system-hub → `demo-secubox-hub.html`
|
||||
- network-modes → `demo-network-modes.html`
|
||||
- client-guardian → `demo-client-guardian.html`
|
||||
- bandwidth-manager → `demo-bandwidth.html`
|
||||
- traffic-shaper → `demo-traffic-shaper.html`
|
||||
- (See help-button-integration.js for complete list)
|
||||
|
||||
**Help Utility Methods:**
|
||||
- `Help.createHelpButton(module, position, options)`
|
||||
- `Help.getHelpUrl(module)`
|
||||
- `Help.openHelpModal(module)`
|
||||
356
EXAMPLES/help-button-integration.js
Normal file
356
EXAMPLES/help-button-integration.js
Normal file
@ -0,0 +1,356 @@
|
||||
/**
|
||||
* SecuBox Help Button Integration Example
|
||||
*
|
||||
* This file demonstrates how to integrate help buttons into SecuBox modules
|
||||
* to link with the deployed website documentation.
|
||||
*
|
||||
* Version: 1.0
|
||||
* Date: 2025-12-28
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// EXAMPLE 1: Shared Help Utility (Recommended)
|
||||
// ============================================================================
|
||||
|
||||
// File: luci-app-secubox/htdocs/luci-static/resources/secubox/help.js
|
||||
|
||||
'use strict';
|
||||
'require baseclass';
|
||||
|
||||
return baseclass.extend({
|
||||
/**
|
||||
* Create a help button element
|
||||
* @param {string} moduleName - Module identifier (e.g., 'network-modes')
|
||||
* @param {string} position - Button position: 'header', 'footer', 'floating'
|
||||
* @param {object} options - Custom options
|
||||
*/
|
||||
createHelpButton: function(moduleName, position, options) {
|
||||
var opts = options || {};
|
||||
var helpUrl = this.getHelpUrl(moduleName);
|
||||
var buttonClass = 'sb-help-btn sb-help-' + position;
|
||||
|
||||
return E('a', {
|
||||
'class': buttonClass,
|
||||
'href': helpUrl,
|
||||
'target': opts.target || '_blank',
|
||||
'title': opts.title || _('View Help & Documentation'),
|
||||
'style': opts.style || ''
|
||||
}, [
|
||||
E('span', { 'class': 'sb-help-icon' }, opts.icon || '❓'),
|
||||
opts.showLabel !== false ? E('span', { 'class': 'sb-help-label' }, opts.label || _('Help')) : null
|
||||
]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get help URL for a module
|
||||
* @param {string} moduleName - Module identifier
|
||||
*/
|
||||
getHelpUrl: function(moduleName) {
|
||||
var baseUrl = '/luci-static/secubox/';
|
||||
var moduleMap = {
|
||||
'secubox': 'index.html#modules',
|
||||
'system-hub': 'demo-secubox-hub.html',
|
||||
'network-modes': 'demo-network-modes.html',
|
||||
'client-guardian': 'demo-client-guardian.html',
|
||||
'bandwidth-manager': 'demo-bandwidth.html',
|
||||
'cdn-cache': 'demo-cdn-cache.html',
|
||||
'traffic-shaper': 'demo-traffic-shaper.html',
|
||||
'wireguard-dashboard': 'demo-wireguard.html',
|
||||
'crowdsec-dashboard': 'demo-crowdsec.html',
|
||||
'netdata-dashboard': 'demo-netdata.html',
|
||||
'netifyd-dashboard': 'demo-netifyd.html',
|
||||
'auth-guardian': 'demo-auth.html',
|
||||
'vhost-manager': 'demo-vhost.html',
|
||||
'ksm-manager': 'demo-ksm-manager.html',
|
||||
'media-flow': 'demo-media.html'
|
||||
};
|
||||
|
||||
return baseUrl + (moduleMap[moduleName] || 'index.html');
|
||||
},
|
||||
|
||||
/**
|
||||
* Open help in modal (for inline help)
|
||||
* @param {string} moduleName - Module identifier
|
||||
*/
|
||||
openHelpModal: function(moduleName) {
|
||||
var helpUrl = this.getHelpUrl(moduleName);
|
||||
var iframe = E('iframe', {
|
||||
'src': helpUrl,
|
||||
'style': 'width: 100%; height: 70vh; border: none; border-radius: 8px;'
|
||||
});
|
||||
|
||||
ui.showModal(_('Help & Documentation'), [
|
||||
E('div', { 'style': 'min-height: 70vh;' }, [iframe]),
|
||||
E('div', { 'class': 'right', 'style': 'margin-top: 1rem;' }, [
|
||||
E('button', {
|
||||
'class': 'btn',
|
||||
'click': ui.hideModal
|
||||
}, _('Close'))
|
||||
])
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// EXAMPLE 2: Module Integration (Network Modes)
|
||||
// ============================================================================
|
||||
|
||||
// File: luci-app-network-modes/htdocs/luci-static/resources/view/network-modes/overview.js
|
||||
|
||||
'use strict';
|
||||
'require view';
|
||||
'require dom';
|
||||
'require ui';
|
||||
'require network-modes.api as api';
|
||||
'require secubox/help as Help'; // ← ADD THIS LINE
|
||||
|
||||
return view.extend({
|
||||
title: _('Network Modes'),
|
||||
|
||||
load: function() {
|
||||
return api.getAllData();
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var self = this;
|
||||
var status = data.status || {};
|
||||
var currentMode = status.current_mode || 'router';
|
||||
|
||||
var view = E('div', { 'class': 'network-modes-dashboard' }, [
|
||||
// Load help CSS
|
||||
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox/help.css') }),
|
||||
|
||||
// Header with help button
|
||||
E('div', { 'class': 'nm-header' }, [
|
||||
E('div', { 'class': 'nm-logo' }, [
|
||||
E('div', { 'class': 'nm-logo-icon' }, '🌐'),
|
||||
E('div', { 'class': 'nm-logo-text' }, ['Network ', E('span', {}, 'Configuration')])
|
||||
]),
|
||||
E('div', { 'class': 'nm-mode-badge ' + currentMode }, [
|
||||
E('span', { 'class': 'nm-mode-dot' }),
|
||||
currentMode
|
||||
]),
|
||||
// ← ADD HELP BUTTON HERE
|
||||
Help.createHelpButton('network-modes', 'header', {
|
||||
icon: '📖',
|
||||
label: _('Help')
|
||||
})
|
||||
]),
|
||||
|
||||
// Rest of the dashboard...
|
||||
]);
|
||||
|
||||
return view;
|
||||
}
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// EXAMPLE 3: SecuBox Dashboard Integration (Quick Actions)
|
||||
// ============================================================================
|
||||
|
||||
// File: luci-app-secubox/htdocs/luci-static/resources/view/secubox/dashboard.js
|
||||
// Add to renderQuickActions method
|
||||
|
||||
renderQuickActions: function() {
|
||||
var self = this;
|
||||
var actions = [
|
||||
{ name: 'restart_rpcd', label: 'RPCD', icon: '🔄', color: '#6366f1' },
|
||||
{ name: 'restart_uhttpd', label: 'Web Server', icon: '🌐', color: '#00ab44' },
|
||||
{ name: 'restart_network', label: 'Network', icon: '📡', color: '#06b6d4' },
|
||||
{ name: 'restart_firewall', label: 'Firewall', icon: '🛡️', color: '#ef4444' },
|
||||
{ name: 'clear_cache', label: 'Clear Cache', icon: '🧹', color: '#f59e0b' },
|
||||
{ name: 'backup_config', label: 'Backup', icon: '💾', color: '#8b5cf6' }
|
||||
];
|
||||
|
||||
var buttons = actions.map(function(action) {
|
||||
return E('button', {
|
||||
'class': 'secubox-action-btn',
|
||||
'style': 'border-color: ' + action.color,
|
||||
'click': function() {
|
||||
self.executeQuickAction(action.name, action.label);
|
||||
}
|
||||
}, [
|
||||
E('span', { 'class': 'secubox-action-icon' }, action.icon),
|
||||
E('span', { 'class': 'secubox-action-label' }, action.label)
|
||||
]);
|
||||
});
|
||||
|
||||
// ← ADD HELP BUTTON TO QUICK ACTIONS
|
||||
buttons.push(
|
||||
E('button', {
|
||||
'class': 'secubox-action-btn',
|
||||
'style': 'border-color: #667eea',
|
||||
'click': function() {
|
||||
window.open('/luci-static/secubox/index.html#modules', '_blank');
|
||||
}
|
||||
}, [
|
||||
E('span', { 'class': 'secubox-action-icon' }, '📖'),
|
||||
E('span', { 'class': 'secubox-action-label' }, _('Help'))
|
||||
])
|
||||
);
|
||||
|
||||
return E('div', { 'class': 'secubox-card' }, [
|
||||
E('h3', { 'class': 'secubox-card-title' }, '⚡ Quick Actions'),
|
||||
E('div', { 'class': 'secubox-actions-grid' }, buttons)
|
||||
]);
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// EXAMPLE 4: System Hub Integration (Header Badge Style)
|
||||
// ============================================================================
|
||||
|
||||
// File: luci-app-system-hub/htdocs/luci-static/resources/view/system-hub/overview.js
|
||||
// Modify renderHeader method
|
||||
|
||||
renderHeader: function() {
|
||||
var score = this.healthData.score || 0;
|
||||
var scoreClass = score >= 80 ? 'excellent' : (score >= 60 ? 'good' : 'warning');
|
||||
var scoreLabel = score >= 80 ? 'Excellent' : (score >= 60 ? 'Good' : 'Warning');
|
||||
|
||||
return E('div', { 'class': 'sh-dashboard-header' }, [
|
||||
E('div', { 'class': 'sh-dashboard-header-content' }, [
|
||||
E('div', {}, [
|
||||
E('h2', {}, '⚙️ System Control Center'),
|
||||
E('p', { 'class': 'sh-dashboard-subtitle' }, 'System Monitoring & Management Center')
|
||||
]),
|
||||
E('div', { 'class': 'sh-dashboard-header-info' }, [
|
||||
E('div', { 'class': 'sh-header-badge-group' }, [
|
||||
E('span', { 'class': 'sh-dashboard-badge sh-dashboard-badge-version' },
|
||||
'v0.3.6'),
|
||||
E('span', { 'class': 'sh-dashboard-badge' },
|
||||
'⏱️ ' + (this.sysInfo.uptime_formatted || '0d 0h 0m')),
|
||||
E('span', { 'class': 'sh-dashboard-badge' },
|
||||
'🖥️ ' + (this.sysInfo.hostname || 'OpenWrt')),
|
||||
// ← ADD HELP BADGE
|
||||
E('a', {
|
||||
'class': 'sh-dashboard-badge sh-help-badge',
|
||||
'href': '/luci-static/secubox/demo-secubox-hub.html',
|
||||
'target': '_blank',
|
||||
'title': _('View Help')
|
||||
}, '📖 Help')
|
||||
]),
|
||||
this.renderHealthGauge(score, scoreClass, scoreLabel)
|
||||
])
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// EXAMPLE 5: Floating Help Button (Global)
|
||||
// ============================================================================
|
||||
|
||||
// Add to any module's render method for a floating help button
|
||||
|
||||
render: function(data) {
|
||||
var container = E('div', { 'class': 'module-dashboard' }, [
|
||||
// ... module content ...
|
||||
|
||||
// ← ADD FLOATING HELP BUTTON
|
||||
E('a', {
|
||||
'class': 'sb-help-floating',
|
||||
'href': '/luci-static/secubox/demo-module.html',
|
||||
'target': '_blank',
|
||||
'title': _('Help & Documentation')
|
||||
}, [
|
||||
E('span', { 'class': 'sb-help-icon' }, '❓')
|
||||
])
|
||||
]);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// EXAMPLE 6: Inline Modal Help
|
||||
// ============================================================================
|
||||
|
||||
// Use Help.openHelpModal() for inline help
|
||||
|
||||
E('button', {
|
||||
'class': 'btn cbi-button-action',
|
||||
'click': function() {
|
||||
Help.openHelpModal('network-modes');
|
||||
}
|
||||
}, [
|
||||
E('span', {}, '❓ '),
|
||||
_('Help')
|
||||
])
|
||||
|
||||
// ============================================================================
|
||||
// EXAMPLE 7: Context-Sensitive Help
|
||||
// ============================================================================
|
||||
|
||||
// Different help URLs based on context
|
||||
|
||||
getContextualHelpUrl: function(context) {
|
||||
var baseUrl = '/luci-static/secubox/demo-network-modes.html';
|
||||
var anchors = {
|
||||
'sniffer': '#sniffer-mode',
|
||||
'accesspoint': '#access-point-mode',
|
||||
'relay': '#relay-mode',
|
||||
'router': '#router-mode'
|
||||
};
|
||||
|
||||
return baseUrl + (anchors[context] || '');
|
||||
}
|
||||
|
||||
// Then use it:
|
||||
E('a', {
|
||||
'href': this.getContextualHelpUrl('sniffer'),
|
||||
'target': '_blank'
|
||||
}, _('Learn about Sniffer Mode'))
|
||||
|
||||
// ============================================================================
|
||||
// CSS INTEGRATION EXAMPLE
|
||||
// ============================================================================
|
||||
|
||||
/*
|
||||
File: luci-app-secubox/htdocs/luci-static/resources/secubox/help.css
|
||||
|
||||
Add to existing module CSS for consistent styling:
|
||||
*/
|
||||
|
||||
/* Help Button Base */
|
||||
.sb-help-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
border: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sb-help-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
/* Floating position */
|
||||
.sb-help-floating {
|
||||
position: fixed;
|
||||
bottom: 2rem;
|
||||
right: 2rem;
|
||||
z-index: 1000;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
padding: 0;
|
||||
justify-content: center;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* System Hub badge style */
|
||||
.sh-help-badge {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.sh-help-badge:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
'require dom';
|
||||
'require ui';
|
||||
'require network-modes.api as api';
|
||||
'require secubox/help as Help';
|
||||
|
||||
return view.extend({
|
||||
title: _('Network Modes'),
|
||||
@ -62,6 +63,9 @@ return view.extend({
|
||||
var currentModeInfo = modeInfos[currentMode];
|
||||
|
||||
var view = E('div', { 'class': 'network-modes-dashboard' }, [
|
||||
// Load help CSS
|
||||
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox/help.css') }),
|
||||
|
||||
// Header
|
||||
E('div', { 'class': 'nm-header' }, [
|
||||
E('div', { 'class': 'nm-logo' }, [
|
||||
@ -71,7 +75,11 @@ return view.extend({
|
||||
E('div', { 'class': 'nm-mode-badge ' + currentMode }, [
|
||||
E('span', { 'class': 'nm-mode-dot' }),
|
||||
currentModeInfo ? currentModeInfo.name : currentMode
|
||||
])
|
||||
]),
|
||||
Help.createHelpButton('network-modes', 'header', {
|
||||
icon: '📖',
|
||||
label: _('Help')
|
||||
})
|
||||
]),
|
||||
|
||||
// Current Mode Display Card
|
||||
|
||||
@ -448,8 +448,8 @@ apply_mode() {
|
||||
apply_accesspoint_features
|
||||
;;
|
||||
|
||||
relay)
|
||||
# Repeater mode: STA + AP relay
|
||||
relay)
|
||||
# Repeater mode: STA + AP relay
|
||||
# Client interface (sta)
|
||||
uci set network.wwan=interface
|
||||
uci set network.wwan.proto='dhcp'
|
||||
@ -465,12 +465,41 @@ apply_mode() {
|
||||
uci set network.stabridge.proto='relay'
|
||||
uci set network.stabridge.network='lan wwan'
|
||||
|
||||
apply_wireguard_config
|
||||
apply_mtu_clamping
|
||||
enable_tcp_bbr
|
||||
;;
|
||||
apply_wireguard_config
|
||||
apply_mtu_clamping
|
||||
enable_tcp_bbr
|
||||
;;
|
||||
|
||||
bridge)
|
||||
sniffer)
|
||||
local ports=$(uci -q get network-modes.sniffer.bridge_ports || echo "eth0 eth1")
|
||||
local bridge_iface=$(uci -q get network-modes.sniffer.bridge_interface || echo "br-lan")
|
||||
local promisc=$(uci -q get network-modes.sniffer.promiscuous || echo 1)
|
||||
|
||||
uci delete network.wan 2>/dev/null
|
||||
uci set network.lan=interface
|
||||
uci set network.lan.proto='none'
|
||||
uci set network.lan.type='bridge'
|
||||
uci set network.lan.ifname="$ports"
|
||||
uci set network.lan.delegate='0'
|
||||
uci set network.lan.device="$bridge_iface"
|
||||
|
||||
uci set dhcp.lan=dhcp
|
||||
uci set dhcp.lan.interface='lan'
|
||||
uci set dhcp.lan.ignore='1'
|
||||
|
||||
uci set firewall.@zone[0].input='ACCEPT'
|
||||
uci set firewall.@zone[0].output='ACCEPT'
|
||||
uci set firewall.@zone[0].forward='ACCEPT'
|
||||
uci delete firewall.@zone[1] 2>/dev/null
|
||||
|
||||
if [ "$promisc" = "1" ]; then
|
||||
for port in $ports; do
|
||||
ip link set "$port" promisc on 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
;;
|
||||
|
||||
bridge)
|
||||
# Pure L2 bridge: all interfaces bridged, DHCP client
|
||||
uci delete network.wan 2>/dev/null
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"admin/secubox/network/network-modes": {
|
||||
"admin/secubox/network-modes": {
|
||||
"title": "Network Modes",
|
||||
"order": 20,
|
||||
"action": {
|
||||
@ -9,7 +9,7 @@
|
||||
"acl": ["luci-app-network-modes"]
|
||||
}
|
||||
},
|
||||
"admin/secubox/network/network-modes/overview": {
|
||||
"admin/secubox/network-modes/overview": {
|
||||
"title": "Overview",
|
||||
"order": 10,
|
||||
"action": {
|
||||
@ -17,7 +17,7 @@
|
||||
"path": "network-modes/overview"
|
||||
}
|
||||
},
|
||||
"admin/secubox/network/network-modes/wizard": {
|
||||
"admin/secubox/network-modes/wizard": {
|
||||
"title": "Mode Wizard",
|
||||
"order": 20,
|
||||
"action": {
|
||||
@ -25,7 +25,7 @@
|
||||
"path": "network-modes/wizard"
|
||||
}
|
||||
},
|
||||
"admin/secubox/network/network-modes/router": {
|
||||
"admin/secubox/network-modes/router": {
|
||||
"title": "Router Mode",
|
||||
"order": 30,
|
||||
"action": {
|
||||
@ -33,7 +33,7 @@
|
||||
"path": "network-modes/router"
|
||||
}
|
||||
},
|
||||
"admin/secubox/network/network-modes/accesspoint": {
|
||||
"admin/secubox/network-modes/accesspoint": {
|
||||
"title": "Access Point Mode",
|
||||
"order": 40,
|
||||
"action": {
|
||||
@ -41,7 +41,7 @@
|
||||
"path": "network-modes/accesspoint"
|
||||
}
|
||||
},
|
||||
"admin/secubox/network/network-modes/relay": {
|
||||
"admin/secubox/network-modes/relay": {
|
||||
"title": "Relay Mode",
|
||||
"order": 50,
|
||||
"action": {
|
||||
@ -49,7 +49,7 @@
|
||||
"path": "network-modes/relay"
|
||||
}
|
||||
},
|
||||
"admin/secubox/network/network-modes/sniffer": {
|
||||
"admin/secubox/network-modes/sniffer": {
|
||||
"title": "Sniffer Mode",
|
||||
"order": 60,
|
||||
"action": {
|
||||
@ -57,7 +57,7 @@
|
||||
"path": "network-modes/sniffer"
|
||||
}
|
||||
},
|
||||
"admin/secubox/network/network-modes/settings": {
|
||||
"admin/secubox/network-modes/settings": {
|
||||
"title": "Settings",
|
||||
"order": 90,
|
||||
"action": {
|
||||
|
||||
@ -244,6 +244,18 @@
|
||||
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
|
||||
}
|
||||
|
||||
.secubox-tab-bonus {
|
||||
background: linear-gradient(135deg, #f97316 0%, #ec4899 100%);
|
||||
border: none;
|
||||
color: white;
|
||||
box-shadow: 0 10px 24px rgba(236, 72, 153, 0.35);
|
||||
}
|
||||
|
||||
.secubox-tab-bonus:hover {
|
||||
background: linear-gradient(135deg, #fb923c 0%, #f472b6 100%);
|
||||
box-shadow: 0 12px 28px rgba(236, 72, 153, 0.4);
|
||||
}
|
||||
|
||||
.secubox-tab-icon {
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
|
||||
322
luci-app-secubox/htdocs/luci-static/resources/secubox/help.css
Normal file
322
luci-app-secubox/htdocs/luci-static/resources/secubox/help.css
Normal file
@ -0,0 +1,322 @@
|
||||
/**
|
||||
* SecuBox Help System Styles
|
||||
* Version: 1.0.0
|
||||
*/
|
||||
|
||||
/* ============================================================================
|
||||
Base Help Button Styles
|
||||
============================================================================ */
|
||||
|
||||
.sb-help-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white !important;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
transition: all 0.3s ease;
|
||||
border: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.sb-help-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
color: white !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.sb-help-btn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 6px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
|
||||
.sb-help-icon {
|
||||
font-size: 1.2em;
|
||||
line-height: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sb-help-label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Position Variants
|
||||
============================================================================ */
|
||||
|
||||
/* Header Position - Compact style for headers */
|
||||
.sb-help-header {
|
||||
margin-left: auto;
|
||||
padding: 0.4rem 0.8rem;
|
||||
font-size: 0.85em;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
/* Footer Position - Full width on mobile */
|
||||
.sb-help-footer {
|
||||
margin-top: 2rem;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.sb-help-footer {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* Badge Style - Minimal, badge-like appearance */
|
||||
.sb-help-badge {
|
||||
padding: 0.3rem 0.6rem;
|
||||
font-size: 0.8rem;
|
||||
border-radius: 4px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white !important;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.sb-help-badge:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.4);
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
/* Floating Button - Fixed position, circular */
|
||||
.sb-help-floating {
|
||||
position: fixed;
|
||||
bottom: 2rem;
|
||||
right: 2rem;
|
||||
z-index: 1000;
|
||||
border-radius: 50%;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
padding: 0;
|
||||
justify-content: center;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.sb-help-floating .sb-help-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sb-help-floating .sb-help-icon {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
.sb-help-floating:hover {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.5);
|
||||
}
|
||||
|
||||
/* Hide floating button on small screens to avoid overlap */
|
||||
@media (max-width: 768px) {
|
||||
.sb-help-floating {
|
||||
bottom: 1rem;
|
||||
right: 1rem;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.sb-help-floating .sb-help-icon {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Tooltip Styles
|
||||
============================================================================ */
|
||||
|
||||
.sb-help-tooltip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
cursor: help;
|
||||
margin-left: 0.3rem;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.sb-help-tooltip:hover {
|
||||
transform: scale(1.2);
|
||||
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Dark Theme Support
|
||||
============================================================================ */
|
||||
|
||||
[data-theme="dark"] .sb-help-btn {
|
||||
background: linear-gradient(135deg, #4c51bf 0%, #553c9a 100%);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .sb-help-btn:hover {
|
||||
box-shadow: 0 4px 12px rgba(76, 81, 191, 0.5);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .sb-help-badge {
|
||||
background: linear-gradient(135deg, #4c51bf 0%, #553c9a 100%);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .sb-help-tooltip {
|
||||
background: linear-gradient(135deg, #4c51bf 0%, #553c9a 100%);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Button States
|
||||
============================================================================ */
|
||||
|
||||
.sb-help-btn:disabled,
|
||||
.sb-help-btn.disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.sb-help-btn:focus {
|
||||
outline: 2px solid #667eea;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Loading State
|
||||
============================================================================ */
|
||||
|
||||
.sb-help-btn.loading {
|
||||
position: relative;
|
||||
color: transparent !important;
|
||||
}
|
||||
|
||||
.sb-help-btn.loading::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -8px;
|
||||
margin-top: -8px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
border-top-color: white;
|
||||
animation: sb-help-spin 0.6s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes sb-help-spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Integration with Existing Modules
|
||||
============================================================================ */
|
||||
|
||||
/* SecuBox Dashboard */
|
||||
.secubox-actions-grid .sb-help-btn {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* System Hub */
|
||||
.sh-dashboard-header .sb-help-badge {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
/* Network Modes */
|
||||
.nm-header .sb-help-btn {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Accessibility
|
||||
============================================================================ */
|
||||
|
||||
/* High contrast mode support */
|
||||
@media (prefers-contrast: high) {
|
||||
.sb-help-btn {
|
||||
border: 2px solid currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reduced motion support */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.sb-help-btn,
|
||||
.sb-help-tooltip,
|
||||
.sb-help-floating {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.sb-help-btn:hover,
|
||||
.sb-help-floating:hover {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.sb-help-btn.loading::after {
|
||||
animation: none;
|
||||
border-top-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
/* Focus visible for keyboard navigation */
|
||||
.sb-help-btn:focus-visible {
|
||||
outline: 3px solid #667eea;
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Print Styles
|
||||
============================================================================ */
|
||||
|
||||
@media print {
|
||||
.sb-help-btn,
|
||||
.sb-help-floating,
|
||||
.sb-help-tooltip {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Responsive Adjustments
|
||||
============================================================================ */
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.sb-help-btn {
|
||||
font-size: 0.85rem;
|
||||
padding: 0.4rem 0.7rem;
|
||||
}
|
||||
|
||||
.sb-help-header {
|
||||
padding: 0.3rem 0.6rem;
|
||||
}
|
||||
|
||||
/* Stack label vertically on very small screens if needed */
|
||||
.sb-help-btn.sb-help-stacked {
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.sb-help-btn.sb-help-stacked .sb-help-icon {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
.sb-help-btn.sb-help-stacked .sb-help-label {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
183
luci-app-secubox/htdocs/luci-static/resources/secubox/help.js
Normal file
183
luci-app-secubox/htdocs/luci-static/resources/secubox/help.js
Normal file
@ -0,0 +1,183 @@
|
||||
'use strict';
|
||||
'require baseclass';
|
||||
'require ui';
|
||||
|
||||
/**
|
||||
* SecuBox Help System
|
||||
* Provides centralized help/documentation access for all SecuBox modules
|
||||
* Version: 1.0.0
|
||||
*/
|
||||
|
||||
console.log('📖 SecuBox Help System v1.0.0 loaded');
|
||||
|
||||
return baseclass.extend({
|
||||
/**
|
||||
* Create a help button element
|
||||
* @param {string} moduleName - Module identifier (e.g., 'network-modes')
|
||||
* @param {string} position - Button position: 'header', 'footer', 'floating', 'badge'
|
||||
* @param {object} options - Custom options
|
||||
* @returns {Element} Help button element
|
||||
*/
|
||||
createHelpButton: function(moduleName, position, options) {
|
||||
var opts = options || {};
|
||||
var helpUrl = this.getHelpUrl(moduleName);
|
||||
var buttonClass = 'sb-help-btn sb-help-' + position;
|
||||
var target = opts.target || '_blank';
|
||||
|
||||
// Handle modal vs new tab
|
||||
if (opts.modal) {
|
||||
var self = this;
|
||||
return E('button', {
|
||||
'class': buttonClass,
|
||||
'title': opts.title || _('View Help & Documentation'),
|
||||
'style': opts.style || '',
|
||||
'click': function(ev) {
|
||||
ev.preventDefault();
|
||||
self.openHelpModal(moduleName);
|
||||
}
|
||||
}, [
|
||||
E('span', { 'class': 'sb-help-icon' }, opts.icon || '❓'),
|
||||
opts.showLabel !== false ? E('span', { 'class': 'sb-help-label' }, opts.label || _('Help')) : null
|
||||
]);
|
||||
}
|
||||
|
||||
// Regular link button
|
||||
return E('a', {
|
||||
'class': buttonClass,
|
||||
'href': helpUrl,
|
||||
'target': target,
|
||||
'title': opts.title || _('View Help & Documentation'),
|
||||
'style': opts.style || ''
|
||||
}, [
|
||||
E('span', { 'class': 'sb-help-icon' }, opts.icon || '❓'),
|
||||
opts.showLabel !== false ? E('span', { 'class': 'sb-help-label' }, opts.label || _('Help')) : null
|
||||
]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get help URL for a module
|
||||
* @param {string} moduleName - Module identifier
|
||||
* @param {string} anchor - Optional anchor/section (e.g., '#features')
|
||||
* @returns {string} Help page URL
|
||||
*/
|
||||
getHelpUrl: function(moduleName, anchor) {
|
||||
var baseUrl = '/luci-static/secubox/';
|
||||
var moduleMap = {
|
||||
'secubox': 'index.html#modules',
|
||||
'system-hub': 'demo-secubox-hub.html',
|
||||
'network-modes': 'demo-network-modes.html',
|
||||
'client-guardian': 'demo-client-guardian.html',
|
||||
'bandwidth-manager': 'demo-bandwidth.html',
|
||||
'cdn-cache': 'demo-cdn-cache.html',
|
||||
'traffic-shaper': 'demo-traffic-shaper.html',
|
||||
'wireguard-dashboard': 'demo-wireguard.html',
|
||||
'crowdsec-dashboard': 'demo-crowdsec.html',
|
||||
'netdata-dashboard': 'demo-netdata.html',
|
||||
'netifyd-dashboard': 'demo-netifyd.html',
|
||||
'auth-guardian': 'demo-auth.html',
|
||||
'vhost-manager': 'demo-vhost.html',
|
||||
'ksm-manager': 'demo-ksm-manager.html',
|
||||
'media-flow': 'demo-media.html'
|
||||
};
|
||||
|
||||
var url = baseUrl + (moduleMap[moduleName] || 'index.html');
|
||||
return anchor ? url + anchor : url;
|
||||
},
|
||||
|
||||
/**
|
||||
* Open help in modal dialog with iframe
|
||||
* @param {string} moduleName - Module identifier
|
||||
* @param {object} options - Modal options
|
||||
*/
|
||||
openHelpModal: function(moduleName, options) {
|
||||
var opts = options || {};
|
||||
var helpUrl = this.getHelpUrl(moduleName);
|
||||
var modalTitle = opts.title || _('Help & Documentation');
|
||||
|
||||
var iframe = E('iframe', {
|
||||
'src': helpUrl,
|
||||
'style': 'width: 100%; height: 70vh; border: none; border-radius: 8px; background: white;',
|
||||
'frameborder': '0'
|
||||
});
|
||||
|
||||
var modal = E('div', { 'style': 'min-height: 70vh;' }, [
|
||||
iframe,
|
||||
E('div', {
|
||||
'class': 'right',
|
||||
'style': 'margin-top: 1rem; display: flex; gap: 0.5rem; justify-content: flex-end;'
|
||||
}, [
|
||||
opts.showOpenButton !== false ? E('a', {
|
||||
'class': 'btn cbi-button-neutral',
|
||||
'href': helpUrl,
|
||||
'target': '_blank'
|
||||
}, [
|
||||
'🔗 ',
|
||||
_('Open in New Tab')
|
||||
]) : null,
|
||||
E('button', {
|
||||
'class': 'btn cbi-button-action',
|
||||
'click': ui.hideModal
|
||||
}, _('Close'))
|
||||
])
|
||||
]);
|
||||
|
||||
ui.showModal(modalTitle, [modal]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a quick help tooltip
|
||||
* @param {string} text - Tooltip text
|
||||
* @param {string} moduleName - Optional module for "Learn More" link
|
||||
* @returns {Element} Tooltip element
|
||||
*/
|
||||
createTooltip: function(text, moduleName) {
|
||||
var tooltip = E('span', {
|
||||
'class': 'sb-help-tooltip',
|
||||
'title': text
|
||||
}, '❓');
|
||||
|
||||
if (moduleName) {
|
||||
var self = this;
|
||||
tooltip.addEventListener('click', function(ev) {
|
||||
ev.preventDefault();
|
||||
window.open(self.getHelpUrl(moduleName), '_blank');
|
||||
});
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if help page exists (basic check)
|
||||
* @param {string} moduleName - Module identifier
|
||||
* @returns {boolean} True if help page is configured
|
||||
*/
|
||||
hasHelpPage: function(moduleName) {
|
||||
var url = this.getHelpUrl(moduleName);
|
||||
return url.indexOf('demo-') !== -1 || moduleName === 'secubox';
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all available help pages
|
||||
* @returns {object} Map of module names to help URLs
|
||||
*/
|
||||
getAllHelpPages: function() {
|
||||
return {
|
||||
'secubox': this.getHelpUrl('secubox'),
|
||||
'system-hub': this.getHelpUrl('system-hub'),
|
||||
'network-modes': this.getHelpUrl('network-modes'),
|
||||
'client-guardian': this.getHelpUrl('client-guardian'),
|
||||
'bandwidth-manager': this.getHelpUrl('bandwidth-manager'),
|
||||
'cdn-cache': this.getHelpUrl('cdn-cache'),
|
||||
'traffic-shaper': this.getHelpUrl('traffic-shaper'),
|
||||
'wireguard-dashboard': this.getHelpUrl('wireguard-dashboard'),
|
||||
'crowdsec-dashboard': this.getHelpUrl('crowdsec-dashboard'),
|
||||
'netdata-dashboard': this.getHelpUrl('netdata-dashboard'),
|
||||
'netifyd-dashboard': this.getHelpUrl('netifyd-dashboard'),
|
||||
'auth-guardian': this.getHelpUrl('auth-guardian'),
|
||||
'vhost-manager': this.getHelpUrl('vhost-manager'),
|
||||
'ksm-manager': this.getHelpUrl('ksm-manager'),
|
||||
'media-flow': this.getHelpUrl('media-flow')
|
||||
};
|
||||
}
|
||||
});
|
||||
@ -92,6 +92,18 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
.secubox-filter-tab-bonus {
|
||||
background: linear-gradient(135deg, #f97316 0%, #ec4899 100%);
|
||||
border-color: transparent;
|
||||
color: white;
|
||||
box-shadow: 0 8px 20px rgba(249, 115, 22, 0.35);
|
||||
}
|
||||
|
||||
.secubox-filter-tab-bonus:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 24px rgba(236, 72, 153, 0.35);
|
||||
}
|
||||
|
||||
/* Modules Grid */
|
||||
.secubox-modules-grid {
|
||||
display: grid;
|
||||
|
||||
@ -345,6 +345,228 @@
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* SecuBox Help Bonus Page */
|
||||
.secubox-help-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.secubox-help-hero {
|
||||
display: flex;
|
||||
gap: 32px;
|
||||
align-items: center;
|
||||
background: linear-gradient(135deg, #312e81 0%, #0f172a 60%, #1e293b 100%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
box-shadow: 0 20px 60px rgba(15, 23, 42, 0.45);
|
||||
color: #eef2ff;
|
||||
}
|
||||
|
||||
.secubox-help-hero-text {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.secubox-help-eyebrow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.2em;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.secubox-help-subtitle {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: 15px;
|
||||
margin: 12px 0 0 0;
|
||||
}
|
||||
|
||||
.secubox-help-hero-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
gap: 16px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.secubox-help-hero-stat {
|
||||
background: rgba(15, 23, 42, 0.55);
|
||||
border-radius: 10px;
|
||||
padding: 14px 16px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.secubox-help-hero-stat-icon {
|
||||
font-size: 22px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.secubox-help-hero-stat-value {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.secubox-help-hero-stat-label {
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.secubox-help-hero-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
min-width: 230px;
|
||||
}
|
||||
|
||||
.secubox-help-cta {
|
||||
background: linear-gradient(135deg, #22c55e 0%, #15803d 100%) !important;
|
||||
box-shadow: 0 10px 30px rgba(21, 128, 61, 0.45);
|
||||
}
|
||||
|
||||
.secubox-card-title-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.secubox-card-hint {
|
||||
font-size: 13px;
|
||||
color: var(--sb-text-muted);
|
||||
}
|
||||
|
||||
.secubox-help-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 16px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.secubox-help-card {
|
||||
background: var(--sb-bg-card);
|
||||
border: 1px solid var(--sb-border);
|
||||
border-radius: 12px;
|
||||
padding: 18px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.secubox-help-card-body {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.secubox-help-card:hover {
|
||||
border-color: var(--sb-primary);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 12px 24px var(--sb-hover-shadow);
|
||||
}
|
||||
|
||||
.secubox-help-card-icon {
|
||||
font-size: 28px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 10px;
|
||||
background: rgba(99, 102, 241, 0.12);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.secubox-help-card-title {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--sb-text);
|
||||
}
|
||||
|
||||
.secubox-help-card-text {
|
||||
margin: 4px 0 8px 0;
|
||||
font-size: 13px;
|
||||
color: var(--sb-text-muted);
|
||||
}
|
||||
|
||||
.secubox-help-card-link {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--sb-primary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.secubox-help-support-grid {
|
||||
margin-top: 16px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.secubox-help-support-item {
|
||||
border: 1px dashed var(--sb-border);
|
||||
border-radius: 10px;
|
||||
padding: 16px;
|
||||
background: rgba(99, 102, 241, 0.04);
|
||||
}
|
||||
|
||||
.secubox-help-support-icon {
|
||||
font-size: 24px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.secubox-help-support-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
color: var(--sb-text);
|
||||
}
|
||||
|
||||
.secubox-help-support-text {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
color: var(--sb-text-muted);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.secubox-help-support-actions {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.secubox-help-footer {
|
||||
background: var(--sb-bg-card);
|
||||
border: 1px solid var(--sb-border);
|
||||
border-radius: 14px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.secubox-help-footer-text {
|
||||
font-size: 14px;
|
||||
color: var(--sb-text-muted);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.secubox-help-footer-links {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
color: var(--sb-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.secubox-help-footer-links .sep {
|
||||
color: var(--sb-text-muted);
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.secubox-health-grid {
|
||||
@ -358,4 +580,24 @@
|
||||
.secubox-modules-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.secubox-help-hero {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.secubox-help-hero-actions {
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.secubox-help-card {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.secubox-help-support-actions {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,20 +239,20 @@ return view.extend({
|
||||
|
||||
// Map module IDs to their dashboard paths
|
||||
var modulePaths = {
|
||||
'crowdsec': 'admin/secubox/security/crowdsec/overview',
|
||||
'netdata': 'admin/secubox/monitoring/netdata/dashboard',
|
||||
'netifyd': 'admin/secubox/security/netifyd/overview',
|
||||
'wireguard': 'admin/secubox/network/wireguard/overview',
|
||||
'network_modes': 'admin/secubox/network/network-modes/overview',
|
||||
'client_guardian': 'admin/secubox/security/client-guardian/overview',
|
||||
'system_hub': 'admin/secubox/system/system-hub/overview',
|
||||
'bandwidth_manager': 'admin/secubox/network/bandwidth-manager/overview',
|
||||
'auth_guardian': 'admin/secubox/security/auth-guardian/overview',
|
||||
'media_flow': 'admin/secubox/monitoring/mediaflow/dashboard',
|
||||
'vhost_manager': 'admin/secubox/services/vhosts/overview',
|
||||
'traffic_shaper': 'admin/secubox/network/traffic-shaper/overview',
|
||||
'cdn_cache': 'admin/secubox/network/cdn-cache/overview',
|
||||
'ksm_manager': 'admin/secubox/security/ksm-manager/overview'
|
||||
'crowdsec': 'admin/secubox/crowdsec/overview',
|
||||
'netdata': 'admin/secubox/netdata/dashboard',
|
||||
'netifyd': 'admin/secubox/netifyd/overview',
|
||||
'wireguard': 'admin/secubox/wireguard/overview',
|
||||
'network_modes': 'admin/secubox/network-modes/overview',
|
||||
'client_guardian': 'admin/secubox/client-guardian/overview',
|
||||
'system_hub': 'admin/secubox/system-hub/overview',
|
||||
'bandwidth_manager': 'admin/secubox/bandwidth-manager/overview',
|
||||
'auth_guardian': 'admin/secubox/auth-guardian/overview',
|
||||
'media_flow': 'admin/secubox/mediaflow/dashboard',
|
||||
'vhost_manager': 'admin/secubox/vhosts/overview',
|
||||
'traffic_shaper': 'admin/secubox/traffic-shaper/overview',
|
||||
'cdn_cache': 'admin/secubox/cdn-cache/overview',
|
||||
'ksm_manager': 'admin/secubox/ksm-manager/overview'
|
||||
};
|
||||
|
||||
var moduleCards = filteredModules.map(function(module) {
|
||||
@ -302,22 +302,34 @@ return view.extend({
|
||||
{ id: 'monitoring', label: 'Monitoring', icon: '📊' }
|
||||
];
|
||||
|
||||
var filterTabs = E('div', { 'class': 'secubox-filter-tabs' },
|
||||
filters.map(function(filter) {
|
||||
var isActive = self.activeFilter === filter.id;
|
||||
return E('div', {
|
||||
'class': 'secubox-filter-tab' + (isActive ? ' active' : ''),
|
||||
'click': function() {
|
||||
self.activeFilter = filter.id;
|
||||
self.updateModulesGrid();
|
||||
}
|
||||
}, [
|
||||
E('span', { 'class': 'secubox-tab-icon' }, filter.icon),
|
||||
E('span', { 'class': 'secubox-tab-label' }, filter.label)
|
||||
]);
|
||||
})
|
||||
var filterTabButtons = filters.map(function(filter) {
|
||||
var isActive = self.activeFilter === filter.id;
|
||||
return E('div', {
|
||||
'class': 'secubox-filter-tab' + (isActive ? ' active' : ''),
|
||||
'click': function() {
|
||||
self.activeFilter = filter.id;
|
||||
self.updateModulesGrid();
|
||||
}
|
||||
}, [
|
||||
E('span', { 'class': 'secubox-tab-icon' }, filter.icon),
|
||||
E('span', { 'class': 'secubox-tab-label' }, filter.label)
|
||||
]);
|
||||
});
|
||||
|
||||
filterTabButtons.push(
|
||||
E('div', {
|
||||
'class': 'secubox-filter-tab secubox-tab-bonus',
|
||||
'click': function() {
|
||||
window.location.href = L.url('admin/secubox/help');
|
||||
}
|
||||
}, [
|
||||
E('span', { 'class': 'secubox-tab-icon' }, '✨'),
|
||||
E('span', { 'class': 'secubox-tab-label' }, _('Bonus · Help à SecuBox'))
|
||||
])
|
||||
);
|
||||
|
||||
var filterTabs = E('div', { 'class': 'secubox-filter-tabs' }, filterTabButtons);
|
||||
|
||||
return E('div', { 'class': 'secubox-card' }, [
|
||||
E('h3', { 'class': 'secubox-card-title' }, '🎯 Active Modules (' + activeModules.length + ')'),
|
||||
filterTabs,
|
||||
@ -359,20 +371,20 @@ return view.extend({
|
||||
|
||||
// Map module IDs to their dashboard paths
|
||||
var modulePaths = {
|
||||
'crowdsec': 'admin/secubox/security/crowdsec/overview',
|
||||
'netdata': 'admin/secubox/monitoring/netdata/dashboard',
|
||||
'netifyd': 'admin/secubox/security/netifyd/overview',
|
||||
'wireguard': 'admin/secubox/network/wireguard/overview',
|
||||
'network_modes': 'admin/secubox/network/network-modes/overview',
|
||||
'client_guardian': 'admin/secubox/security/client-guardian/overview',
|
||||
'system_hub': 'admin/secubox/system/system-hub/overview',
|
||||
'bandwidth_manager': 'admin/secubox/network/bandwidth-manager/overview',
|
||||
'auth_guardian': 'admin/secubox/security/auth-guardian/overview',
|
||||
'media_flow': 'admin/secubox/monitoring/mediaflow/dashboard',
|
||||
'vhost_manager': 'admin/secubox/services/vhosts/overview',
|
||||
'traffic_shaper': 'admin/secubox/network/traffic-shaper/overview',
|
||||
'cdn_cache': 'admin/secubox/network/cdn-cache/overview',
|
||||
'ksm_manager': 'admin/secubox/security/ksm-manager/overview'
|
||||
'crowdsec': 'admin/secubox/crowdsec/overview',
|
||||
'netdata': 'admin/secubox/netdata/dashboard',
|
||||
'netifyd': 'admin/secubox/netifyd/overview',
|
||||
'wireguard': 'admin/secubox/wireguard/overview',
|
||||
'network_modes': 'admin/secubox/network-modes/overview',
|
||||
'client_guardian': 'admin/secubox/client-guardian/overview',
|
||||
'system_hub': 'admin/secubox/system-hub/overview',
|
||||
'bandwidth_manager': 'admin/secubox/bandwidth-manager/overview',
|
||||
'auth_guardian': 'admin/secubox/auth-guardian/overview',
|
||||
'media_flow': 'admin/secubox/mediaflow/dashboard',
|
||||
'vhost_manager': 'admin/secubox/vhosts/overview',
|
||||
'traffic_shaper': 'admin/secubox/traffic-shaper/overview',
|
||||
'cdn_cache': 'admin/secubox/cdn-cache/overview',
|
||||
'ksm_manager': 'admin/secubox/ksm-manager/overview'
|
||||
};
|
||||
|
||||
var moduleCards = filteredModules.map(function(module) {
|
||||
|
||||
@ -0,0 +1,203 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require dom';
|
||||
'require secubox/api as API';
|
||||
'require secubox/help as Help';
|
||||
'require secubox/theme as Theme';
|
||||
|
||||
// Ensure SecuBox theme variables are loaded for this view
|
||||
Theme.init();
|
||||
|
||||
// Load base SecuBox + help styles
|
||||
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/help.css')
|
||||
}));
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return API.getStatus();
|
||||
},
|
||||
|
||||
render: function(status) {
|
||||
var data = status || {};
|
||||
var helpPages = Help.getAllHelpPages();
|
||||
|
||||
return E('div', { 'class': 'secubox-help-page' }, [
|
||||
this.renderHero(data),
|
||||
this.renderHelpCatalog(helpPages),
|
||||
this.renderSupportSection(),
|
||||
this.renderFooter()
|
||||
]);
|
||||
},
|
||||
|
||||
renderHero: function(status) {
|
||||
return E('div', { 'class': 'secubox-card secubox-help-hero' }, [
|
||||
E('div', { 'class': 'secubox-help-hero-text' }, [
|
||||
E('span', { 'class': 'secubox-help-eyebrow' }, _('Bonus Tab')),
|
||||
E('h2', {}, _('Help à SecuBox')),
|
||||
E('p', { 'class': 'secubox-help-subtitle' },
|
||||
_('Retrouvez la documentation, les guides et toutes les façons de soutenir la suite SecuBox.')),
|
||||
E('div', { 'class': 'secubox-help-hero-stats' }, [
|
||||
this.renderHeroStat('📦', _('Modules Couvert•e•s'), Object.keys(Help.getAllHelpPages()).length),
|
||||
this.renderHeroStat('⚙️', _('Version Actuelle'), status.version || 'v1.0.0'),
|
||||
this.renderHeroStat('🌐', _('Site Officiel'), 'secubox.cybermood.eu')
|
||||
])
|
||||
]),
|
||||
E('div', { 'class': 'secubox-help-hero-actions' }, [
|
||||
Help.createHelpButton('secubox', 'header', {
|
||||
icon: '📚',
|
||||
label: _('Ouvrir la knowledge base'),
|
||||
modal: true
|
||||
}),
|
||||
E('a', {
|
||||
'class': 'sb-help-btn sb-help-header secubox-help-cta',
|
||||
'href': 'https://secubox.cybermood.eu/#contact',
|
||||
'target': '_blank'
|
||||
}, [
|
||||
E('span', { 'class': 'sb-help-icon' }, '🤝'),
|
||||
E('span', { 'class': 'sb-help-label' }, _('Contacter SecuBox'))
|
||||
])
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
renderHeroStat: function(icon, label, value) {
|
||||
return E('div', { 'class': 'secubox-help-hero-stat' }, [
|
||||
E('div', { 'class': 'secubox-help-hero-stat-icon' }, icon),
|
||||
E('div', { 'class': 'secubox-help-hero-stat-value' }, value),
|
||||
E('div', { 'class': 'secubox-help-hero-stat-label' }, label)
|
||||
]);
|
||||
},
|
||||
|
||||
renderHelpCatalog: function(pages) {
|
||||
var self = this;
|
||||
var entries = Object.keys(pages || {});
|
||||
|
||||
return E('div', { 'class': 'secubox-card' }, [
|
||||
E('div', { 'class': 'secubox-card-title-row' }, [
|
||||
E('h3', { 'class': 'secubox-card-title' }, '📘 ' + _('Documentation Express')),
|
||||
E('span', { 'class': 'secubox-card-hint' },
|
||||
_('Chaque tuile ouvre la doc dédiée dans un nouvel onglet.'))
|
||||
]),
|
||||
E('div', { 'class': 'secubox-help-grid' },
|
||||
entries.map(function(key) {
|
||||
return self.renderHelpCard(key, pages[key]);
|
||||
})
|
||||
)
|
||||
]);
|
||||
},
|
||||
|
||||
renderHelpCard: function(key, url) {
|
||||
var info = this.getModuleInfo(key);
|
||||
|
||||
return E('a', {
|
||||
'class': 'secubox-help-card',
|
||||
'href': url,
|
||||
'target': '_blank'
|
||||
}, [
|
||||
E('div', { 'class': 'secubox-help-card-icon' }, info.icon),
|
||||
E('div', { 'class': 'secubox-help-card-body' }, [
|
||||
E('h4', { 'class': 'secubox-help-card-title' }, info.title),
|
||||
E('p', { 'class': 'secubox-help-card-text' }, info.description || _('Guide officiel et FAQ.'))
|
||||
]),
|
||||
E('span', { 'class': 'secubox-help-card-link' }, _('Voir la doc →'))
|
||||
]);
|
||||
},
|
||||
|
||||
renderSupportSection: function() {
|
||||
var items = [
|
||||
{
|
||||
icon: '💬',
|
||||
title: _('Feedback & idées'),
|
||||
text: _('Partagez vos retours via GitHub Issues ou email pour faire évoluer les modules.')
|
||||
},
|
||||
{
|
||||
icon: '🛠️',
|
||||
title: _('Contribuer au code'),
|
||||
text: _('Forkez le dépôt SecuBox, proposez des améliorations, corrigez des bugs, créez de nouveaux helpers.')
|
||||
},
|
||||
{
|
||||
icon: '🤗',
|
||||
title: _('Soutenir le projet'),
|
||||
text: _('Commandes pro, sponsoring ou partenariats : contactez CyberMind.fr pour renforcer SecuBox.')
|
||||
}
|
||||
];
|
||||
|
||||
return E('div', { 'class': 'secubox-card secubox-help-support' }, [
|
||||
E('h3', { 'class': 'secubox-card-title' }, '🤝 ' + _('Comment aider SecuBox ?')),
|
||||
E('div', { 'class': 'secubox-help-support-grid' },
|
||||
items.map(function(item) {
|
||||
return E('div', { 'class': 'secubox-help-support-item' }, [
|
||||
E('div', { 'class': 'secubox-help-support-icon' }, item.icon),
|
||||
E('div', { 'class': 'secubox-help-support-title' }, item.title),
|
||||
E('p', { 'class': 'secubox-help-support-text' }, item.text)
|
||||
]);
|
||||
})
|
||||
),
|
||||
E('div', { 'class': 'secubox-help-support-actions' }, [
|
||||
Help.createHelpButton('secubox', 'footer', {
|
||||
icon: '💡',
|
||||
label: _('Ouvrir la FAQ')
|
||||
}),
|
||||
E('a', {
|
||||
'class': 'sb-help-btn sb-help-footer',
|
||||
'href': 'mailto:contact@cybermind.fr?subject=SecuBox%20Feedback'
|
||||
}, [
|
||||
E('span', { 'class': 'sb-help-icon' }, '✉️'),
|
||||
E('span', { 'class': 'sb-help-label' }, _('Écrire à l’équipe'))
|
||||
])
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
renderFooter: function() {
|
||||
return E('div', { 'class': 'secubox-help-footer' }, [
|
||||
E('div', { 'class': 'secubox-help-footer-text' },
|
||||
_('Besoin d’un accompagnement premium ? SecuBox peut être intégré, maintenu et personnalisé par CyberMind.fr.')),
|
||||
E('div', { 'class': 'secubox-help-footer-links' }, [
|
||||
E('a', {
|
||||
'href': 'https://secubox.cybermood.eu/',
|
||||
'target': '_blank'
|
||||
}, _('Découvrir le site vitrine')),
|
||||
E('span', { 'class': 'sep' }, '•'),
|
||||
E('a', {
|
||||
'href': 'https://github.com/CyberMindStudio/secubox-openwrt',
|
||||
'target': '_blank'
|
||||
}, _('GitHub SecuBox'))
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
getModuleInfo: function(key) {
|
||||
var titles = {
|
||||
'secubox': { title: _('SecuBox Hub'), icon: '🚀', description: _('Vue d’ensemble, modules et roadmap.') },
|
||||
'system-hub': { title: _('System Hub'), icon: '⚙️', description: _('Surveillance système et diagnostics.') },
|
||||
'network-modes': { title: _('Network Modes'), icon: '🌐', description: _('Guides de bascule et scénarios réseau.') },
|
||||
'client-guardian': { title: _('Client Guardian'), icon: '🛡️', description: _('Portail captif et NAC avancé.') },
|
||||
'bandwidth-manager': { title: _('Bandwidth Manager'), icon: '📶', description: _('QoS, classes et quotas réseau.') },
|
||||
'cdn-cache': { title: _('CDN Cache'), icon: '🗄️', description: _('Cache CDN local et politiques.') },
|
||||
'traffic-shaper': { title: _('Traffic Shaper'), icon: '🌀', description: _('Profils et préréglages QoS.') },
|
||||
'wireguard-dashboard': { title: _('WireGuard Dashboard'), icon: '🛜', description: _('Peers, profils et QR codes.') },
|
||||
'crowdsec-dashboard': { title: _('CrowdSec Dashboard'), icon: '🕵️', description: _('Décisions, bouncers et alertes.') },
|
||||
'netdata-dashboard': { title: _('Netdata Dashboard'), icon: '📊', description: _('Monitoring temps réel Netdata.') },
|
||||
'netifyd-dashboard': { title: _('Netifyd Dashboard'), icon: '🔍', description: _('DPI, flux et risques applications.') },
|
||||
'auth-guardian': { title: _('Auth Guardian'), icon: '🔐', description: _('Auth portail, vouchers et OAuth.') },
|
||||
'vhost-manager': { title: _('VHost Manager'), icon: '🧩', description: _('Virtual hosts, SSL & redirections.') },
|
||||
'ksm-manager': { title: _('KSM Manager'), icon: '🔑', description: _('Gestion clés et secrets sécurisés.') },
|
||||
'media-flow': { title: _('Media Flow'), icon: '🎬', description: _('Analytique streaming & clients.') }
|
||||
};
|
||||
|
||||
var fallbackTitle = key.replace(/-/g, ' ').replace(/\b\w/g, function(c) {
|
||||
return c.toUpperCase();
|
||||
});
|
||||
|
||||
return titles[key] || { title: fallbackTitle, icon: '📦' };
|
||||
}
|
||||
});
|
||||
@ -106,21 +106,30 @@ return view.extend({
|
||||
{ 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);
|
||||
})
|
||||
var filterButtons = 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);
|
||||
});
|
||||
|
||||
filterButtons.push(
|
||||
E('button', {
|
||||
'class': 'secubox-filter-tab secubox-filter-tab-bonus',
|
||||
'click': function() {
|
||||
window.location.href = L.url('admin/secubox/help');
|
||||
}
|
||||
}, '✨ ' + _('Bonus · Help à SecuBox'))
|
||||
);
|
||||
|
||||
return E('div', { 'class': 'secubox-filter-tabs' }, filterButtons);
|
||||
},
|
||||
|
||||
renderModuleCards: function(modules, filter) {
|
||||
@ -256,20 +265,20 @@ return view.extend({
|
||||
|
||||
getModuleDashboardPath: function(moduleId) {
|
||||
var paths = {
|
||||
'crowdsec': 'admin/secubox/security/crowdsec/overview',
|
||||
'netdata': 'admin/secubox/monitoring/netdata/dashboard',
|
||||
'netifyd': 'admin/secubox/security/netifyd/overview',
|
||||
'wireguard': 'admin/secubox/network/wireguard/overview',
|
||||
'network_modes': 'admin/secubox/network/network-modes/overview',
|
||||
'client_guardian': 'admin/secubox/security/client-guardian/overview',
|
||||
'system_hub': 'admin/secubox/system/system-hub/overview',
|
||||
'bandwidth_manager': 'admin/secubox/network/bandwidth-manager/overview',
|
||||
'auth_guardian': 'admin/secubox/security/auth-guardian/overview',
|
||||
'media_flow': 'admin/secubox/monitoring/mediaflow/dashboard',
|
||||
'vhost_manager': 'admin/secubox/services/vhosts/overview',
|
||||
'traffic_shaper': 'admin/secubox/network/traffic-shaper/overview',
|
||||
'cdn_cache': 'admin/secubox/network/cdn-cache/overview',
|
||||
'ksm_manager': 'admin/secubox/security/ksm-manager/overview'
|
||||
'crowdsec': 'admin/secubox/crowdsec/overview',
|
||||
'netdata': 'admin/secubox/netdata/dashboard',
|
||||
'netifyd': 'admin/secubox/netifyd/overview',
|
||||
'wireguard': 'admin/secubox/wireguard/overview',
|
||||
'network_modes': 'admin/secubox/network-modes/overview',
|
||||
'client_guardian': 'admin/secubox/client-guardian/overview',
|
||||
'system_hub': 'admin/secubox/system-hub/overview',
|
||||
'bandwidth_manager': 'admin/secubox/bandwidth-manager/overview',
|
||||
'auth_guardian': 'admin/secubox/auth-guardian/overview',
|
||||
'media_flow': 'admin/secubox/mediaflow/dashboard',
|
||||
'vhost_manager': 'admin/secubox/vhosts/overview',
|
||||
'traffic_shaper': 'admin/secubox/traffic-shaper/overview',
|
||||
'cdn_cache': 'admin/secubox/cdn-cache/overview',
|
||||
'ksm_manager': 'admin/secubox/ksm-manager/overview'
|
||||
};
|
||||
return paths[moduleId] || null;
|
||||
},
|
||||
|
||||
@ -39,11 +39,6 @@
|
||||
"order": 10,
|
||||
"action": {"type": "view", "path": "secubox/monitoring"}
|
||||
},
|
||||
"admin/secubox/network": {
|
||||
"title": "Network Management",
|
||||
"order": 40,
|
||||
"action": {"type": "firstchild"}
|
||||
},
|
||||
"admin/secubox/system": {
|
||||
"title": "System & Performance",
|
||||
"order": 50,
|
||||
@ -53,5 +48,10 @@
|
||||
"title": "Services & Applications",
|
||||
"order": 60,
|
||||
"action": {"type": "firstchild"}
|
||||
},
|
||||
"admin/secubox/help": {
|
||||
"title": "Bonus · Help à SecuBox",
|
||||
"order": 99,
|
||||
"action": {"type": "view", "path": "secubox/help"}
|
||||
}
|
||||
}
|
||||
|
||||
68
scripts/sync_module_versions.py
Executable file
68
scripts/sync_module_versions.py
Executable file
@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Synchronize module versions and website progress bars."""
|
||||
from __future__ import annotations
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import difflib
|
||||
import subprocess
|
||||
|
||||
RE_WEBSITE = re.compile(
|
||||
r'(<div class="module-progress-fill" style="width:)([0-9.]+)(%;"></div>\s*</div>\s*<div class="module-progress-label">v)'
|
||||
r'([0-9]+\.[0-9]+\.[0-9]+)(?:\s*·\s*)([0-9.]+)(\s*/ 1.00</div>)'
|
||||
)
|
||||
|
||||
|
||||
def version_ratio(ver: str) -> float:
|
||||
major, minor, patch = map(int, ver.split('.'))
|
||||
return major + minor / 10 + patch / 100
|
||||
|
||||
|
||||
def update_website(html: Path) -> bool:
|
||||
text = html.read_text()
|
||||
|
||||
def repl(match: re.Match) -> str:
|
||||
ver = match.group(4)
|
||||
ratio = version_ratio(ver)
|
||||
width = f"{ratio * 100:.0f}".rstrip('0').rstrip('.')
|
||||
label = f"{ratio:.2f}".rstrip('0').rstrip('.')
|
||||
return f"{match.group(1)}{width}{match.group(3)}{ver} · {label}{match.group(6)}"
|
||||
|
||||
new_text, count = RE_WEBSITE.subn(repl, text)
|
||||
if count:
|
||||
if new_text == text:
|
||||
return False
|
||||
diff = difflib.unified_diff(
|
||||
text.splitlines(keepends=True),
|
||||
new_text.splitlines(keepends=True),
|
||||
fromfile=str(html),
|
||||
tofile=str(html)
|
||||
)
|
||||
diff_text = ''.join(diff)
|
||||
if not diff_text:
|
||||
return False
|
||||
subprocess.run(['patch', str(html)], input=diff_text.encode(), check=True)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def main() -> int:
|
||||
repo_root = Path(__file__).resolve().parents[1]
|
||||
site_dir = repo_root.parent / 'secubox-website'
|
||||
|
||||
targets = [site_dir / 'index.html', site_dir / 'campaign.html']
|
||||
overall = False
|
||||
|
||||
for html in targets:
|
||||
if not html.exists():
|
||||
print(f'Skipping missing file: {html}', file=sys.stderr)
|
||||
continue
|
||||
if update_website(html):
|
||||
print(f'Updated {html.name}')
|
||||
overall = True
|
||||
|
||||
print('Website progress sync', 'done' if overall else 'no changes')
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main())
|
||||
6
scripts/sync_module_versions.sh
Executable file
6
scripts/sync_module_versions.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
SCR="$REPO_ROOT/scripts/sync_module_versions.py"
|
||||
|
||||
python3 "$SCR"
|
||||
99
secubox-tools/deploy-website.sh
Executable file
99
secubox-tools/deploy-website.sh
Executable file
@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env bash
|
||||
# Deploy SecuBox website to an OpenWrt router.
|
||||
# Usage: ./secubox-tools/deploy-website.sh [root@192.168.1.1] [/path/to/website]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
ROUTER_HOST="${1:-root@192.168.8.191}"
|
||||
WEBSITE_PATH="${2:-}"
|
||||
TARGET_DIR="/www/luci-static/secubox"
|
||||
|
||||
# Determine website source path
|
||||
if [[ -z "$WEBSITE_PATH" ]]; then
|
||||
# Check common locations
|
||||
COMMON_PATHS=(
|
||||
"$REPO_ROOT/../secubox-website"
|
||||
"$HOME/CyberMindStudio/_files/secubox-website"
|
||||
"./secubox-website"
|
||||
)
|
||||
|
||||
for path in "${COMMON_PATHS[@]}"; do
|
||||
if [[ -d "$path" ]]; then
|
||||
WEBSITE_PATH="$path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -z "$WEBSITE_PATH" ]]; then
|
||||
echo "ERROR: Website directory not found. Please specify path as second argument." >&2
|
||||
echo "Usage: $0 [router_host] [website_path]" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ! -d "$WEBSITE_PATH" ]]; then
|
||||
echo "ERROR: Website directory not found: $WEBSITE_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[1/4] Preparing website files from $WEBSITE_PATH…" >&2
|
||||
|
||||
# Create tarball excluding unnecessary files
|
||||
TARBALL="/tmp/secubox-website-$(date +%s).tar.gz"
|
||||
(cd "$WEBSITE_PATH" && tar czf "$TARBALL" \
|
||||
--exclude='.git' \
|
||||
--exclude='.claude' \
|
||||
--exclude='*.md' \
|
||||
--exclude='.gitignore' \
|
||||
--exclude='README*' \
|
||||
--exclude='LICENSE' \
|
||||
.)
|
||||
|
||||
echo "[2/4] Uploading website files to $ROUTER_HOST:$TARGET_DIR/" >&2
|
||||
scp "$TARBALL" "${ROUTER_HOST}:/tmp/secubox-website.tar.gz"
|
||||
|
||||
echo "[3/4] Deploying website on router…" >&2
|
||||
ssh "$ROUTER_HOST" "sh -s" <<EOF
|
||||
set -e
|
||||
|
||||
# Create target directory
|
||||
mkdir -p "$TARGET_DIR"
|
||||
|
||||
# Backup existing website if present
|
||||
if [ -d "$TARGET_DIR" ] && [ "\$(ls -A $TARGET_DIR)" ]; then
|
||||
BACKUP_DIR="/tmp/secubox-website-backup-\$(date +%s)"
|
||||
echo "[router] Creating backup at \$BACKUP_DIR…" >&2
|
||||
mkdir -p "\$BACKUP_DIR"
|
||||
cp -a "$TARGET_DIR"/* "\$BACKUP_DIR/" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Extract new website
|
||||
echo "[router] Extracting website files…" >&2
|
||||
cd "$TARGET_DIR"
|
||||
tar xzf /tmp/secubox-website.tar.gz
|
||||
|
||||
# Set proper permissions
|
||||
chmod 755 "$TARGET_DIR"
|
||||
find "$TARGET_DIR" -type d -exec chmod 755 {} \;
|
||||
find "$TARGET_DIR" -type f -name "*.html" -exec chmod 644 {} \;
|
||||
find "$TARGET_DIR" -type f -name "*.js" -exec chmod 644 {} \;
|
||||
find "$TARGET_DIR" -type f -name "*.css" -exec chmod 644 {} \; 2>/dev/null || true
|
||||
|
||||
# Clean up
|
||||
rm -f /tmp/secubox-website.tar.gz
|
||||
|
||||
echo "[router] Website deployed to $TARGET_DIR"
|
||||
echo "[router] Access URL: http://\$(uci get network.lan.ipaddress 2>/dev/null || echo 'router-ip')/luci-static/secubox/"
|
||||
EOF
|
||||
|
||||
echo "[4/4] Cleaning up local tarball…" >&2
|
||||
rm -f "$TARBALL"
|
||||
|
||||
echo ""
|
||||
echo "✓ Website deployment completed successfully!"
|
||||
echo " Target: $ROUTER_HOST:$TARGET_DIR"
|
||||
echo " Files: $(find "$WEBSITE_PATH" -type f \( -name "*.html" -o -name "*.js" \) | wc -l) files deployed"
|
||||
echo ""
|
||||
Loading…
Reference in New Issue
Block a user