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
|
## Repository Layout
|
||||||
**Type**: Modular security suite for OpenWrt routers
|
- `.claude/` – authoritative assistant guidance, prompts, and settings
|
||||||
**Version**: 1.0.0
|
- `.github/workflows/` – CI definitions (package build matrix, validation, firmware images)
|
||||||
**Author**: CyberMind.fr (Gandalf)
|
- `luci-app-*/` – one directory per LuCI module (Makefile, README, `htdocs/`, `root/`)
|
||||||
**License**: Apache-2.0
|
- `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/`.
|
||||||
|
|
||||||
```
|
| Module | Purpose | Primary Views (JS) |
|
||||||
┌─────────────────────────────────────────────────────────────┐
|
|--------|---------|--------------------|
|
||||||
│ LuCI Web Interface │
|
| `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`
|
||||||
│ │ View.js │ │ View.js │ │ View.js │ │ View.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`
|
||||||
│ │ JSON-RPC │
|
| `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`
|
||||||
│ RPCD Daemon │
|
| `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`
|
||||||
│ │ Script │ │ Script │ │ Script │ │ Script │ ... │
|
| `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`
|
||||||
│ │ UCI │ Shell │ System │ │
|
| `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`
|
||||||
│ │ Config │ Commands │ Services │ │
|
|
||||||
└───────┴───────────┴───────────┴───────────┴─────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📁 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.)
|
||||||
|
|
||||||
```
|
## Stack & Integration Points
|
||||||
luci-app-{module-name}/
|
- **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`.
|
||||||
├── Makefile # OpenWrt package definition
|
- **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/`.
|
||||||
├── README.md # Module documentation
|
- **UBus / RPC**: JavaScript uses `rpc.declare` with `object: 'luci.<module>'`. RPCD `list` and `call` cases must mirror these names.
|
||||||
├── htdocs/
|
- **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.
|
||||||
│ └── luci-static/
|
- **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.
|
||||||
│ └── 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📋 Naming Conventions
|
## Glossary
|
||||||
|
- **LuCI** – OpenWrt web interface framework (Lua backend + JS frontend)
|
||||||
| Context | Format | Example |
|
- **RPCD** – Daemon providing ubus RPC endpoints; modules drop scripts in `/usr/libexec/rpcd/`
|
||||||
|---------|--------|---------|
|
- **ubus** – OpenWrt message bus used for remote procedure calls
|
||||||
| Package name | luci-app-{module-name} | luci-app-vhost-manager |
|
- **UCI** – Unified Configuration Interface (files in `/etc/config/`)
|
||||||
| RPCD script | {module-name} | vhost-manager |
|
- **ACL** – RPCD permission JSON files in `/usr/share/rpcd/acl.d/`
|
||||||
| UCI config | {module_name} | vhost_manager |
|
- **PKG_FILE_MODES** – Makefile variable forcing specific permissions for installed files
|
||||||
| View path | {module_name}/ | vhost_manager/ |
|
- **SecuBox Design System** – Shared CSS variables (`--sh-*`) and components defined in `system-hub/common.css`
|
||||||
| ubus object | luci.{module-name} | luci.vhost-manager |
|
- **Validation suite** – `./secubox-tools/validate-modules.sh`, `validate-module-generation.sh`, `pre-push-validation.sh`
|
||||||
| Menu path | admin/services/{module_name} | admin/services/vhost_manager |
|
- **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
|
||||||
## 🔧 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
|
|
||||||
```
|
|
||||||
|
|
||||||
### ACL File Template
|
### 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`
|
- **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`
|
- **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)
|
- **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
|
- **Use Cases**: Traffic analysis, bandwidth optimization, security monitoring
|
||||||
|
|
||||||
#### luci-app-network-modes
|
#### luci-app-network-modes
|
||||||
- **Version**: 0.3.1-1
|
- **Version**: 0.3.5-1
|
||||||
- **Status**: ✅ In Heavily Development Stage
|
- **Status**: ✅ Production Ready
|
||||||
- **Description**: Dynamic network mode switching and configuration
|
- **Description**: Dynamic network mode switching and configuration
|
||||||
- **Views**: 7 (overview, wizard, router, relay, accesspoint, sniffer, settings)
|
- **Views**: 7 (overview, wizard, router, relay, accesspoint, sniffer, settings)
|
||||||
- **JavaScript Lines**: 2,104
|
- **JavaScript Lines**: 2,104
|
||||||
@ -171,8 +171,8 @@
|
|||||||
- DHCP server/client mode switching
|
- DHCP server/client mode switching
|
||||||
- Interface bridging automation
|
- Interface bridging automation
|
||||||
- **Recent Updates**:
|
- **Recent Updates**:
|
||||||
- v0.3.1: Enhanced mode switching logic
|
- v0.3.5: Auto-deploy proxies (Squid/TinyProxy/Privoxy), DoH, nginx vhosts, and Let’s Encrypt certificates
|
||||||
- Improved configuration persistence
|
- Auto-apply advanced WiFi (802.11r/k/v, band steering) and tcpdump packet capture per mode
|
||||||
- **Integration**: network, firewall, DHCP, hostapd/wpa_supplicant
|
- **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 dom';
|
||||||
'require ui';
|
'require ui';
|
||||||
'require network-modes.api as api';
|
'require network-modes.api as api';
|
||||||
|
'require secubox/help as Help';
|
||||||
|
|
||||||
return view.extend({
|
return view.extend({
|
||||||
title: _('Network Modes'),
|
title: _('Network Modes'),
|
||||||
@ -62,6 +63,9 @@ return view.extend({
|
|||||||
var currentModeInfo = modeInfos[currentMode];
|
var currentModeInfo = modeInfos[currentMode];
|
||||||
|
|
||||||
var view = E('div', { 'class': 'network-modes-dashboard' }, [
|
var view = E('div', { 'class': 'network-modes-dashboard' }, [
|
||||||
|
// Load help CSS
|
||||||
|
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox/help.css') }),
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
E('div', { 'class': 'nm-header' }, [
|
E('div', { 'class': 'nm-header' }, [
|
||||||
E('div', { 'class': 'nm-logo' }, [
|
E('div', { 'class': 'nm-logo' }, [
|
||||||
@ -71,7 +75,11 @@ return view.extend({
|
|||||||
E('div', { 'class': 'nm-mode-badge ' + currentMode }, [
|
E('div', { 'class': 'nm-mode-badge ' + currentMode }, [
|
||||||
E('span', { 'class': 'nm-mode-dot' }),
|
E('span', { 'class': 'nm-mode-dot' }),
|
||||||
currentModeInfo ? currentModeInfo.name : currentMode
|
currentModeInfo ? currentModeInfo.name : currentMode
|
||||||
])
|
]),
|
||||||
|
Help.createHelpButton('network-modes', 'header', {
|
||||||
|
icon: '📖',
|
||||||
|
label: _('Help')
|
||||||
|
})
|
||||||
]),
|
]),
|
||||||
|
|
||||||
// Current Mode Display Card
|
// Current Mode Display Card
|
||||||
|
|||||||
@ -448,8 +448,8 @@ apply_mode() {
|
|||||||
apply_accesspoint_features
|
apply_accesspoint_features
|
||||||
;;
|
;;
|
||||||
|
|
||||||
relay)
|
relay)
|
||||||
# Repeater mode: STA + AP relay
|
# Repeater mode: STA + AP relay
|
||||||
# Client interface (sta)
|
# Client interface (sta)
|
||||||
uci set network.wwan=interface
|
uci set network.wwan=interface
|
||||||
uci set network.wwan.proto='dhcp'
|
uci set network.wwan.proto='dhcp'
|
||||||
@ -465,12 +465,41 @@ apply_mode() {
|
|||||||
uci set network.stabridge.proto='relay'
|
uci set network.stabridge.proto='relay'
|
||||||
uci set network.stabridge.network='lan wwan'
|
uci set network.stabridge.network='lan wwan'
|
||||||
|
|
||||||
apply_wireguard_config
|
apply_wireguard_config
|
||||||
apply_mtu_clamping
|
apply_mtu_clamping
|
||||||
enable_tcp_bbr
|
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
|
# Pure L2 bridge: all interfaces bridged, DHCP client
|
||||||
uci delete network.wan 2>/dev/null
|
uci delete network.wan 2>/dev/null
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"admin/secubox/network/network-modes": {
|
"admin/secubox/network-modes": {
|
||||||
"title": "Network Modes",
|
"title": "Network Modes",
|
||||||
"order": 20,
|
"order": 20,
|
||||||
"action": {
|
"action": {
|
||||||
@ -9,7 +9,7 @@
|
|||||||
"acl": ["luci-app-network-modes"]
|
"acl": ["luci-app-network-modes"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin/secubox/network/network-modes/overview": {
|
"admin/secubox/network-modes/overview": {
|
||||||
"title": "Overview",
|
"title": "Overview",
|
||||||
"order": 10,
|
"order": 10,
|
||||||
"action": {
|
"action": {
|
||||||
@ -17,7 +17,7 @@
|
|||||||
"path": "network-modes/overview"
|
"path": "network-modes/overview"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin/secubox/network/network-modes/wizard": {
|
"admin/secubox/network-modes/wizard": {
|
||||||
"title": "Mode Wizard",
|
"title": "Mode Wizard",
|
||||||
"order": 20,
|
"order": 20,
|
||||||
"action": {
|
"action": {
|
||||||
@ -25,7 +25,7 @@
|
|||||||
"path": "network-modes/wizard"
|
"path": "network-modes/wizard"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin/secubox/network/network-modes/router": {
|
"admin/secubox/network-modes/router": {
|
||||||
"title": "Router Mode",
|
"title": "Router Mode",
|
||||||
"order": 30,
|
"order": 30,
|
||||||
"action": {
|
"action": {
|
||||||
@ -33,7 +33,7 @@
|
|||||||
"path": "network-modes/router"
|
"path": "network-modes/router"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin/secubox/network/network-modes/accesspoint": {
|
"admin/secubox/network-modes/accesspoint": {
|
||||||
"title": "Access Point Mode",
|
"title": "Access Point Mode",
|
||||||
"order": 40,
|
"order": 40,
|
||||||
"action": {
|
"action": {
|
||||||
@ -41,7 +41,7 @@
|
|||||||
"path": "network-modes/accesspoint"
|
"path": "network-modes/accesspoint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin/secubox/network/network-modes/relay": {
|
"admin/secubox/network-modes/relay": {
|
||||||
"title": "Relay Mode",
|
"title": "Relay Mode",
|
||||||
"order": 50,
|
"order": 50,
|
||||||
"action": {
|
"action": {
|
||||||
@ -49,7 +49,7 @@
|
|||||||
"path": "network-modes/relay"
|
"path": "network-modes/relay"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin/secubox/network/network-modes/sniffer": {
|
"admin/secubox/network-modes/sniffer": {
|
||||||
"title": "Sniffer Mode",
|
"title": "Sniffer Mode",
|
||||||
"order": 60,
|
"order": 60,
|
||||||
"action": {
|
"action": {
|
||||||
@ -57,7 +57,7 @@
|
|||||||
"path": "network-modes/sniffer"
|
"path": "network-modes/sniffer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin/secubox/network/network-modes/settings": {
|
"admin/secubox/network-modes/settings": {
|
||||||
"title": "Settings",
|
"title": "Settings",
|
||||||
"order": 90,
|
"order": 90,
|
||||||
"action": {
|
"action": {
|
||||||
|
|||||||
@ -244,6 +244,18 @@
|
|||||||
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
|
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 {
|
.secubox-tab-icon {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 1;
|
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;
|
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 */
|
/* Modules Grid */
|
||||||
.secubox-modules-grid {
|
.secubox-modules-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@ -345,6 +345,228 @@
|
|||||||
font-style: italic;
|
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 */
|
/* Responsive Design */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.secubox-health-grid {
|
.secubox-health-grid {
|
||||||
@ -358,4 +580,24 @@
|
|||||||
.secubox-modules-grid {
|
.secubox-modules-grid {
|
||||||
grid-template-columns: 1fr;
|
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
|
// Map module IDs to their dashboard paths
|
||||||
var modulePaths = {
|
var modulePaths = {
|
||||||
'crowdsec': 'admin/secubox/security/crowdsec/overview',
|
'crowdsec': 'admin/secubox/crowdsec/overview',
|
||||||
'netdata': 'admin/secubox/monitoring/netdata/dashboard',
|
'netdata': 'admin/secubox/netdata/dashboard',
|
||||||
'netifyd': 'admin/secubox/security/netifyd/overview',
|
'netifyd': 'admin/secubox/netifyd/overview',
|
||||||
'wireguard': 'admin/secubox/network/wireguard/overview',
|
'wireguard': 'admin/secubox/wireguard/overview',
|
||||||
'network_modes': 'admin/secubox/network/network-modes/overview',
|
'network_modes': 'admin/secubox/network-modes/overview',
|
||||||
'client_guardian': 'admin/secubox/security/client-guardian/overview',
|
'client_guardian': 'admin/secubox/client-guardian/overview',
|
||||||
'system_hub': 'admin/secubox/system/system-hub/overview',
|
'system_hub': 'admin/secubox/system-hub/overview',
|
||||||
'bandwidth_manager': 'admin/secubox/network/bandwidth-manager/overview',
|
'bandwidth_manager': 'admin/secubox/bandwidth-manager/overview',
|
||||||
'auth_guardian': 'admin/secubox/security/auth-guardian/overview',
|
'auth_guardian': 'admin/secubox/auth-guardian/overview',
|
||||||
'media_flow': 'admin/secubox/monitoring/mediaflow/dashboard',
|
'media_flow': 'admin/secubox/mediaflow/dashboard',
|
||||||
'vhost_manager': 'admin/secubox/services/vhosts/overview',
|
'vhost_manager': 'admin/secubox/vhosts/overview',
|
||||||
'traffic_shaper': 'admin/secubox/network/traffic-shaper/overview',
|
'traffic_shaper': 'admin/secubox/traffic-shaper/overview',
|
||||||
'cdn_cache': 'admin/secubox/network/cdn-cache/overview',
|
'cdn_cache': 'admin/secubox/cdn-cache/overview',
|
||||||
'ksm_manager': 'admin/secubox/security/ksm-manager/overview'
|
'ksm_manager': 'admin/secubox/ksm-manager/overview'
|
||||||
};
|
};
|
||||||
|
|
||||||
var moduleCards = filteredModules.map(function(module) {
|
var moduleCards = filteredModules.map(function(module) {
|
||||||
@ -302,22 +302,34 @@ return view.extend({
|
|||||||
{ id: 'monitoring', label: 'Monitoring', icon: '📊' }
|
{ id: 'monitoring', label: 'Monitoring', icon: '📊' }
|
||||||
];
|
];
|
||||||
|
|
||||||
var filterTabs = E('div', { 'class': 'secubox-filter-tabs' },
|
var filterTabButtons = filters.map(function(filter) {
|
||||||
filters.map(function(filter) {
|
var isActive = self.activeFilter === filter.id;
|
||||||
var isActive = self.activeFilter === filter.id;
|
return E('div', {
|
||||||
return E('div', {
|
'class': 'secubox-filter-tab' + (isActive ? ' active' : ''),
|
||||||
'class': 'secubox-filter-tab' + (isActive ? ' active' : ''),
|
'click': function() {
|
||||||
'click': function() {
|
self.activeFilter = filter.id;
|
||||||
self.activeFilter = filter.id;
|
self.updateModulesGrid();
|
||||||
self.updateModulesGrid();
|
}
|
||||||
}
|
}, [
|
||||||
}, [
|
E('span', { 'class': 'secubox-tab-icon' }, filter.icon),
|
||||||
E('span', { 'class': 'secubox-tab-icon' }, filter.icon),
|
E('span', { 'class': 'secubox-tab-label' }, filter.label)
|
||||||
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' }, [
|
return E('div', { 'class': 'secubox-card' }, [
|
||||||
E('h3', { 'class': 'secubox-card-title' }, '🎯 Active Modules (' + activeModules.length + ')'),
|
E('h3', { 'class': 'secubox-card-title' }, '🎯 Active Modules (' + activeModules.length + ')'),
|
||||||
filterTabs,
|
filterTabs,
|
||||||
@ -359,20 +371,20 @@ return view.extend({
|
|||||||
|
|
||||||
// Map module IDs to their dashboard paths
|
// Map module IDs to their dashboard paths
|
||||||
var modulePaths = {
|
var modulePaths = {
|
||||||
'crowdsec': 'admin/secubox/security/crowdsec/overview',
|
'crowdsec': 'admin/secubox/crowdsec/overview',
|
||||||
'netdata': 'admin/secubox/monitoring/netdata/dashboard',
|
'netdata': 'admin/secubox/netdata/dashboard',
|
||||||
'netifyd': 'admin/secubox/security/netifyd/overview',
|
'netifyd': 'admin/secubox/netifyd/overview',
|
||||||
'wireguard': 'admin/secubox/network/wireguard/overview',
|
'wireguard': 'admin/secubox/wireguard/overview',
|
||||||
'network_modes': 'admin/secubox/network/network-modes/overview',
|
'network_modes': 'admin/secubox/network-modes/overview',
|
||||||
'client_guardian': 'admin/secubox/security/client-guardian/overview',
|
'client_guardian': 'admin/secubox/client-guardian/overview',
|
||||||
'system_hub': 'admin/secubox/system/system-hub/overview',
|
'system_hub': 'admin/secubox/system-hub/overview',
|
||||||
'bandwidth_manager': 'admin/secubox/network/bandwidth-manager/overview',
|
'bandwidth_manager': 'admin/secubox/bandwidth-manager/overview',
|
||||||
'auth_guardian': 'admin/secubox/security/auth-guardian/overview',
|
'auth_guardian': 'admin/secubox/auth-guardian/overview',
|
||||||
'media_flow': 'admin/secubox/monitoring/mediaflow/dashboard',
|
'media_flow': 'admin/secubox/mediaflow/dashboard',
|
||||||
'vhost_manager': 'admin/secubox/services/vhosts/overview',
|
'vhost_manager': 'admin/secubox/vhosts/overview',
|
||||||
'traffic_shaper': 'admin/secubox/network/traffic-shaper/overview',
|
'traffic_shaper': 'admin/secubox/traffic-shaper/overview',
|
||||||
'cdn_cache': 'admin/secubox/network/cdn-cache/overview',
|
'cdn_cache': 'admin/secubox/cdn-cache/overview',
|
||||||
'ksm_manager': 'admin/secubox/security/ksm-manager/overview'
|
'ksm_manager': 'admin/secubox/ksm-manager/overview'
|
||||||
};
|
};
|
||||||
|
|
||||||
var moduleCards = filteredModules.map(function(module) {
|
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: '⚙️' }
|
{ id: 'system', label: 'System', icon: '⚙️' }
|
||||||
];
|
];
|
||||||
|
|
||||||
return E('div', { 'class': 'secubox-filter-tabs' },
|
var filterButtons = tabs.map(function(tab) {
|
||||||
tabs.map(function(tab) {
|
return E('button', {
|
||||||
return E('button', {
|
'class': 'secubox-filter-tab' + (tab.id === 'all' ? ' active' : ''),
|
||||||
'class': 'secubox-filter-tab' + (tab.id === 'all' ? ' active' : ''),
|
'data-filter': tab.id,
|
||||||
'data-filter': tab.id,
|
'click': function(ev) {
|
||||||
'click': function(ev) {
|
document.querySelectorAll('.secubox-filter-tab').forEach(function(el) {
|
||||||
document.querySelectorAll('.secubox-filter-tab').forEach(function(el) {
|
el.classList.remove('active');
|
||||||
el.classList.remove('active');
|
});
|
||||||
});
|
ev.target.classList.add('active');
|
||||||
ev.target.classList.add('active');
|
self.filterModules(tab.id);
|
||||||
self.filterModules(tab.id);
|
}
|
||||||
}
|
}, tab.icon + ' ' + tab.label);
|
||||||
}, 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) {
|
renderModuleCards: function(modules, filter) {
|
||||||
@ -256,20 +265,20 @@ return view.extend({
|
|||||||
|
|
||||||
getModuleDashboardPath: function(moduleId) {
|
getModuleDashboardPath: function(moduleId) {
|
||||||
var paths = {
|
var paths = {
|
||||||
'crowdsec': 'admin/secubox/security/crowdsec/overview',
|
'crowdsec': 'admin/secubox/crowdsec/overview',
|
||||||
'netdata': 'admin/secubox/monitoring/netdata/dashboard',
|
'netdata': 'admin/secubox/netdata/dashboard',
|
||||||
'netifyd': 'admin/secubox/security/netifyd/overview',
|
'netifyd': 'admin/secubox/netifyd/overview',
|
||||||
'wireguard': 'admin/secubox/network/wireguard/overview',
|
'wireguard': 'admin/secubox/wireguard/overview',
|
||||||
'network_modes': 'admin/secubox/network/network-modes/overview',
|
'network_modes': 'admin/secubox/network-modes/overview',
|
||||||
'client_guardian': 'admin/secubox/security/client-guardian/overview',
|
'client_guardian': 'admin/secubox/client-guardian/overview',
|
||||||
'system_hub': 'admin/secubox/system/system-hub/overview',
|
'system_hub': 'admin/secubox/system-hub/overview',
|
||||||
'bandwidth_manager': 'admin/secubox/network/bandwidth-manager/overview',
|
'bandwidth_manager': 'admin/secubox/bandwidth-manager/overview',
|
||||||
'auth_guardian': 'admin/secubox/security/auth-guardian/overview',
|
'auth_guardian': 'admin/secubox/auth-guardian/overview',
|
||||||
'media_flow': 'admin/secubox/monitoring/mediaflow/dashboard',
|
'media_flow': 'admin/secubox/mediaflow/dashboard',
|
||||||
'vhost_manager': 'admin/secubox/services/vhosts/overview',
|
'vhost_manager': 'admin/secubox/vhosts/overview',
|
||||||
'traffic_shaper': 'admin/secubox/network/traffic-shaper/overview',
|
'traffic_shaper': 'admin/secubox/traffic-shaper/overview',
|
||||||
'cdn_cache': 'admin/secubox/network/cdn-cache/overview',
|
'cdn_cache': 'admin/secubox/cdn-cache/overview',
|
||||||
'ksm_manager': 'admin/secubox/security/ksm-manager/overview'
|
'ksm_manager': 'admin/secubox/ksm-manager/overview'
|
||||||
};
|
};
|
||||||
return paths[moduleId] || null;
|
return paths[moduleId] || null;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -39,11 +39,6 @@
|
|||||||
"order": 10,
|
"order": 10,
|
||||||
"action": {"type": "view", "path": "secubox/monitoring"}
|
"action": {"type": "view", "path": "secubox/monitoring"}
|
||||||
},
|
},
|
||||||
"admin/secubox/network": {
|
|
||||||
"title": "Network Management",
|
|
||||||
"order": 40,
|
|
||||||
"action": {"type": "firstchild"}
|
|
||||||
},
|
|
||||||
"admin/secubox/system": {
|
"admin/secubox/system": {
|
||||||
"title": "System & Performance",
|
"title": "System & Performance",
|
||||||
"order": 50,
|
"order": 50,
|
||||||
@ -53,5 +48,10 @@
|
|||||||
"title": "Services & Applications",
|
"title": "Services & Applications",
|
||||||
"order": 60,
|
"order": 60,
|
||||||
"action": {"type": "firstchild"}
|
"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