luci-app-vnstat2: fully convert to client side rendering
This converts the graph rendering to client side JavaScript and replaces the route registration with declarative JSON. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
parent
7cfce56553
commit
40c56ddd77
5 changed files with 113 additions and 105 deletions
|
@ -0,0 +1,73 @@
|
||||||
|
// This is free software, licensed under the Apache License, Version 2.0
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
'require fs';
|
||||||
|
'require ui';
|
||||||
|
|
||||||
|
return L.view.extend({
|
||||||
|
renderTab: function(ifaces, style, title) {
|
||||||
|
var tab = E('div', {
|
||||||
|
'class': 'cbi-section',
|
||||||
|
'data-tab': style,
|
||||||
|
'data-tab-title': title
|
||||||
|
}, [
|
||||||
|
E('p', {}, E('em', { 'class': 'spinning' }, [ _('Loading graphs…') ]))
|
||||||
|
]);
|
||||||
|
|
||||||
|
ifaces.forEach(function(iface) {
|
||||||
|
tab.appendChild(E('p', {}, E('img', { 'data-iface': iface, 'style': 'display:none' })));
|
||||||
|
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.style.display = '';
|
||||||
|
tab.firstElementChild.style.display = 'none';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
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 [];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function(ifaces) {
|
||||||
|
var view = E([], [
|
||||||
|
E('h2', [_('vnStat Graphs')]),
|
||||||
|
E('div', ifaces.length ? [
|
||||||
|
this.renderTab(ifaces, 's', _('Summary')),
|
||||||
|
this.renderTab(ifaces, 't', _('Top')),
|
||||||
|
this.renderTab(ifaces, '5', _('5 Minute')),
|
||||||
|
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.')]) ])
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (ifaces.length)
|
||||||
|
ui.tabs.initTabGroup(view.lastElementChild.childNodes);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSave: null,
|
||||||
|
handleSaveApply: null,
|
||||||
|
handleReset: null
|
||||||
|
});
|
|
@ -1,50 +0,0 @@
|
||||||
module("luci.controller.vnstat2", package.seeall)
|
|
||||||
|
|
||||||
function index()
|
|
||||||
if not nixio.fs.access("/etc/config/vnstat") then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
entry({"admin", "status", "vnstat2"}, alias("admin", "status", "vnstat2", "graphs"), _("vnStat Traffic Monitor"), 90)
|
|
||||||
entry({"admin", "status", "vnstat2", "graphs"}, template("vnstat2/graphs"), _("Graphs"), 1)
|
|
||||||
entry({"admin", "status", "vnstat2", "config"}, view("vnstat2/config"), _("Configuration"), 2)
|
|
||||||
entry({"admin", "status", "vnstat2", "graph"}, call("action_graph"), nil, 3)
|
|
||||||
end
|
|
||||||
|
|
||||||
function action_graph()
|
|
||||||
local util = require "luci.util"
|
|
||||||
|
|
||||||
local param = luci.http.formvalue
|
|
||||||
|
|
||||||
local iface = param("iface")
|
|
||||||
local style = param("style")
|
|
||||||
|
|
||||||
if not iface or not style then
|
|
||||||
luci.http.status(404, "Not Found")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local style_valid = false
|
|
||||||
for _, v in ipairs({"s", "t", "5", "h", "d", "m", "y"}) do
|
|
||||||
if v == style then
|
|
||||||
style_valid = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not style_valid then
|
|
||||||
luci.http.status(404, "Not Found")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
luci.http.prepare_content("image/png")
|
|
||||||
|
|
||||||
local cmd = "vnstati -i %s -%s -o -" % {
|
|
||||||
util.shellquote(iface),
|
|
||||||
util.shellquote(style)
|
|
||||||
}
|
|
||||||
|
|
||||||
local image = io.popen(cmd)
|
|
||||||
luci.http.write(image:read("*a"))
|
|
||||||
image:close()
|
|
||||||
end
|
|
|
@ -1,55 +0,0 @@
|
||||||
<%#
|
|
||||||
This is free software, licensed under the Apache License, Version 2.0
|
|
||||||
-%>
|
|
||||||
|
|
||||||
<%-
|
|
||||||
|
|
||||||
local util = require "luci.util"
|
|
||||||
local json = require "luci.jsonc"
|
|
||||||
|
|
||||||
|
|
||||||
local ifaces = {}
|
|
||||||
|
|
||||||
local data = util.exec("vnstat --json f 1 2>/dev/null")
|
|
||||||
local content = json.parse(data)
|
|
||||||
if type(content) == "table" then
|
|
||||||
for _, iface in pairs(content["interfaces"]) do
|
|
||||||
table.insert(ifaces, iface["name"])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function render_section(style, title)
|
|
||||||
%><div class="cbi-section" data-tab="<%=style%>" data-tab-title="<%=title%>"><%
|
|
||||||
|
|
||||||
for _, iface in ipairs(ifaces) do
|
|
||||||
%><p><img src="<%=url("admin/status/vnstat2/graph")%>?iface=<%=iface%>&style=<%=style%>" alt="" style="max-width:100%" /></p><%
|
|
||||||
end
|
|
||||||
|
|
||||||
%></div><%
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-%>
|
|
||||||
|
|
||||||
<%+header%>
|
|
||||||
|
|
||||||
<h2 name="content"><%:vnStat Graphs%></h2>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<%
|
|
||||||
if #ifaces == 0 then
|
|
||||||
%><p><em><%:No monitored interfaces have been found. Go to the configuration to enable monitoring for one or more interfaces.%></em></p><%
|
|
||||||
else
|
|
||||||
render_section("s", translate("Summary"))
|
|
||||||
render_section("t", translate("Top"))
|
|
||||||
render_section("5", translate("5 Minute"))
|
|
||||||
render_section("h", translate("Hourly"))
|
|
||||||
render_section("d", translate("Daily"))
|
|
||||||
render_section("m", translate("Monthly"))
|
|
||||||
render_section("y", translate("Yearly"))
|
|
||||||
end
|
|
||||||
%>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<%+footer%>
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"admin/status/vnstat2": {
|
||||||
|
"title": "vnStat Traffic Monitor",
|
||||||
|
"order": 90,
|
||||||
|
"action": {
|
||||||
|
"type": "firstchild"
|
||||||
|
},
|
||||||
|
"depends": {
|
||||||
|
"fs": {
|
||||||
|
"/usr/bin/vnstat": "executable",
|
||||||
|
"/usr/bin/vnstati": "executable"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"admin/status/vnstat2/graphs": {
|
||||||
|
"title": "Graphs",
|
||||||
|
"order": 1,
|
||||||
|
"action": {
|
||||||
|
"type": "view",
|
||||||
|
"path": "vnstat2/graphs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"admin/status/vnstat2/config": {
|
||||||
|
"title": "Configuration",
|
||||||
|
"order": 2,
|
||||||
|
"action": {
|
||||||
|
"type": "view",
|
||||||
|
"path": "vnstat2/config"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,13 @@
|
||||||
{
|
{
|
||||||
"luci-app-vnstat2": {
|
"luci-app-vnstat2": {
|
||||||
"description": "Grant access to LuCI app vnstat2",
|
"description": "Grant access to LuCI app vnstat2",
|
||||||
|
"read": {
|
||||||
|
"cgi-io": [ "exec" ],
|
||||||
|
"file": {
|
||||||
|
"/usr/bin/vnstat --json f 1": [ "exec" ],
|
||||||
|
"/usr/bin/vnstati -[5dhmsty] -i * -o -": [ "exec" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
"write": {
|
"write": {
|
||||||
"file": {
|
"file": {
|
||||||
"/usr/bin/vnstat": [ "exec" ]
|
"/usr/bin/vnstat": [ "exec" ]
|
||||||
|
|
Loading…
Reference in a new issue