secubox-openwrt/luci-app-cdn-cache/htdocs/luci-static/resources/view/cdn-cache/overview.js
CyberMind-FR cf39eb6e1d fix: resolve validation issues across all modules
- Fixed minified RPC declaration in secubox/modules.js that caused false positive in validation
- Added 30 missing menu entries across 10 modules:
  * bandwidth-manager: clients, schedules
  * client-guardian: zones, portal, logs, alerts, parental
  * crowdsec-dashboard: metrics
  * netdata-dashboard: system, processes, realtime, network
  * netifyd-dashboard: talkers, risks, devices
  * network-modes: router, accesspoint, relay, sniffer
  * secubox: settings
  * system-hub: components, diagnostics, health, remote, settings
  * vhost-manager: internal, ssl, redirects
  * wireguard-dashboard: traffic, config
- All modules now pass comprehensive validation (0 errors, 0 warnings)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-25 09:01:06 +01:00

256 lines
12 KiB
JavaScript

'use strict';
'require view';
'require poll';
'require rpc';
'require uci';
var callStatus = rpc.declare({
object: 'luci.cdn-cache',
method: 'status',
expect: { }
});
var callStats = rpc.declare({
object: 'luci.cdn-cache',
method: 'stats',
expect: { }
});
var callCacheSize = rpc.declare({
object: 'luci.cdn-cache',
method: 'cache_size',
expect: { }
});
var callTopDomains = rpc.declare({
object: 'luci.cdn-cache',
method: 'top_domains',
expect: { domains: [] }
});
function formatBytes(bytes) {
if (bytes === 0) return '0 B';
var k = 1024;
var sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
var i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
function formatUptime(seconds) {
if (seconds < 60) return seconds + 's';
if (seconds < 3600) return Math.floor(seconds / 60) + 'm ' + (seconds % 60) + 's';
if (seconds < 86400) return Math.floor(seconds / 3600) + 'h ' + Math.floor((seconds % 3600) / 60) + 'm';
return Math.floor(seconds / 86400) + 'd ' + Math.floor((seconds % 86400) / 3600) + 'h';
}
return view.extend({
load: function() {
return Promise.all([
callStatus(),
callStats(),
callCacheSize(),
callTopDomains()
]);
},
render: function(data) {
var status = data[0] || {};
var stats = data[1] || {};
var cacheSize = data[2] || {};
var topDomains = data[3].domains || [];
var view = E('div', { 'class': 'cbi-map cdn-cache-dashboard' }, [
E('style', {}, `
.cdn-cache-dashboard { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
.cdn-header { background: linear-gradient(135deg, #0891b2, #06b6d4, #22d3ee); color: white; padding: 30px; border-radius: 16px; margin-bottom: 24px; }
.cdn-header h2 { margin: 0 0 8px 0; font-size: 28px; font-weight: 700; }
.cdn-header p { margin: 0; opacity: 0.9; }
.cdn-status-badge { display: inline-flex; align-items: center; gap: 8px; padding: 6px 14px; border-radius: 20px; font-size: 13px; font-weight: 600; margin-top: 12px; }
.cdn-status-badge.running { background: rgba(34,197,94,0.2); color: #22c55e; }
.cdn-status-badge.stopped { background: rgba(239,68,68,0.2); color: #ef4444; }
.cdn-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 20px; margin-bottom: 24px; }
.cdn-card { background: #1e293b; border-radius: 12px; padding: 20px; border: 1px solid #334155; }
.cdn-card-icon { font-size: 28px; margin-bottom: 12px; }
.cdn-card-value { font-size: 32px; font-weight: 700; color: #f1f5f9; margin-bottom: 4px; font-family: 'JetBrains Mono', monospace; }
.cdn-card-label { font-size: 13px; color: #94a3b8; }
.cdn-card-sub { font-size: 12px; color: #64748b; margin-top: 8px; }
.cdn-section { background: #1e293b; border-radius: 12px; padding: 24px; border: 1px solid #334155; margin-bottom: 24px; }
.cdn-section-title { font-size: 16px; font-weight: 600; color: #f1f5f9; margin-bottom: 16px; display: flex; align-items: center; gap: 10px; }
.cdn-progress-bar { background: #334155; border-radius: 8px; height: 12px; overflow: hidden; }
.cdn-progress-fill { height: 100%; border-radius: 8px; transition: width 0.3s; }
.cdn-progress-fill.low { background: linear-gradient(90deg, #22c55e, #4ade80); }
.cdn-progress-fill.medium { background: linear-gradient(90deg, #eab308, #facc15); }
.cdn-progress-fill.high { background: linear-gradient(90deg, #f97316, #fb923c); }
.cdn-progress-fill.critical { background: linear-gradient(90deg, #ef4444, #f87171); }
.cdn-domain-list { list-style: none; padding: 0; margin: 0; }
.cdn-domain-item { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid #334155; }
.cdn-domain-item:last-child { border-bottom: none; }
.cdn-domain-name { font-weight: 500; color: #f1f5f9; }
.cdn-domain-stats { display: flex; gap: 16px; font-size: 13px; color: #94a3b8; }
.cdn-hit-ratio { display: flex; align-items: center; gap: 12px; }
.cdn-ratio-circle { width: 100px; height: 100px; position: relative; }
.cdn-ratio-circle svg { transform: rotate(-90deg); }
.cdn-ratio-circle circle { fill: none; stroke-width: 8; }
.cdn-ratio-circle .bg { stroke: #334155; }
.cdn-ratio-circle .fg { stroke: #06b6d4; stroke-linecap: round; transition: stroke-dashoffset 0.5s; }
.cdn-ratio-value { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24px; font-weight: 700; color: #06b6d4; }
.cdn-savings { text-align: center; padding: 20px; background: linear-gradient(135deg, rgba(34,197,94,0.1), rgba(16,185,129,0.05)); border-radius: 12px; border: 1px solid rgba(34,197,94,0.2); }
.cdn-savings-value { font-size: 42px; font-weight: 800; color: #22c55e; font-family: 'JetBrains Mono', monospace; }
.cdn-savings-label { font-size: 14px; color: #94a3b8; margin-top: 4px; }
`),
E('div', { 'class': 'cdn-header' }, [
E('h2', {}, '📦 CDN Cache Dashboard'),
E('p', {}, 'Proxy cache local pour optimisation de bande passante'),
E('span', { 'class': 'cdn-status-badge ' + (status.running ? 'running' : 'stopped') }, [
E('span', {}, status.running ? '● Actif' : '○ Inactif'),
status.running ? E('span', {}, ' — Port ' + status.listen_port) : null
])
]),
E('div', { 'class': 'cdn-grid' }, [
E('div', { 'class': 'cdn-card' }, [
E('div', { 'class': 'cdn-card-icon' }, '🎯'),
E('div', { 'class': 'cdn-card-value' }, stats.hit_ratio + '%'),
E('div', { 'class': 'cdn-card-label' }, 'Hit Ratio'),
E('div', { 'class': 'cdn-card-sub' }, stats.hits + ' hits / ' + stats.misses + ' misses')
]),
E('div', { 'class': 'cdn-card' }, [
E('div', { 'class': 'cdn-card-icon' }, '💾'),
E('div', { 'class': 'cdn-card-value' }, formatBytes(cacheSize.used_kb * 1024)),
E('div', { 'class': 'cdn-card-label' }, 'Cache utilisé'),
E('div', { 'class': 'cdn-card-sub' }, cacheSize.usage_percent + '% de ' + formatBytes(cacheSize.max_kb * 1024))
]),
E('div', { 'class': 'cdn-card' }, [
E('div', { 'class': 'cdn-card-icon' }, '📊'),
E('div', { 'class': 'cdn-card-value' }, stats.requests.toLocaleString()),
E('div', { 'class': 'cdn-card-label' }, 'Requêtes totales'),
E('div', { 'class': 'cdn-card-sub' }, status.cache_files + ' fichiers en cache')
]),
E('div', { 'class': 'cdn-card' }, [
E('div', { 'class': 'cdn-card-icon' }, '⏱️'),
E('div', { 'class': 'cdn-card-value' }, formatUptime(status.uptime || 0)),
E('div', { 'class': 'cdn-card-label' }, 'Uptime'),
E('div', { 'class': 'cdn-card-sub' }, 'PID: ' + (status.pid || 'N/A'))
])
]),
E('div', { 'style': 'display: grid; grid-template-columns: 1fr 1fr; gap: 24px;' }, [
E('div', { 'class': 'cdn-section' }, [
E('div', { 'class': 'cdn-section-title' }, ['🎯 ', 'Hit Ratio Gauge']),
E('div', { 'style': 'display: flex; justify-content: center; padding: 20px;' }, [
E('div', { 'class': 'cdn-ratio-circle' }, [
(function() {
var ratio = stats.hit_ratio || 0;
var circumference = 2 * Math.PI * 46; // radius = 46
var offset = circumference - (ratio / 100) * circumference;
return E('svg', { 'width': '100', 'height': '100' }, [
E('circle', { 'class': 'bg', 'cx': '50', 'cy': '50', 'r': '46' }),
E('circle', {
'class': 'fg',
'cx': '50',
'cy': '50',
'r': '46',
'style': 'stroke-dasharray: ' + circumference + '; stroke-dashoffset: ' + offset + ';'
})
]);
})(),
E('div', { 'class': 'cdn-ratio-value' }, (stats.hit_ratio || 0) + '%')
])
]),
E('div', { 'style': 'text-align: center; margin-top: 16px;' }, [
E('div', { 'style': 'display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 12px;' }, [
E('div', {}, [
E('div', { 'style': 'font-size: 20px; font-weight: 700; color: #22c55e;' }, stats.hits || 0),
E('div', { 'style': 'font-size: 12px; color: #94a3b8;' }, 'Cache Hits')
]),
E('div', {}, [
E('div', { 'style': 'font-size: 20px; font-weight: 700; color: #ef4444;' }, stats.misses || 0),
E('div', { 'style': 'font-size: 12px; color: #94a3b8;' }, 'Cache Misses')
])
])
])
]),
E('div', { 'class': 'cdn-section' }, [
E('div', { 'class': 'cdn-section-title' }, ['📈 ', 'Économies de Bande Passante']),
E('div', { 'class': 'cdn-savings' }, [
E('div', { 'class': 'cdn-savings-value' }, stats.saved_mb + ' MB'),
E('div', { 'class': 'cdn-savings-label' }, 'Économisés grâce au cache')
]),
E('div', { 'style': 'margin-top: 16px;' }, [
E('div', { 'style': 'display: flex; justify-content: space-between; margin-bottom: 8px;' }, [
E('span', { 'style': 'color: #94a3b8; font-size: 13px;' }, 'Cache'),
E('span', { 'style': 'color: #22c55e; font-weight: 600;' }, stats.saved_mb + ' MB')
]),
E('div', { 'class': 'cdn-progress-bar' }, [
E('div', { 'class': 'cdn-progress-fill low', 'style': 'width: ' + (stats.hit_ratio || 0) + '%;' })
]),
E('div', { 'style': 'display: flex; justify-content: space-between; margin-top: 8px;' }, [
E('span', { 'style': 'color: #94a3b8; font-size: 13px;' }, 'Téléchargé'),
E('span', { 'style': 'color: #94a3b8; font-weight: 600;' }, stats.served_mb + ' MB')
])
])
])
]),
E('div', { 'style': 'display: grid; grid-template-columns: 1fr 1fr; gap: 24px;' }, [
E('div', { 'class': 'cdn-section' }, [
E('div', { 'class': 'cdn-section-title' }, ['💿 ', 'Espace Cache']),
E('div', { 'style': 'margin-bottom: 16px;' }, [
E('div', { 'style': 'display: flex; justify-content: space-between; margin-bottom: 8px;' }, [
E('span', { 'style': 'color: #94a3b8;' }, 'Utilisation'),
E('span', { 'style': 'color: #f1f5f9; font-weight: 600;' }, cacheSize.usage_percent + '%')
]),
E('div', { 'class': 'cdn-progress-bar' }, [
E('div', {
'class': 'cdn-progress-fill ' + (cacheSize.usage_percent < 50 ? 'low' : cacheSize.usage_percent < 75 ? 'medium' : cacheSize.usage_percent < 90 ? 'high' : 'critical'),
'style': 'width: ' + cacheSize.usage_percent + '%;'
})
])
]),
E('div', { 'style': 'display: grid; grid-template-columns: 1fr 1fr; gap: 16px; text-align: center;' }, [
E('div', {}, [
E('div', { 'style': 'font-size: 24px; font-weight: 700; color: #06b6d4;' }, formatBytes(cacheSize.used_kb * 1024)),
E('div', { 'style': 'font-size: 12px; color: #94a3b8;' }, 'Utilisé')
]),
E('div', {}, [
E('div', { 'style': 'font-size: 24px; font-weight: 700; color: #22c55e;' }, formatBytes(cacheSize.free_kb * 1024)),
E('div', { 'style': 'font-size: 12px; color: #94a3b8;' }, 'Disponible')
])
])
])
]),
E('div', { 'class': 'cdn-section' }, [
E('div', { 'class': 'cdn-section-title' }, ['🌐 ', 'Top Domaines en Cache']),
E('ul', { 'class': 'cdn-domain-list' },
topDomains.length > 0 ? topDomains.slice(0, 10).map(function(d) {
return E('li', { 'class': 'cdn-domain-item' }, [
E('span', { 'class': 'cdn-domain-name' }, d.domain || 'Unknown'),
E('div', { 'class': 'cdn-domain-stats' }, [
E('span', {}, '📁 ' + d.files + ' fichiers'),
E('span', {}, '💾 ' + formatBytes(d.size_kb * 1024))
])
]);
}) : [E('li', { 'style': 'color: #64748b; text-align: center; padding: 20px;' }, 'Aucun domaine en cache')]
)
])
]);
poll.add(L.bind(function() {
return Promise.all([callStatus(), callStats(), callCacheSize()]).then(L.bind(function(data) {
// Update would go here for real-time updates
}, this));
}, this), 10);
return view;
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});