'use strict'; 'require baseclass'; /** * SecuBox Development Status Widget v2.1 * Dynamic + Interactive Architecture Dashboard * Features → Components → Submodules + Interconnections * - Live data from RPCD (no auth required for read-only) * - LocalStorage for filter persistence * - Auto-refresh capability * - ES5 compatible for older browsers * Generated from DEV-STATUS.md - 2026-03-09 */ var DevStatusWidget = { targetVersion: '1.0.0', lastUpdate: '2026-03-16', totalPackages: 190, refreshInterval: null, refreshSeconds: 60, activeFilters: { layer: null, status: null, category: null }, // ============================================================ // ARCHITECTURE: 4 LAYERS // ============================================================ layers: { 'core': { id: 'core', name: 'Couche 1: Core Mesh', description: 'Infrastructure fondamentale: reverse proxy, WAF, DNS, containers', progress: 98, icon: '🏗️', color: '#10b981', order: 1 }, 'ai': { id: 'ai', name: 'Couche 2: AI Gateway', description: 'Intelligence artificielle: inference, agents, mémoire contextuelle', progress: 95, icon: '🤖', color: '#8b5cf6', order: 2 }, 'mirrornet': { id: 'mirrornet', name: 'Couche 3: MirrorNet P2P', description: 'Réseau maillé: identité, gossip, partage IOC, mirroring', progress: 90, icon: '🌐', color: '#06b6d4', order: 3 }, 'certification': { id: 'certification', name: 'Couche 4: Certification', description: 'Conformité: ANSSI CSPN, CRA, audit sécurité', progress: 75, icon: '🏆', color: '#f59e0b', order: 4 } }, // ============================================================ // FEATURES: Major functional areas // ============================================================ features: { // === SECURITY === 'intrusion-prevention': { id: 'intrusion-prevention', name: 'Intrusion Prevention', layer: 'core', category: 'security', status: 'production', progress: 95, icon: '🛡️', description: 'Détection et blocage des menaces en temps réel', components: ['crowdsec', 'firewall-bouncer', 'wazuh'], dependsOn: ['network-stack'], usedBy: ['threat-intelligence', 'ai-security'] }, 'waf': { id: 'waf', name: 'Web Application Firewall', layer: 'core', category: 'security', status: 'production', progress: 90, icon: '🔥', description: 'Inspection HTTP/HTTPS, détection bots, analytics', components: ['mitmproxy', 'haproxy-router', 'analytics'], dependsOn: ['reverse-proxy'], usedBy: ['session-analytics', 'threat-intelligence'] }, 'dns-firewall': { id: 'dns-firewall', name: 'DNS Firewall', layer: 'core', category: 'security', status: 'production', progress: 85, icon: '🚫', description: 'Blocage DNS (RPZ), threat feeds, mesh DNS', components: ['vortex-dns', 'vortex-firewall', 'rpz-zones'], dependsOn: ['dns-master'], usedBy: ['ai-security', 'mesh-network'] }, 'access-control': { id: 'access-control', name: 'Access Control', layer: 'core', category: 'security', status: 'production', progress: 90, icon: '🔐', description: 'NAC, portail captif, OAuth2, vouchers', components: ['auth-guardian', 'client-guardian', 'nodogsplash', 'mac-guardian'], dependsOn: ['network-stack'], usedBy: ['user-management'] }, // === NETWORK === 'reverse-proxy': { id: 'reverse-proxy', name: 'Reverse Proxy & SSL', layer: 'core', category: 'network', status: 'production', progress: 95, icon: '🔀', description: 'HAProxy SNI routing, ACME SSL, 226 vhosts', components: ['haproxy', 'acme', 'vhost-manager'], dependsOn: ['dns-master'], usedBy: ['waf', 'service-exposure'], stats: { vhosts: 226, certificates: 92 } }, 'dns-master': { id: 'dns-master', name: 'DNS Master', layer: 'core', category: 'network', status: 'production', progress: 90, icon: '🌍', description: 'BIND9 authoritative, zone management, 7 zones', components: ['bind9', 'dns-provider', 'zone-editor'], dependsOn: [], usedBy: ['reverse-proxy', 'dns-firewall', 'mesh-network'], stats: { zones: 7, records: 78 } }, 'vpn-mesh': { id: 'vpn-mesh', name: 'VPN & Mesh', layer: 'core', category: 'network', status: 'production', progress: 85, icon: '🔒', description: 'WireGuard tunnels, QR codes, mesh topology', components: ['wireguard', 'mesh-discovery', 'qr-generator'], dependsOn: ['network-stack'], usedBy: ['mirrornet-p2p', 'master-link'] }, 'bandwidth-qos': { id: 'bandwidth-qos', name: 'Bandwidth & QoS', layer: 'core', category: 'network', status: 'production', progress: 85, icon: '📊', description: 'SQM/CAKE, quotas, traffic shaping', components: ['bandwidth-manager', 'traffic-shaper', 'sqm'], dependsOn: ['network-stack'], usedBy: ['media-services'] }, // === SERVICES === 'container-platform': { id: 'container-platform', name: 'Container Platform', layer: 'core', category: 'services', status: 'production', progress: 95, icon: '📦', description: 'LXC containers, 18 running, auto-start', components: ['lxc-manager', 'container-networking', 'resource-limits'], dependsOn: ['network-stack'], usedBy: ['media-services', 'communication', 'cloud-services'], stats: { running: 18, total: 25 } }, 'media-services': { id: 'media-services', name: 'Media Services', layer: 'core', category: 'services', status: 'production', progress: 90, icon: '🎬', description: 'Streaming, photos, musique', components: ['jellyfin', 'photoprism', 'lyrion', 'peertube'], dependsOn: ['container-platform', 'reverse-proxy'], usedBy: [] }, 'communication': { id: 'communication', name: 'Communication', layer: 'core', category: 'services', status: 'production', progress: 85, icon: '💬', description: 'Chat, video, federation', components: ['matrix', 'jitsi', 'jabber', 'gotosocial', 'simplex'], dependsOn: ['container-platform', 'reverse-proxy'], usedBy: [] }, 'cloud-services': { id: 'cloud-services', name: 'Cloud Services', layer: 'core', category: 'services', status: 'production', progress: 85, icon: '☁️', description: 'Files, email, git', components: ['nextcloud', 'mailserver', 'gitea'], dependsOn: ['container-platform', 'reverse-proxy'], usedBy: [] }, 'remote-access': { id: 'remote-access', name: 'Remote Access', layer: 'core', category: 'services', status: 'production', progress: 80, icon: '🖥️', description: 'Terminal web, RDP, TURN/STUN', components: ['rtty-remote', 'turn-server', 'rustdesk'], dependsOn: ['reverse-proxy'], usedBy: ['master-link'] }, // === AI === 'ai-inference': { id: 'ai-inference', name: 'AI Inference', layer: 'ai', category: 'ai', status: 'production', progress: 80, icon: '🧠', description: 'LocalAI, Ollama, embeddings, completions', components: ['localai', 'ollama', 'model-manager'], dependsOn: ['container-platform'], usedBy: ['ai-security', 'ai-agents'] }, 'ai-security': { id: 'ai-security', name: 'AI Security Agents', layer: 'ai', category: 'ai', status: 'production', progress: 90, icon: '🤖', description: 'Threat analysis, DNS anomaly, network behavior', components: ['threat-analyst', 'dns-guard-ai', 'network-anomaly'], dependsOn: ['ai-inference', 'intrusion-prevention'], usedBy: [] }, 'ai-memory': { id: 'ai-memory', name: 'AI Memory & Context', layer: 'ai', category: 'ai', status: 'production', progress: 85, icon: '💾', description: 'LocalRecall, RAG, conversation history', components: ['localrecall', 'mcp-server', 'embedding-store'], dependsOn: ['ai-inference'], usedBy: ['ai-security'] }, // === MIRRORNET === 'mesh-network': { id: 'mesh-network', name: 'Mesh Network', layer: 'mirrornet', category: 'p2p', status: 'production', progress: 90, icon: '🕸️', description: 'P2P mesh, gossip protocol, service discovery', components: ['p2p-core', 'gossip', 'mesh-dns'], dependsOn: ['vpn-mesh', 'dns-master'], usedBy: ['p2p-intel', 'service-mirroring'] }, 'identity-trust': { id: 'identity-trust', name: 'Identity & Trust', layer: 'mirrornet', category: 'p2p', status: 'production', progress: 85, icon: '🪪', description: 'DID identity, reputation, trust hierarchy', components: ['identity-did', 'reputation', 'master-link'], dependsOn: ['mesh-network'], usedBy: ['p2p-intel'] }, 'p2p-intel': { id: 'p2p-intel', name: 'P2P Intelligence', layer: 'mirrornet', category: 'p2p', status: 'production', progress: 80, icon: '🔍', description: 'IOC sharing, signed alerts, collective defense', components: ['p2p-intel-core', 'ioc-signatures', 'alert-propagation'], dependsOn: ['identity-trust', 'intrusion-prevention'], usedBy: [] }, 'service-exposure': { id: 'service-exposure', name: 'Service Exposure', layer: 'core', category: 'exposure', status: 'production', progress: 80, icon: '🚀', description: 'Peek/Poke/Emancipate, multi-channel exposure', components: ['exposure-engine', 'tor-hidden', 'dns-ssl', 'mesh-publish'], dependsOn: ['reverse-proxy', 'dns-master'], usedBy: ['mesh-network'] }, // === MONITORING === 'system-monitoring': { id: 'system-monitoring', name: 'System Monitoring', layer: 'core', category: 'monitoring', status: 'production', progress: 90, icon: '📈', description: 'Glances, Netdata, system health', components: ['glances', 'netdata', 'health-checks'], dependsOn: [], usedBy: ['ai-security'] }, 'network-analytics': { id: 'network-analytics', name: 'Network Analytics', layer: 'core', category: 'monitoring', status: 'production', progress: 85, icon: '🔬', description: 'DPI, flow analysis, application detection', components: ['netifyd', 'ndpid', 'flow-analyzer'], dependsOn: ['network-stack'], usedBy: ['ai-security', 'bandwidth-qos'] }, 'session-analytics': { id: 'session-analytics', name: 'Session Analytics', layer: 'core', category: 'monitoring', status: 'production', progress: 85, icon: '👁️', description: 'Avatar-Tap recording, cookie tracking, replay', components: ['avatar-tap', 'cookie-tracker', 'session-replay'], dependsOn: ['waf'], usedBy: ['threat-intelligence'] }, 'threat-intelligence': { id: 'threat-intelligence', name: 'Threat Intelligence', layer: 'core', category: 'monitoring', status: 'production', progress: 80, icon: '🎯', description: 'CVE triage, cyberfeed, device intel', components: ['cve-triage', 'cyberfeed', 'device-intel'], dependsOn: ['intrusion-prevention'], usedBy: ['ai-security'] }, // === ADMIN === 'config-management': { id: 'config-management', name: 'Configuration Management', layer: 'certification', category: 'admin', status: 'production', progress: 95, icon: '⚙️', description: 'Backup, restore, config vault, device provisioning', components: ['backup', 'config-advisor', 'cloner', 'config-vault'], dependsOn: [], usedBy: [] }, 'compliance': { id: 'compliance', name: 'Compliance & Audit', layer: 'certification', category: 'admin', status: 'beta', progress: 60, icon: '📋', description: 'ANSSI CSPN, CRA, security audit', components: ['anssi-checker', 'sbom-generator', 'audit-log'], dependsOn: ['config-management'], usedBy: [] } }, // ============================================================ // COMPONENTS: Building blocks // ============================================================ components: { // Security components 'crowdsec': { name: 'CrowdSec', type: 'backend', status: 'production', packages: ['secubox-app-crowdsec', 'luci-app-crowdsec-dashboard'] }, 'firewall-bouncer': { name: 'Firewall Bouncer', type: 'backend', status: 'production', packages: ['secubox-app-cs-firewall-bouncer'] }, 'wazuh': { name: 'Wazuh SIEM', type: 'backend', status: 'production', packages: ['secubox-app-wazuh', 'luci-app-wazuh'] }, 'mitmproxy': { name: 'Mitmproxy WAF', type: 'backend', status: 'production', packages: ['secubox-app-mitmproxy', 'luci-app-mitmproxy'] }, 'haproxy-router': { name: 'HAProxy Router', type: 'addon', status: 'production', packages: [] }, 'analytics': { name: 'SecuBox Analytics', type: 'addon', status: 'production', packages: [] }, 'vortex-dns': { name: 'Vortex DNS', type: 'backend', status: 'production', packages: ['secubox-vortex-dns', 'luci-app-vortex-dns'] }, 'vortex-firewall': { name: 'Vortex Firewall', type: 'backend', status: 'production', packages: ['secubox-vortex-firewall', 'luci-app-vortex-firewall'] }, 'rpz-zones': { name: 'RPZ Zones', type: 'config', status: 'production', packages: [] }, 'auth-guardian': { name: 'Auth Guardian', type: 'luci', status: 'production', packages: ['luci-app-auth-guardian'] }, 'client-guardian': { name: 'Client Guardian', type: 'luci', status: 'production', packages: ['luci-app-client-guardian'] }, 'nodogsplash': { name: 'Nodogsplash', type: 'backend', status: 'production', packages: ['secubox-app-nodogsplash'] }, 'mac-guardian': { name: 'MAC Guardian', type: 'backend', status: 'production', packages: ['secubox-app-mac-guardian', 'luci-app-mac-guardian'] }, // Network components 'haproxy': { name: 'HAProxy', type: 'backend', status: 'production', packages: ['secubox-app-haproxy', 'luci-app-haproxy'] }, 'acme': { name: 'ACME SSL', type: 'backend', status: 'production', packages: [] }, 'vhost-manager': { name: 'VHost Manager', type: 'luci', status: 'production', packages: ['secubox-app-vhost-manager', 'luci-app-vhost-manager'] }, 'bind9': { name: 'BIND9', type: 'backend', status: 'production', packages: ['secubox-app-dns-master', 'luci-app-dns-master'] }, 'dns-provider': { name: 'DNS Provider API', type: 'backend', status: 'beta', packages: ['secubox-app-dns-provider', 'luci-app-dns-provider'] }, 'zone-editor': { name: 'Zone Editor', type: 'luci', status: 'production', packages: [] }, 'wireguard': { name: 'WireGuard', type: 'backend', status: 'production', packages: ['luci-app-wireguard-dashboard'] }, 'mesh-discovery': { name: 'Mesh Discovery', type: 'backend', status: 'beta', packages: ['secubox-app-meshname-dns'] }, 'qr-generator': { name: 'QR Generator', type: 'addon', status: 'production', packages: [] }, 'bandwidth-manager': { name: 'Bandwidth Manager', type: 'luci', status: 'production', packages: ['luci-app-bandwidth-manager'] }, 'traffic-shaper': { name: 'Traffic Shaper', type: 'luci', status: 'production', packages: ['luci-app-traffic-shaper'] }, 'sqm': { name: 'SQM/CAKE', type: 'backend', status: 'production', packages: [] }, // Service components 'lxc-manager': { name: 'LXC Manager', type: 'luci', status: 'production', packages: ['luci-app-vm'] }, 'container-networking': { name: 'Container Networking', type: 'backend', status: 'production', packages: [] }, 'resource-limits': { name: 'Resource Limits', type: 'config', status: 'production', packages: [] }, 'jellyfin': { name: 'Jellyfin', type: 'backend', status: 'production', packages: ['secubox-app-jellyfin', 'luci-app-jellyfin'] }, 'photoprism': { name: 'PhotoPrism', type: 'backend', status: 'production', packages: ['secubox-app-photoprism', 'luci-app-photoprism'] }, 'lyrion': { name: 'Lyrion Music', type: 'backend', status: 'production', packages: ['secubox-app-lyrion', 'luci-app-lyrion'] }, 'peertube': { name: 'PeerTube', type: 'backend', status: 'beta', packages: ['secubox-app-peertube', 'luci-app-peertube'] }, 'matrix': { name: 'Matrix', type: 'backend', status: 'production', packages: ['secubox-app-matrix', 'luci-app-matrix'] }, 'jitsi': { name: 'Jitsi', type: 'backend', status: 'production', packages: ['secubox-app-jitsi', 'luci-app-jitsi'] }, 'jabber': { name: 'Prosody XMPP', type: 'backend', status: 'production', packages: ['secubox-app-jabber', 'luci-app-jabber'] }, 'gotosocial': { name: 'GoToSocial', type: 'backend', status: 'production', packages: ['secubox-app-gotosocial', 'luci-app-gotosocial'] }, 'simplex': { name: 'SimpleX', type: 'backend', status: 'beta', packages: ['secubox-app-simplex', 'luci-app-simplex'] }, 'nextcloud': { name: 'Nextcloud', type: 'backend', status: 'production', packages: ['secubox-app-nextcloud', 'luci-app-nextcloud'] }, 'mailserver': { name: 'Mail Server', type: 'backend', status: 'production', packages: ['secubox-app-mailserver', 'luci-app-mailserver'] }, 'gitea': { name: 'Gitea', type: 'backend', status: 'production', packages: ['secubox-app-gitea', 'luci-app-gitea'] }, 'rtty-remote': { name: 'RTTY Remote', type: 'backend', status: 'production', packages: ['secubox-app-rtty-remote', 'luci-app-rtty-remote'] }, 'turn-server': { name: 'TURN Server', type: 'backend', status: 'production', packages: ['secubox-app-turn', 'luci-app-turn'] }, 'rustdesk': { name: 'RustDesk', type: 'backend', status: 'beta', packages: ['secubox-app-rustdesk'] }, // AI components 'localai': { name: 'LocalAI', type: 'backend', status: 'production', packages: ['secubox-app-localai', 'luci-app-localai'] }, 'ollama': { name: 'Ollama', type: 'backend', status: 'beta', packages: ['secubox-app-ollama', 'luci-app-ollama'] }, 'model-manager': { name: 'Model Manager', type: 'luci', status: 'beta', packages: ['luci-app-ai-gateway'] }, 'threat-analyst': { name: 'Threat Analyst', type: 'backend', status: 'beta', packages: ['secubox-threat-analyst', 'luci-app-threat-analyst'] }, 'dns-guard-ai': { name: 'DNS Guard AI', type: 'backend', status: 'beta', packages: ['secubox-dns-guard', 'luci-app-dnsguard'] }, 'network-anomaly': { name: 'Network Anomaly', type: 'backend', status: 'beta', packages: ['secubox-network-anomaly', 'luci-app-network-anomaly'] }, 'localrecall': { name: 'LocalRecall', type: 'backend', status: 'alpha', packages: ['secubox-localrecall', 'luci-app-localrecall'] }, 'mcp-server': { name: 'MCP Server', type: 'backend', status: 'beta', packages: ['secubox-mcp-server'] }, 'embedding-store': { name: 'Embedding Store', type: 'backend', status: 'alpha', packages: [] }, // P2P components 'p2p-core': { name: 'P2P Core', type: 'backend', status: 'beta', packages: ['secubox-p2p', 'luci-app-secubox-p2p'] }, 'gossip': { name: 'Gossip Protocol', type: 'backend', status: 'beta', packages: [] }, 'mesh-dns': { name: 'Mesh DNS', type: 'backend', status: 'beta', packages: ['secubox-app-meshname-dns', 'luci-app-meshname-dns'] }, 'identity-did': { name: 'Identity DID', type: 'backend', status: 'alpha', packages: ['secubox-identity'] }, 'reputation': { name: 'Reputation System', type: 'backend', status: 'alpha', packages: [] }, 'master-link': { name: 'Master Link', type: 'backend', status: 'production', packages: ['secubox-master-link', 'luci-app-master-link'] }, 'p2p-intel-core': { name: 'P2P Intel Core', type: 'backend', status: 'alpha', packages: ['secubox-p2p-intel'] }, 'ioc-signatures': { name: 'IOC Signatures', type: 'backend', status: 'alpha', packages: [] }, 'alert-propagation': { name: 'Alert Propagation', type: 'backend', status: 'alpha', packages: [] }, 'exposure-engine': { name: 'Exposure Engine', type: 'backend', status: 'production', packages: ['secubox-app-exposure', 'luci-app-exposure'] }, 'tor-hidden': { name: 'Tor Hidden Services', type: 'backend', status: 'production', packages: ['secubox-app-tor', 'luci-app-tor-shield'] }, 'dns-ssl': { name: 'DNS/SSL Channel', type: 'backend', status: 'production', packages: [] }, 'mesh-publish': { name: 'Mesh Publish', type: 'backend', status: 'beta', packages: [] }, // Monitoring components 'glances': { name: 'Glances', type: 'backend', status: 'production', packages: ['secubox-app-glances', 'luci-app-glances'] }, 'netdata': { name: 'Netdata', type: 'backend', status: 'production', packages: ['luci-app-netdata-dashboard'] }, 'health-checks': { name: 'Health Checks', type: 'backend', status: 'production', packages: [] }, 'netifyd': { name: 'Netifyd', type: 'backend', status: 'production', packages: ['secubox-app-netifyd', 'luci-app-secubox-netifyd'] }, 'ndpid': { name: 'nDPId', type: 'backend', status: 'production', packages: ['secubox-app-ndpid', 'luci-app-ndpid'] }, 'flow-analyzer': { name: 'Flow Analyzer', type: 'backend', status: 'production', packages: [] }, 'avatar-tap': { name: 'Avatar-Tap', type: 'backend', status: 'production', packages: ['secubox-avatar-tap', 'luci-app-avatar-tap'] }, 'cookie-tracker': { name: 'Cookie Tracker', type: 'backend', status: 'production', packages: ['secubox-cookie-tracker', 'luci-app-cookie-tracker'] }, 'session-replay': { name: 'Session Replay', type: 'luci', status: 'production', packages: [] }, 'cve-triage': { name: 'CVE Triage', type: 'backend', status: 'beta', packages: ['secubox-cve-triage', 'luci-app-cve-triage'] }, 'cyberfeed': { name: 'CyberFeed', type: 'backend', status: 'production', packages: ['secubox-app-cyberfeed', 'luci-app-cyberfeed'] }, 'device-intel': { name: 'Device Intel', type: 'backend', status: 'production', packages: ['secubox-app-device-intel', 'luci-app-device-intel'] }, // Admin components 'backup': { name: 'Backup', type: 'backend', status: 'production', packages: ['secubox-app-backup', 'luci-app-backup'] }, 'config-advisor': { name: 'Config Advisor', type: 'backend', status: 'beta', packages: ['secubox-config-advisor', 'luci-app-config-advisor'] }, 'cloner': { name: 'Station Cloner', type: 'luci', status: 'alpha', packages: ['luci-app-cloner'] }, 'anssi-checker': { name: 'ANSSI Checker', type: 'backend', status: 'alpha', packages: [] }, 'sbom-generator': { name: 'SBOM Generator', type: 'backend', status: 'planned', packages: [] }, 'audit-log': { name: 'Audit Log', type: 'backend', status: 'beta', packages: ['secubox-app-auth-logger'] }, // Virtual/implicit 'network-stack': { name: 'Network Stack', type: 'system', status: 'production', packages: [] } }, // ============================================================ // MILESTONES: Version targets // ============================================================ milestones: [ { version: '0.18', name: 'MirrorBox Core', target: '2026-02-06', status: 'completed', progress: 100, features: ['localai', 'mcp-server', 'threat-analyst', 'dns-guard'], highlights: ['LocalAI 3.9 upgrade', 'MCP Server for Claude Desktop', 'Threat Analyst agent'] }, { version: '0.19', name: 'AI Expansion + MirrorNet', target: '2026-02-07', status: 'completed', progress: 100, features: ['cve-triage', 'network-anomaly', 'mirrornet', 'identity'], highlights: ['CVE Triage agent', 'Network Anomaly detection', 'MirrorNet P2P mesh'] }, { version: '1.0', name: 'Full Stack Release', target: '2026-03-16', status: 'completed', progress: 100, features: ['voip', 'matrix', 'factory', 'config-vault', 'smtp-relay'], highlights: ['VoIP integration', 'Matrix federation', 'Device provisioning', 'Unified SMTP relay'] }, { version: '1.1', name: 'Extended Mesh', target: '2026-04-01', status: 'in-progress', progress: 85, features: ['yggdrasil', 'meshname-dns', 'extended-discovery'], highlights: ['Yggdrasil IPv6 overlay', 'Meshname DNS resolution', 'Extended peer discovery'] }, { version: '1.2', name: 'Certification', target: '2026-06-01', status: 'planned', progress: 20, features: ['compliance', 'sbom', 'anssi'], highlights: ['ANSSI CSPN prep', 'CRA Annex I SBOM', 'Security documentation'] } ], // ============================================================ // PRODUCTION STATS (defaults, updated via RPCD) // ============================================================ stats: { totalPackages: 190, luciApps: 92, backends: 98, lxcContainers: 18, haproxyVhosts: 243, sslCertificates: 95, dnsZones: 7, dnsRecords: 82, mitmproxyRoutes: 174, architectures: 13, commits: 1850, modulesCount: 92, lastLiveUpdate: null }, // ============================================================ // DYNAMIC DATA FETCHING // ============================================================ loadFiltersFromStorage: function() { try { var stored = localStorage.getItem('dsw_filters'); if (stored) { var parsed = JSON.parse(stored); this.activeFilters = parsed; } } catch (e) { // Ignore localStorage errors } }, saveFiltersToStorage: function() { try { localStorage.setItem('dsw_filters', JSON.stringify(this.activeFilters)); } catch (e) { // Ignore localStorage errors } }, fetchLiveStats: function() { var self = this; // Try to fetch from system-hub RPCD (no auth required for read-only) if (typeof L !== 'undefined' && L.rpc) { var rpc = L.rpc.declare({ object: 'luci.system-hub', method: 'status', expect: {} }); rpc().then(function(result) { if (result) { self.updateLiveStats(result); } }).catch(function() { // Silently fail, use static data }); } else { // Standalone mode - try direct fetch this.fetchStatsStandalone(); } }, fetchStatsStandalone: function() { var self = this; var xhr = new XMLHttpRequest(); xhr.open('POST', '/ubus', true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { try { var resp = JSON.parse(xhr.responseText); if (resp && resp.result && resp.result[1]) { self.updateLiveStats(resp.result[1]); } } catch (e) { // Ignore parse errors } } }; xhr.send(JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'call', params: ['00000000000000000000000000000000', 'luci.system-hub', 'status', {}] })); }, updateLiveStats: function(data) { if (data.service_count) { this.stats.backends = data.service_count; } this.stats.lastLiveUpdate = new Date().toISOString(); // Update display if rendered var statsContainer = document.querySelector('.dsw-stats-grid'); if (statsContainer) { this.updateStatsDisplay(); } }, updateStatsDisplay: function() { var liveIndicator = document.querySelector('.dsw-live-indicator'); if (liveIndicator && this.stats.lastLiveUpdate) { liveIndicator.classList.add('dsw-live-active'); liveIndicator.title = 'Last update: ' + this.stats.lastLiveUpdate; } }, startAutoRefresh: function() { var self = this; if (this.refreshInterval) { clearInterval(this.refreshInterval); } this.refreshInterval = setInterval(function() { self.fetchLiveStats(); }, this.refreshSeconds * 1000); }, stopAutoRefresh: function() { if (this.refreshInterval) { clearInterval(this.refreshInterval); this.refreshInterval = null; } }, // ============================================================ // RENDER METHODS // ============================================================ render: function(containerId) { var self = this; var container = document.getElementById(containerId); if (!container) return; // Load saved filters this.loadFiltersFromStorage(); container.innerHTML = this.renderLoading(); // Small delay for smooth loading animation setTimeout(function() { container.innerHTML = [ '
Chargement de l\'architecture...
Architecture: ', this.totalPackages, ' packages · 4 couches · ', Object.keys(this.features).length, ' features
', '', layer.description, '
', '', feature.description, '
', '', deps.length, ' interconnections entre features
', '