uci-app-vnstat2: refactoring 5438/head
authorHelge Mader <ma@dev.tdt.de>
Thu, 3 Feb 2022 12:48:10 +0000 (13:48 +0100)
committerHelge Mader <ma@dev.tdt.de>
Thu, 3 Feb 2022 12:48:10 +0000 (13:48 +0100)
This is a huge change to the already existing vnstat2 LuCI module with some
improvements and some new features.

"Graphs Page":

  - Implementation of refreshing the graphs.

  - Only in the UCI configuration existing interfaces will be shown in any
    case. Before this change, all interfaces existing in the database were
    shown.

  - Introduced a button to clear the statistics for all interfaces (in fact
    this is removing and adding again the interfaces from/to the database).

    Before clearing the data a confirmation dialog is shown.

  - Show user hint if service is not running, so no updating of graphs.

  - "Error image" for a graph which can not be loaded

General:

  - Updated translations, added missing translations for ./po/de

  - Renamed the menu entry from "vnStat Traffic Monitor" to "Traffic Monitor" only

Signed-off-by: Helge Mader <ma@dev.tdt.de>
applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/graphs.js
applications/luci-app-vnstat2/root/usr/share/luci/menu.d/luci-app-vnstat2.json
applications/luci-app-vnstat2/root/usr/share/rpcd/acl.d/luci-app-vnstat2.json

index 7ac3b3f7e779e239e3187ab961ffdab7976a97f3..7113c4119e070c94894de76c8fa9fdc2d52800ba 100644 (file)
@@ -1,9 +1,65 @@
 // This is free software, licensed under the Apache License, Version 2.0
 
 'use strict';
+'require poll';
 'require view';
 'require fs';
 '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({
        renderTab: function(ifaces, style, title) {
@@ -16,41 +72,41 @@ return view.extend({
                ]);
 
                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) {
                                var img = tab.querySelector('img[data-iface="%s"]'.format(iface));
                                img.src = URL.createObjectURL(res);
+                               img.alt = _('Could not load graph, no data available: ') + iface;
+                               img.align = 'middle';
                                img.style.visibility = 'visible';
+                               img.id = 'graph_' + style + '_' + iface;
                                tab.firstElementChild.style.display = 'none';
                        });
+                       tab.appendChild(E('span', {}, E('img', { 'data-iface': iface, 'style': 'visibility:hidden; margin:5px 10px' })));
                });
 
                return tab;
        },
 
        load: function() {
-               return fs.exec_direct('/usr/bin/vnstat', [ '--json', 'f', '1' ], 'text').then(function(res) {
-                       var json = null;
-
-                       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 [];
-               });
+               return Promise.all([
+                       L.resolveDefault(callServiceList('vnstat'), {}),
+                       uci.load('vnstat'),
+               ]);
        },
 
-       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([], [
                        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 ? [
                                this.renderTab(ifaces, 's', _('Summary')),
                                this.renderTab(ifaces, 't', _('Top')),
@@ -58,13 +114,28 @@ return view.extend({
                                this.renderTab(ifaces, 'h', _('Hourly')),
                                this.renderTab(ifaces, 'd', _('Daily')),
                                this.renderTab(ifaces, 'm', _('Monthly')),
-                               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.')]) ])
+                               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.')]) ]),
                ]);
 
-               if (ifaces.length)
+               if (ifaces.length) {
                        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;
        },
 
index 4aa9dd2aa05f4d41da2fe876054fb0c974b19343..eed7b0a2d7358089385c38ec3b36bad567eb2117 100644 (file)
@@ -1,6 +1,6 @@
 {
        "admin/status/vnstat2": {
-               "title": "vnStat Traffic Monitor",
+               "title": "Traffic Monitor",
                "order": 90,
                "action": {
                        "type": "firstchild"
index 7acf74bd59efa79a8b62c93ae5d906965dc72038..5be965a99c395a2168964ba94607d4b9b3780d42 100644 (file)
@@ -7,6 +7,9 @@
                                "/usr/bin/vnstat --json f 1": [ "exec" ],
                                "/usr/bin/vnstati -[5dhmsty] -i * -o -": [ "exec" ]
                        },
+                       "ubus": {
+                               "service": [ "list" ]
+                       },
                        "uci": [ "vnstat" ]
                },
                "write": {