138 lines
5.1 KiB
JavaScript
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
|
|
});
|