small-packages/luci-app-interfaces-statistics/htdocs/luci-static/resources/view/interfaces-statistics.js
2026-05-27 23:25:57 +08:00

385 lines
12 KiB
JavaScript

'use strict';
'require poll';
'require rpc';
'require ui';
'require view';
const labelStyleUp = 'background-color:#388438; color:#fff';
const labelStyleDown = 'background-color:#767676; color:#fff';
return view.extend({
ifacesArray : [],
callNetDevice: rpc.declare({
object: 'network.device',
method: 'status',
expect: { '': {} }
}),
formatBytesString(bytes) {
let units = (bytes > 10**12) ?
`${Number((bytes / 1000 / 1000 / 1000 / 1000).toFixed(2))} ${_('Tb')}` :
(bytes > 10**9) ?
`${Number((bytes / 1000 / 1000 / 1000).toFixed(2))} ${_('Gb')}` :
(bytes > 10**6) ?
`${Number((bytes / 1000 / 1000).toFixed(2))} ${_('Mb')}` :
`${Number((bytes / 1000).toFixed(2))} ${_('Kb')}`;
return `${bytes} (${units})`;
},
setIfacesData(ifacesData) {
for(let iface of this.ifacesArray) {
let ifaceState = null;
let ifacesStatisticsObject = null;
if(ifacesData[iface] !== undefined) {
ifaceState = ifacesData[iface].up;
ifacesStatisticsObject = ifacesData[iface].statistics;
};
let state = document.querySelector('[data-ifstat="%s_state"]'.format(iface));
state.textContent = (ifaceState) ? _('Interface is up') : _('Interface is down');
state.style = (ifaceState) ? labelStyleUp : labelStyleDown;
if(!ifacesStatisticsObject) continue;
for(let [k, v] of Object.entries(ifacesStatisticsObject)) {
let elem = document.querySelector('[data-ifstat="%s_%s"]'.format(iface, k));
if(elem !== null) {
if(k == 'rx_bytes' || k == 'tx_bytes') {
elem.innerHTML = this.formatBytesString(v);
} else {
elem.textContent = v;
}
};
};
};
},
update() {
return this.callNetDevice().then(ifacesData => {
this.setIfacesData(ifacesData);
}).catch(e => ui.addNotification(null, E('p', {}, e.message)));
},
load() {
return this.callNetDevice().catch(
e => ui.addNotification(null, E('p', {}, e.message)));
},
render(ifacesData) {
let ifacesNode = E('div', { 'class': 'cbi-section fade-in' },
E('div', { 'class': 'cbi-section-node' },
E('div', { 'class': 'cbi-value' },
E('em', {}, _('No interfaces detected'))
)
)
);
if(ifacesData) {
ifacesNode = E('div', { 'class': 'cbi-section fade-in' },
E('div', { 'class': 'cbi-section-node' },
E('div', { 'class': 'cbi-value' }, [
E('div', { 'style': 'width:100%; text-align:right !important' },
E('button', {
'class': 'btn',
'click': () => window.location.reload(),
}, _('Refresh interfaces'))
)
])
)
);
let tabsContainer = E('div', { 'class': 'cbi-section-node cbi-section-node-tabbed' });
ifacesNode.append(tabsContainer);
let tab = 0;
for(let iface in ifacesData) {
let ifaceName = iface;
let ifacesStatisticsObject = ifacesData[iface].statistics;
let ifaceState = ifacesData[iface].up;
let ifaceMac = ifacesData[iface].macaddr;
if(ifaceMac == "00:00:00:00:00:00") {
ifaceMac = null;
};
this.ifacesArray.push(iface);
this.ifacesArray.sort();
let ifaceTab = E('div', {
'data-tab' : tab,
'data-tab-title': ifaceName,
});
tabsContainer.append(ifaceTab);
let ifaceTable = E('table', { 'class': 'table' });
if(ifaceMac) {
ifaceTable.append(
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'style': 'width:33%' },
_('MAC Address') + ':'),
E('td', { 'class': 'td left' }, ifaceMac),
]),
);
};
ifaceTable.append(
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'style': 'width:33%' },
_('State') + ':'),
E('td', { 'class': 'td left' },
E('span', {
'data-ifstat': iface + '_state',
'class': 'label',
'style': (ifaceState) ? labelStyleUp : labelStyleDown,
},
(ifaceState) ?
_('Interface is up') : _('Interface is down')
)
),
]),
);
let statTable = E('table', { 'class': 'table' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th left', 'style': 'width:33%' },
_('Parameter')),
E('th', { 'class': 'th left', 'style': 'width:33%' },
_('Receive')),
E('th', { 'class': 'th left' }, _('Transmit')),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('bytes')),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_rx_bytes',
'data-title' : _('Receive') },
ifacesStatisticsObject.rx_bytes
),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_tx_bytes',
'data-title' : _('Transmit') },
ifacesStatisticsObject.tx_bytes
),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('packets')),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_rx_packets',
'data-title' : _('Receive') },
ifacesStatisticsObject.rx_packets
),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_tx_packets',
'data-title' : _('Transmit') },
ifacesStatisticsObject.tx_packets
),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('errors')),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_rx_errors',
'data-title' : _('Receive') },
ifacesStatisticsObject.rx_errors
),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_tx_errors',
'data-title' : _('Transmit') },
ifacesStatisticsObject.tx_errors
),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('dropped')),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_rx_dropped',
'data-title' : _('Receive') },
ifacesStatisticsObject.rx_dropped
),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_tx_dropped',
'data-title' : _('Transmit') },
ifacesStatisticsObject.tx_dropped
),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('compressed')),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_rx_compressed',
'data-title' : _('Receive') },
ifacesStatisticsObject.rx_compressed
),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_tx_compressed',
'data-title' : _('Transmit') },
ifacesStatisticsObject.tx_compressed
),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('fifo errors')),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_rx_fifo_errors',
'data-title' : _('Receive') },
ifacesStatisticsObject.rx_fifo_errors
),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_tx_fifo_errors',
'data-title' : _('Transmit') },
ifacesStatisticsObject.tx_fifo_errors
),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('multicast')),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_multicast',
'data-title' : _('Receive') },
ifacesStatisticsObject.multicast
),
E('td', { 'class': 'td left', 'data-title': _('Transmit') },
' '),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('crc errors')),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_rx_crc_errors',
'data-title' : _('Receive') },
ifacesStatisticsObject.rx_crc_errors
),
E('td', { 'class': 'td left', 'data-title': _('Transmit') },
' '),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('frame errors')),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_rx_frame_errors',
'data-title' : _('Receive') },
ifacesStatisticsObject.rx_frame_errors
),
E('td', { 'class': 'td left', 'data-title': _('Transmit') },
' '),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('length errors')),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_rx_length_errors',
'data-title' : _('Receive') },
ifacesStatisticsObject.rx_length_errors
),
E('td', { 'class': 'td left', 'data-title': _('Transmit') },
' '),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('missed errors')),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_rx_missed_errors',
'data-title' : _('Receive') },
ifacesStatisticsObject.rx_missed_errors
),
E('td', { 'class': 'td left', 'data-title': _('Transmit') },
' '),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('over errors')),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_rx_over_errors',
'data-title' : _('Receive') },
ifacesStatisticsObject.rx_over_errors
),
E('td', { 'class': 'td left', 'data-title': _('Transmit') },
' '),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('collisions')),
E('td', { 'class': 'td left', 'data-title': _('Receive') },
' '),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_collisions',
'data-title' : _('Transmit') },
ifacesStatisticsObject.collisions
),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('carrier errors')),
E('td', { 'class': 'td left', 'data-title': _('Receive') },
' '),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_tx_carrier_errors',
'data-title' : _('Transmit') },
ifacesStatisticsObject.tx_carrier_errors
),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('heartbeat errors')),
E('td', { 'class': 'td left', 'data-title': _('Receive') },
' '),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_tx_heartbeat_errors',
'data-title' : _('Transmit') },
ifacesStatisticsObject.tx_heartbeat_errors
),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('aborted errors')),
E('td', { 'class': 'td left', 'data-title': _('Receive') },
' '),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_tx_aborted_errors',
'data-title' : _('Transmit') },
ifacesStatisticsObject.tx_aborted_errors
),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'data-title': _('Parameter') },
_('window errors')),
E('td', { 'class': 'td left', 'data-title': _('Receive') },
' '),
E('td', { 'class': 'td left',
'data-ifstat': ifaceName + '_tx_window_errors',
'data-title' : _('Transmit') },
ifacesStatisticsObject.tx_window_errors
),
]),
]);
ifaceTab.append(E([
E('div', { 'class': 'cbi-value' }, ifaceTable),
E('div', { 'class': 'cbi-value' }, statTable),
]));
tab++;
};
ui.tabs.initTabGroup(tabsContainer.children);
poll.add(L.bind(this.update, this));
};
return E([
E('h2', { 'class': 'fade-in' }, _('Interfaces Statistics')),
E('div', { 'class': 'cbi-section-descr fade-in' }),
ifacesNode,
]);
},
handleSaveApply: null,
handleSave : null,
handleReset : null,
});