secubox-openwrt/luci-app-wireguard-dashboard/htdocs/luci-static/resources/view/wireguard-dashboard/traffic.js

138 lines
5.1 KiB
JavaScript

'use strict';
'require view';
'require poll';
'require dom';
'require ui';
'require wireguard-dashboard.api as api';
return view.extend({
title: _('WireGuard Traffic'),
load: function() {
return api.getTraffic();
},
render: function(data) {
var traffic = data || {};
var interfaces = traffic.interfaces || [];
var totalRx = traffic.total_rx || 0;
var totalTx = traffic.total_tx || 0;
var totalTraffic = totalRx + totalTx;
var view = E('div', { 'class': 'wireguard-dashboard' }, [
// Header
E('div', { 'class': 'wg-header' }, [
E('div', { 'class': 'wg-logo' }, [
E('div', { 'class': 'wg-logo-icon' }, '📊'),
E('div', { 'class': 'wg-logo-text' }, ['Traffic ', E('span', {}, 'Statistics')])
])
]),
// Total Stats
E('div', { 'class': 'wg-quick-stats' }, [
E('div', { 'class': 'wg-quick-stat', 'style': '--stat-gradient: linear-gradient(135deg, #10b981, #34d399)' }, [
E('div', { 'class': 'wg-quick-stat-header' }, [
E('span', { 'class': 'wg-quick-stat-icon' }, '📥'),
E('span', { 'class': 'wg-quick-stat-label' }, 'Total Downloaded')
]),
E('div', { 'class': 'wg-quick-stat-value' }, api.formatBytes(totalRx)),
E('div', { 'class': 'wg-quick-stat-sub' }, 'All interfaces combined')
]),
E('div', { 'class': 'wg-quick-stat', 'style': '--stat-gradient: linear-gradient(135deg, #0ea5e9, #38bdf8)' }, [
E('div', { 'class': 'wg-quick-stat-header' }, [
E('span', { 'class': 'wg-quick-stat-icon' }, '📤'),
E('span', { 'class': 'wg-quick-stat-label' }, 'Total Uploaded')
]),
E('div', { 'class': 'wg-quick-stat-value' }, api.formatBytes(totalTx)),
E('div', { 'class': 'wg-quick-stat-sub' }, 'All interfaces combined')
]),
E('div', { 'class': 'wg-quick-stat' }, [
E('div', { 'class': 'wg-quick-stat-header' }, [
E('span', { 'class': 'wg-quick-stat-icon' }, '📈'),
E('span', { 'class': 'wg-quick-stat-label' }, 'Total Traffic')
]),
E('div', { 'class': 'wg-quick-stat-value' }, api.formatBytes(totalTraffic)),
E('div', { 'class': 'wg-quick-stat-sub' }, 'RX + TX combined')
])
]),
// Per-interface traffic
E('div', { 'class': 'wg-card' }, [
E('div', { 'class': 'wg-card-header' }, [
E('div', { 'class': 'wg-card-title' }, [
E('span', { 'class': 'wg-card-title-icon' }, '🔗'),
'Traffic by Interface'
])
]),
E('div', { 'class': 'wg-card-body' },
interfaces.length > 0 ?
interfaces.map(function(iface) {
var ifaceTotal = (iface.total_rx || 0) + (iface.total_tx || 0);
var rxPct = totalTraffic > 0 ? ((iface.total_rx || 0) / totalTraffic * 100) : 0;
var txPct = totalTraffic > 0 ? ((iface.total_tx || 0) / totalTraffic * 100) : 0;
return E('div', { 'class': 'wg-interface-card', 'style': 'margin-bottom: 16px' }, [
E('div', { 'class': 'wg-interface-header' }, [
E('div', { 'class': 'wg-interface-name' }, [
E('div', { 'class': 'wg-interface-icon' }, '🌐'),
E('div', {}, [
E('h3', {}, iface.name),
E('p', {}, api.formatBytes(ifaceTotal) + ' total')
])
])
]),
E('div', { 'class': 'wg-traffic-bar' }, [
E('div', { 'class': 'wg-traffic-bar-header' }, [
E('span', { 'style': 'color: #10b981' }, '↓ ' + api.formatBytes(iface.total_rx || 0)),
E('span', { 'style': 'color: #0ea5e9' }, '↑ ' + api.formatBytes(iface.total_tx || 0))
]),
E('div', { 'class': 'wg-traffic-bar-track' }, [
E('div', { 'class': 'wg-traffic-bar-rx', 'style': 'width:' + rxPct + '%' }),
E('div', { 'class': 'wg-traffic-bar-tx', 'style': 'width:' + txPct + '%' })
])
]),
(iface.peers || []).length > 0 ? E('div', { 'class': 'wg-table-container', 'style': 'margin-top: 16px' }, [
E('table', { 'class': 'wg-table' }, [
E('thead', {}, [
E('tr', {}, [
E('th', {}, 'Peer'),
E('th', {}, 'Downloaded'),
E('th', {}, 'Uploaded'),
E('th', {}, 'Total')
])
]),
E('tbody', {},
(iface.peers || []).map(function(peer) {
var peerTotal = (peer.rx_bytes || 0) + (peer.tx_bytes || 0);
return E('tr', {}, [
E('td', { 'class': 'mono key' }, peer.short_key + '...'),
E('td', { 'class': 'mono', 'style': 'color: #10b981' }, api.formatBytes(peer.rx_bytes || 0)),
E('td', { 'class': 'mono', 'style': 'color: #0ea5e9' }, api.formatBytes(peer.tx_bytes || 0)),
E('td', { 'class': 'mono' }, api.formatBytes(peerTotal))
]);
})
)
])
]) : ''
]);
}) :
E('div', { 'class': 'wg-empty' }, [
E('div', { 'class': 'wg-empty-icon' }, '📊'),
E('div', { 'class': 'wg-empty-text' }, 'No traffic data available')
])
)
])
]);
// Include CSS
var cssLink = E('link', { 'rel': 'stylesheet', 'href': L.resource('wireguard-dashboard/dashboard.css') });
document.head.appendChild(cssLink);
return view;
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});