Merge pull request #5438 from TDT-AG/pr/20211012-luci-app-vnstat2
[WIP] luci-app-vnstat2: refactoring
This commit is contained in:
commit
70051988c6
3 changed files with 97 additions and 23 deletions
|
@ -1,9 +1,65 @@
|
||||||
// This is free software, licensed under the Apache License, Version 2.0
|
// This is free software, licensed under the Apache License, Version 2.0
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
'require poll';
|
||||||
'require view';
|
'require view';
|
||||||
'require fs';
|
'require fs';
|
||||||
'require ui';
|
'require ui';
|
||||||
|
'require uci';
|
||||||
|
'require rpc';
|
||||||
|
|
||||||
|
var RefreshIfaces = "";
|
||||||
|
var RefreshTabs = ['s', 't', '5', 'h', 'd', 'm', 'y'];
|
||||||
|
|
||||||
|
var callServiceList = rpc.declare({
|
||||||
|
object: 'service',
|
||||||
|
method: 'list',
|
||||||
|
params: [ 'name' ],
|
||||||
|
expect: { '': {} }
|
||||||
|
});
|
||||||
|
|
||||||
|
var isReadonlyView = !L.hasViewPermission() || null;
|
||||||
|
|
||||||
|
function RefreshGraphs() {
|
||||||
|
RefreshTabs.forEach(function (id) {
|
||||||
|
RefreshIfaces.forEach(function (iface) {
|
||||||
|
fs.exec_direct('/usr/bin/vnstati', [ '-' + id, '-i', iface, '-o', '-' ], 'blob').then(function(res) {
|
||||||
|
document.getElementById('graph_' + id + '_' + iface).src = URL.createObjectURL(res);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function IfacesResetData(ev) {
|
||||||
|
ui.showModal(_('Delete data for ALL interfaces'), [
|
||||||
|
E('p', _('The data will be removed from the database permanently. This cannot be undone.')),
|
||||||
|
E('div', { 'class': 'right' }, [
|
||||||
|
E('div', {
|
||||||
|
'class': 'btn',
|
||||||
|
'click': L.hideModal
|
||||||
|
}, _('Cancel')),
|
||||||
|
' ',
|
||||||
|
E('div', {
|
||||||
|
'class': 'btn cbi-button-negative',
|
||||||
|
'click': function(ev) {
|
||||||
|
var if_count = 0;
|
||||||
|
|
||||||
|
RefreshIfaces.forEach(function (iface) {
|
||||||
|
fs.exec_direct('/usr/bin/vnstat', [ '--remove', '-i', iface, '--force' ], 'blob').then(function() {
|
||||||
|
fs.exec_direct('/usr/bin/vnstat', [ '--add', '-i', iface ], 'blob').then(function() {
|
||||||
|
if_count++;
|
||||||
|
if (if_count == RefreshIfaces.length) {
|
||||||
|
RefreshGraphs();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ui.hideModal();
|
||||||
|
}
|
||||||
|
}, _('Delete'))
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
return view.extend({
|
return view.extend({
|
||||||
renderTab: function(ifaces, style, title) {
|
renderTab: function(ifaces, style, title) {
|
||||||
|
@ -16,41 +72,41 @@ return view.extend({
|
||||||
]);
|
]);
|
||||||
|
|
||||||
ifaces.forEach(function(iface) {
|
ifaces.forEach(function(iface) {
|
||||||
tab.appendChild(E('span', {}, E('img', { 'data-iface': iface, 'style': 'visibility:hidden; margin:5px 10px' })));
|
|
||||||
fs.exec_direct('/usr/bin/vnstati', [ '-'+style, '-i', iface, '-o', '-' ], 'blob').then(function(res) {
|
fs.exec_direct('/usr/bin/vnstati', [ '-'+style, '-i', iface, '-o', '-' ], 'blob').then(function(res) {
|
||||||
var img = tab.querySelector('img[data-iface="%s"]'.format(iface));
|
var img = tab.querySelector('img[data-iface="%s"]'.format(iface));
|
||||||
img.src = URL.createObjectURL(res);
|
img.src = URL.createObjectURL(res);
|
||||||
|
img.alt = _('Could not load graph, no data available: ') + iface;
|
||||||
|
img.align = 'middle';
|
||||||
img.style.visibility = 'visible';
|
img.style.visibility = 'visible';
|
||||||
|
img.id = 'graph_' + style + '_' + iface;
|
||||||
tab.firstElementChild.style.display = 'none';
|
tab.firstElementChild.style.display = 'none';
|
||||||
});
|
});
|
||||||
|
tab.appendChild(E('span', {}, E('img', { 'data-iface': iface, 'style': 'visibility:hidden; margin:5px 10px' })));
|
||||||
});
|
});
|
||||||
|
|
||||||
return tab;
|
return tab;
|
||||||
},
|
},
|
||||||
|
|
||||||
load: function() {
|
load: function() {
|
||||||
return fs.exec_direct('/usr/bin/vnstat', [ '--json', 'f', '1' ], 'text').then(function(res) {
|
return Promise.all([
|
||||||
var json = null;
|
L.resolveDefault(callServiceList('vnstat'), {}),
|
||||||
|
uci.load('vnstat'),
|
||||||
try {
|
]);
|
||||||
json = JSON.parse(res)
|
|
||||||
}
|
|
||||||
catch(e) {
|
|
||||||
throw new Error(res.replace(/^Error: /, ''));
|
|
||||||
}
|
|
||||||
|
|
||||||
return (L.isObject(json) ? L.toArray(json.interfaces) : []).map(function(iface) {
|
|
||||||
return iface.name;
|
|
||||||
}).sort();
|
|
||||||
}).catch(function(err) {
|
|
||||||
ui.addNotification(null, E('p', { 'style': 'white-space:pre' }, [err]));
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function(ifaces) {
|
render: function(data) {
|
||||||
|
var ifaces = uci.get_first('vnstat', 'vnstat', 'interface') || [];
|
||||||
|
var isRunning = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
isRunning = data[0]['vnstat']['instances']['instance1']['running'];
|
||||||
|
} catch (e) { }
|
||||||
|
|
||||||
var view = E([], [
|
var view = E([], [
|
||||||
E('h2', [_('vnStat Graphs')]),
|
E('h2', [_('vnStat Graphs')]),
|
||||||
|
|
||||||
|
(isRunning == false) ? E('p', { 'class': 'alert-message warning' }, _('Warning: The service is not running, graphs will not be updated!')):E('p'),
|
||||||
|
|
||||||
E('div', ifaces.length ? [
|
E('div', ifaces.length ? [
|
||||||
this.renderTab(ifaces, 's', _('Summary')),
|
this.renderTab(ifaces, 's', _('Summary')),
|
||||||
this.renderTab(ifaces, 't', _('Top')),
|
this.renderTab(ifaces, 't', _('Top')),
|
||||||
|
@ -58,13 +114,28 @@ return view.extend({
|
||||||
this.renderTab(ifaces, 'h', _('Hourly')),
|
this.renderTab(ifaces, 'h', _('Hourly')),
|
||||||
this.renderTab(ifaces, 'd', _('Daily')),
|
this.renderTab(ifaces, 'd', _('Daily')),
|
||||||
this.renderTab(ifaces, 'm', _('Monthly')),
|
this.renderTab(ifaces, 'm', _('Monthly')),
|
||||||
this.renderTab(ifaces, 'y', _('Yearly'))
|
this.renderTab(ifaces, 'y', _('Yearly')),
|
||||||
] : [ E('em', [_('No monitored interfaces have been found. Go to the configuration to enable monitoring for one or more interfaces.')]) ])
|
] : [ E('em', [_('No monitored interfaces have been found. Go to the configuration to enable monitoring for one or more interfaces.')]) ]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (ifaces.length)
|
if (ifaces.length) {
|
||||||
ui.tabs.initTabGroup(view.lastElementChild.childNodes);
|
ui.tabs.initTabGroup(view.lastElementChild.childNodes);
|
||||||
|
|
||||||
|
view.appendChild(E('div', { 'class': 'right' }, [
|
||||||
|
E('br'),
|
||||||
|
E('button', {
|
||||||
|
'class': 'cbi-button cbi-button-neutral',
|
||||||
|
'click': IfacesResetData,
|
||||||
|
'disabled': isReadonlyView
|
||||||
|
}, [ _('Clear data for all interfaces') ])
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preserve the interfaces for the poll/refresh function
|
||||||
|
RefreshIfaces = ifaces;
|
||||||
|
|
||||||
|
poll.add(RefreshGraphs, 60);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"admin/status/vnstat2": {
|
"admin/status/vnstat2": {
|
||||||
"title": "vnStat Traffic Monitor",
|
"title": "Traffic Monitor",
|
||||||
"order": 90,
|
"order": 90,
|
||||||
"action": {
|
"action": {
|
||||||
"type": "firstchild"
|
"type": "firstchild"
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
"/usr/bin/vnstat --json f 1": [ "exec" ],
|
"/usr/bin/vnstat --json f 1": [ "exec" ],
|
||||||
"/usr/bin/vnstati -[5dhmsty] -i * -o -": [ "exec" ]
|
"/usr/bin/vnstati -[5dhmsty] -i * -o -": [ "exec" ]
|
||||||
},
|
},
|
||||||
|
"ubus": {
|
||||||
|
"service": [ "list" ]
|
||||||
|
},
|
||||||
"uci": [ "vnstat" ]
|
"uci": [ "vnstat" ]
|
||||||
},
|
},
|
||||||
"write": {
|
"write": {
|
||||||
|
|
Loading…
Reference in a new issue