summaryrefslogtreecommitdiffhomepage
path: root/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-02-08 22:12:17 +0100
committerJo-Philipp Wich <jo@mein.io>2020-02-12 11:59:41 +0100
commite7d22dce50b4a0c50c9f8ae8c18eeb5a37a51b3e (patch)
tree19a86aed11fae3741f8aa4f773d979f30ba13a1d /applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics
parent2df2958fd6f0206f56116e88693cb7b748e736fa (diff)
luci-app-statistics: convert collectd configuration to client side views
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics')
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/collectd.js160
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/apcups.js33
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/conntrack.js11
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/contextswitch.js11
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/cpu.js33
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/cpufreq.js26
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/csv.js27
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/curl.js32
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/df.js110
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/disk.js49
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/dns.js35
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/email.js52
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/entropy.js11
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/exec.js63
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/interface.js36
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/iptables.js166
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/irq.js60
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/iwinfo.js41
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/load.js11
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/memory.js30
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/netlink.js58
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/network.js72
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/nut.js24
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/olsrd.js51
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/openvpn.js53
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/ping.js43
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/processes.js27
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/rrdtool.js92
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/sensors.js64
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/splash_leases.js11
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/tcpconns.js39
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/thermal.js52
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/unixsock.js36
-rw-r--r--applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/uptime.js11
34 files changed, 1630 insertions, 0 deletions
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/collectd.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/collectd.js
new file mode 100644
index 0000000000..6ba571e8b8
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/collectd.js
@@ -0,0 +1,160 @@
+'use strict';
+'require fs';
+'require ui';
+'require uci';
+'require form';
+
+return L.view.extend({
+ load: function() {
+ return Promise.all([
+ fs.list('/usr/lib/collectd'),
+ fs.list('/usr/share/luci/statistics/plugins')
+ ]).then(function(data) {
+ var installed = data[0],
+ plugins = data[1],
+ tasks = [];
+
+ for (var i = 0; i < plugins.length; i++) {
+ tasks.push(fs.read_direct('/usr/share/luci/statistics/plugins/' + plugins[i].name, 'json').then(L.bind(function(name, spec) {
+ return L.resolveDefault(L.require('view.statistics.plugins.' + name)).then(function(form) {
+ return {
+ name: name,
+ spec: spec,
+ form: form,
+ installed: installed.filter(function(e) { return e.name == name + '.so' }).length > 0
+ };
+ });
+ }, this, plugins[i].name.replace(/\.json$/, ''))));
+ }
+
+ return Promise.all(tasks);
+ });
+ },
+
+ render: function(plugins) {
+ var m, s, o;
+
+ for (var i = 0; i < plugins.length; i++)
+ plugins[plugins[i].name] = plugins[i];
+
+ m = new form.Map('luci_statistics', _('Collectd Settings'));
+ m.tabbed = true;
+
+ s = m.section(form.NamedSection, 'collectd', 'statistics', _('Collectd Settings'));
+
+ o = s.option(form.Value, 'Hostname', _('Hostname'));
+ o.load = function() {
+ return fs.trimmed('/proc/sys/kernel/hostname').then(L.bind(function(name) {
+ this.placeholder = name;
+ return uci.get('collectd', 'statistics', 'hostname');
+ }, this));
+ };
+
+ o = s.option(form.Value, 'BaseDir', _('Base Directory'));
+ o.default = '/var/run/collectd';
+
+ o = s.option(form.Value, 'Include', _('Directory for sub-configurations'));
+ o.default = '/etc/collectd/conf.d/*.conf';
+
+ o = s.option(form.Value, 'PluginDir', _('Directory for collectd plugins'));
+ o.default = '/usr/lib/collectd/';
+
+ o = s.option(form.Value, 'PIDFile', _('Used PID file'));
+ o.default = '/var/run/collectd.pid';
+
+ o = s.option(form.Value, 'TypesDB', _('Datasets definition file'));
+ o.default = '/etc/collectd/types.db';
+
+ o = s.option(form.Value, 'Interval', _('Data collection interval'), _('Seconds'));
+ o.default = '60';
+
+ o = s.option(form.Value, 'ReadThreads', _('Number of threads for data collection'));
+ o.default = '5';
+
+ o = s.option(form.Flag, 'FQDNLookup', _('Try to lookup fully qualified hostname'));
+ o.default = o.disabled;
+ o.optional = true;
+ o.depends('Hostname', '');
+
+ var groupNames = [
+ 'general', _('General plugins'),
+ 'network', _('Network plugins'),
+ 'output', _('Output plugins')
+ ];
+
+ for (var i = 0; i < groupNames.length; i += 2) {
+ s = m.section(form.GridSection, 'statistics_' + groupNames[i], groupNames[i + 1]);
+
+ s.cfgsections = L.bind(function(category) {
+ return this.map.data.sections('luci_statistics', 'statistics')
+ .map(function(s) { return s['.name'] })
+ .filter(function(section_id) {
+ var name = section_id.replace(/^collectd_/, ''),
+ plugin = plugins[name];
+
+ return (section_id.indexOf('collectd_') == 0 && plugin != null &&
+ plugin.installed && plugin.spec.category == category);
+ });
+ }, s, groupNames[i]);
+
+ s.sectiontitle = function(section_id) {
+ var name = section_id.replace(/^collectd_/, ''),
+ plugin = plugins[name];
+
+ return plugin ? plugin.spec.title : name
+ };
+
+ o = s.option(form.Flag, 'enable', _('Enabled'));
+ o.editable = true;
+ o.modalonly = false;
+
+ o = s.option(form.DummyValue, '_dummy', _('Status'));
+ o.width = '50%';
+ o.modalonly = false;
+ o.textvalue = function(section_id) {
+ var name = section_id.replace(/^collectd_/, ''),
+ section = uci.get('luci_statistics', section_id),
+ plugin = plugins[name];
+
+ if (section.enable != '1')
+ return E('em', {}, [_('Plugin is disabled')]);
+
+ var summary = plugin ? plugin.form.configSummary(section) : null;
+ return summary || E('em', _('none'));
+ };
+
+ s.modaltitle = function(section_id) {
+ var name = section_id.replace(/^collectd_/, ''),
+ plugin = plugins[name];
+
+ return plugin ? plugin.form.title : null;
+ };
+
+ s.addModalOptions = function(s) {
+ var name = s.section.replace(/^collectd_/, ''),
+ plugin = plugins[name];
+
+ if (!plugin)
+ return;
+
+ s.description = plugin.form.description;
+
+ plugin.form.addFormOptions(s);
+ };
+
+ s.renderRowActions = function(section_id) {
+ var name = section_id.replace(/^collectd_/, ''),
+ plugin = plugins[name];
+
+ var trEl = this.super('renderRowActions', [ section_id, _('Configureā€¦') ]);
+
+ if (!plugin || !plugin.form.addFormOptions)
+ L.dom.content(trEl, null);
+
+ return trEl;
+ };
+ }
+
+ return m.render();
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/apcups.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/apcups.js
new file mode 100644
index 0000000000..d305994428
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/apcups.js
@@ -0,0 +1,33 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('APCUPS Plugin Configuration'),
+ description: _('The APCUPS plugin collects statistics about the APC UPS.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.DynamicList, 'Host', _('Monitor host'));
+ o.default = 'localhost';
+ o.datatype = 'host';
+ o.depends('enable', '1');
+
+ o = s.option(form.Value, 'Port', _('Port for apcupsd communication'));
+ o.default = '3551';
+ o.datatype = 'port';
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ var hosts = L.toArray(section.Host);
+ if (hosts.length)
+ return N_(hosts.length,
+ 'Monitoring APC UPS at host %s, port %d',
+ 'Monitoring APC UPS at hosts %s, port %d'
+ ).format(hosts.join(', '), section.Port || 3551);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/conntrack.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/conntrack.js
new file mode 100644
index 0000000000..23f14e846c
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/conntrack.js
@@ -0,0 +1,11 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('Conntrack Plugin Configuration'),
+ description: _('The conntrack plugin collects statistics about the number of tracked connections.'),
+
+ configSummary: function(section) {
+ return _('Conntrack monitoring enabled');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/contextswitch.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/contextswitch.js
new file mode 100644
index 0000000000..f4e30fe354
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/contextswitch.js
@@ -0,0 +1,11 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('CPU Context Switches Plugin Configuration'),
+ description: _('This plugin collects statistics about the processor context switches.'),
+
+ configSummary: function(section) {
+ return _('Context switch monitoring enabled');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/cpu.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/cpu.js
new file mode 100644
index 0000000000..71e9c47f3c
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/cpu.js
@@ -0,0 +1,33 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('CPU Plugin Configuration'),
+ description: _('The cpu plugin collects basic statistics about the processor usage.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.Flag, 'ReportByCpu', _('Report by CPU'),
+ _('By setting this, CPU is not aggregate of all processors on the system'));
+ o.default = '1';
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'ReportByState', _('Report by state'),
+ _('When set to true, reports per-state metric (system, user, idle)'));
+ o.default = '1';
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'ValuesPercentage', _('Report in percent'),
+ _('When set to true, we request percentage values'));
+ o.default = '0';
+ o.depends({ 'enable': '1', 'ReportByCpu': '1', 'ReportByState': '1' });
+ },
+
+ configSummary: function(section) {
+ return _('CPU monitoring is enabled');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/cpufreq.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/cpufreq.js
new file mode 100644
index 0000000000..ab3f69172c
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/cpufreq.js
@@ -0,0 +1,26 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('CPU Frequency Plugin Configuration'),
+ description: _('This plugin collects statistics about the processor frequency scaling.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.Flag, 'ExtraItems', _('Extra items'),
+ _('More details about frequency usage and transitions'));
+ o.default = '0';
+ o.optional = true;
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ return (section.ExtraItems == '1')
+ ? _('Detailled CPU frequency monitoring enabled')
+ : _('Simple CPU frequency monitoring enabled');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/csv.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/csv.js
new file mode 100644
index 0000000000..683843ec56
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/csv.js
@@ -0,0 +1,27 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('CSV Plugin Configuration'),
+ description: _('The csv plugin stores collected data in csv file format for further processing by external programs.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.Value, 'DataDir', _('Storage directory for the csv files'));
+ o.default = '127.0.0.1';
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'StoreRates', _('Store data values as rates instead of absolute values'));
+ o.default = '0';
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ if (section.DataDir)
+ return _('Storing CSV data in %s').format(section.DataDir);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/curl.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/curl.js
new file mode 100644
index 0000000000..1ae76f1a8c
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/curl.js
@@ -0,0 +1,32 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('cUrl Plugin Configuration'),
+
+ addFormOptions: function(s) {
+ var o, ss;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.SectionValue, '__pages', form.TableSection, 'collectd_curl_page');
+ o.title = _('Fetch pages');
+ o.depends('enable', '1');
+
+ ss = o.subsection;
+ ss.anonymous = true;
+ ss.addremove = true;
+
+ o = ss.option(form.Flag, 'enable', _('Enable'));
+ o.default = '1';
+
+ o = ss.option(form.Value, 'name', _('Name'));
+
+ o = ss.option(form.Value, 'url', _('URL'));
+ },
+
+ configSummary: function(section) {
+ return _('cURL plugin enabled');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/df.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/df.js
new file mode 100644
index 0000000000..fafe4afe16
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/df.js
@@ -0,0 +1,110 @@
+'use strict';
+'require fs';
+'require form';
+
+return L.Class.extend({
+ title: _('DF Plugin Configuration'),
+ description: _('The df plugin collects statistics about the disk space usage on different devices, mount points or filesystem types.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.DynamicList, 'Devices', _('Monitor devices'));
+ o.optional = true;
+ o.depends('enable', '1');
+ o.load = function(section_id) {
+ return fs.lines('/proc/partitions').then(L.bind(function(lines) {
+ var parts = [];
+
+ for (var i = 0; i < lines.length; i++) {
+ var line = L.toArray(lines[i]);
+ if (!isNaN(line[0]))
+ parts.push('/dev/' + line[3]);
+ }
+
+ parts.sort();
+
+ for (var i = 0; i < parts.length; i++)
+ this.value(parts[i]);
+
+ return this.super('load', [section_id]);
+ }, this));
+ };
+
+ o = s.option(form.DynamicList, 'MountPoints', _('Monitor mount points'));
+ o.default = '/overlay';
+ o.optional = true;
+ o.depends('enable', '1');
+ o.load = function(section_id) {
+ return fs.lines('/proc/mounts').then(L.bind(function(lines) {
+ var mounts = {};
+
+ for (var i = 0; i < lines.length; i++) {
+ var line = L.toArray(lines[i]);
+ mounts[line[1]] = true;
+ }
+
+ mounts = Object.keys(mounts).sort();
+
+ for (var i = 0; i < mounts.length; i++)
+ this.value(mounts[i]);
+
+ return this.super('load', [section_id]);
+ }, this));
+ };
+
+ o = s.option(form.DynamicList, 'FSTypes', _('Monitor filesystem types'));
+ o.default = 'tmpfs';
+ o.optional = true;
+ o.depends('enable', '1');
+ o.load = function(section_id) {
+ return Promise.all([
+ fs.lines('/etc/filesystems'),
+ fs.lines('/proc/filesystems')
+ ]).then(L.bind(function(lines) {
+ var fslines = lines[0].concat(lines[1]),
+ fstypes = {};
+
+ for (var i = 0; i < fslines.length; i++) {
+ var line = L.toArray(fslines[i]);
+
+ if (line.length == 2 && line[0] == 'nodev')
+ continue;
+
+ fstypes[line.pop()] = true;
+ }
+
+ fstypes = Object.keys(fstypes).sort();
+
+ for (var i = 0; i < fstypes.length; i++)
+ this.value(fstypes[i]);
+
+ return this.super('load', [section_id]);
+ }, this));
+ };
+
+ o = s.option(form.Flag, 'IgnoreSelected', _('Monitor all except specified'));
+ o.default = '0';
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ var devs = L.toArray(section.Devices),
+ mounts = L.toArray(section.MountPoints),
+ fstypes = L.toArray(section.FSTypes),
+ count = devs.length + mounts.length + count.length,
+ invert = section.IgnoreSelected == '1';
+
+ if (count == 0)
+ return _('Monitoring all partitions');
+ else
+ return (invert ? _('Monitoring all except %s, %s, %s') : _('Monitoring %s, %s, %s')).format(
+ N_(devs.length, 'one device', '%d devices').format(devs.length),
+ N_(mounts.length, 'one mount', '%d mounts').format(mounts.length),
+ N_(fstypes.length, 'one filesystem type', '%d filesystem types').format(fstypes.length)
+ );
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/disk.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/disk.js
new file mode 100644
index 0000000000..a2664d4eb2
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/disk.js
@@ -0,0 +1,49 @@
+'use strict';
+'require fs';
+'require form';
+
+return L.Class.extend({
+ title: _('Disk Plugin Configuration'),
+ description: _('The disk plugin collects detailed usage statistics for selected partitions or whole disks.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.DynamicList, 'Disks', _('Monitor disks and partitions'),
+ _('When none selected, all disks will be monitored.'));
+ o.rmempty = true;
+ o.depends('enable', '1');
+ o.load = function(section_id) {
+ return fs.trimmed('/proc/partitions').then(L.bind(function(str) {
+ var lines = (str || '').split(/\n/);
+
+ for (var i = 0; i < lines.length; i++) {
+ var m = lines[i].match(/^ +[0-9]+ +[0-9]+ +[0-9]+ (\S+)$/);
+ if (m)
+ this.value(m[1]);
+ }
+
+ return this.super('load', [section_id]);
+ }, this));
+ };
+
+ o = s.option(form.Flag, 'IgnoreSelected', _('Monitor all except specified'));
+ o.default = '0';
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ var disks = L.toArray(section.Disks),
+ invert = section.IgnoreSelected == '1';
+
+ if (disks.length == 0)
+ return _('Monitoring all disks');
+ else if (invert)
+ return N_(disks.length, 'Monitoring all but one disk', 'Monitoring all but %d disks').format(disks.length);
+ else
+ return N_(disks.length, 'Monitoring one disk', 'Monitoring %d disks').format(disks.length);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/dns.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/dns.js
new file mode 100644
index 0000000000..bdca0d65ee
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/dns.js
@@ -0,0 +1,35 @@
+'use strict';
+'require form';
+'require tools.widgets as widgets';
+
+return L.Class.extend({
+ title: _('DNS Plugin Configuration'),
+ description: _('The dns plugin collects detailed statistics about dns related traffic on selected interfaces.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(widgets.DeviceSelect, 'Interfaces', _('Monitor interfaces'),
+ _('When none selected, all interfaces will be monitored.'));
+ o.multiple = true;
+ o.noaliases = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.DynamicList, 'IgnoreSources', _('Ignore source addresses'));
+ o.datatype = 'ipaddr("nomask")';
+ o.default = '127.0.0.1';
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ var ifaces = L.toArray(section.Interfaces);
+
+ if (ifaces.length == 0)
+ return _('Monitoring DNS queries on all interfaces');
+ else
+ return N_(ifaces.length, 'Monitoring DNS queries on one interface', 'Monitoring DNS queries on %d interfaces').format(ifaces.length);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/email.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/email.js
new file mode 100644
index 0000000000..2e0c6340fd
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/email.js
@@ -0,0 +1,52 @@
+'use strict';
+'require form';
+'require tools.widgets as widgets';
+
+return L.Class.extend({
+ title: _('E-Mail Plugin Configuration'),
+ description: _('The email plugin creates a unix socket which can be used to transmit email-statistics to a running collectd daemon. This plugin is primarily intended to be used in conjunction with Mail::SpamAssasin::Plugin::Collectd but can be used in other ways as well.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.Value, 'SocketFile', _('Socket file'));
+ o.default = '/var/run/collect-email.sock';
+ o.depends('enable', '1');
+
+ o = s.option(widgets.GroupSelect, 'SocketGroup', _('Socket group'));
+ o.default = 'nogroup';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Value, 'SocketPerms', _('Socket permissions'));
+ o.default = '0770';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+ o.validate = function(section_id, v) {
+ if (v == '')
+ return true;
+
+ if (!v.match(/^[0-7]{1,4}$/))
+ return _('Expecting permssions in octal notation');
+
+ return true;
+ };
+
+ o = s.option(form.Value, 'MaxConns', _('Maximum allowed connections'));
+ o.datatype = 'range(1,16384)';
+ o.default = '5';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ if (section.SocketFile)
+ return _('Awaiting email input at %s').format(section.SocketFile);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/entropy.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/entropy.js
new file mode 100644
index 0000000000..cf15d98a30
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/entropy.js
@@ -0,0 +1,11 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('Entropy Plugin Configuration'),
+ description: _('The entropy plugin collects statistics about the available entropy.'),
+
+ configSummary: function(section) {
+ return _('Entropy monitoring enabled');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/exec.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/exec.js
new file mode 100644
index 0000000000..093f3fddbc
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/exec.js
@@ -0,0 +1,63 @@
+'use strict';
+'require form';
+'require tools.widgets as widgets';
+
+return L.Class.extend({
+ title: _('Exec Plugin Configuration'),
+ description: _('The exec plugin starts external commands to read values from or to notify external processes when certain threshold values have been reached.'),
+
+ addFormOptions: function(s) {
+ var o, ss;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.SectionValue, '__input', form.TableSection, 'collectd_exec_input');
+ o.title = _('Add command for reading values');
+ o.description = _('Here you can define external commands which will be started by collectd in order to read certain values. The values will be read from stdout.');
+ o.depends('enable', '1');
+
+ ss = o.subsection;
+ ss.anonymous = true;
+ ss.addremove = true;
+
+ o = ss.option(form.Value, 'cmdline', _('Script'));
+ o.default = '/usr/bin/stat-dhcpusers';
+
+ o = ss.option(widgets.UserSelect, 'cmduser', _('User'));
+ o.default = 'nobody';
+ o.optional = true;
+ o.rmempty = true;
+
+ o = ss.option(widgets.GroupSelect, 'cmdgroup', _('Group'));
+ o.default = 'nogroup';
+ o.optional = true;
+ o.rmempty = true;
+
+ o = s.option(form.SectionValue, '__notify', form.TableSection, 'collectd_exec_notify');
+ o.title = _('Add notification command');
+ o.description = _('Here you can define external commands which will be started by collectd when certain threshold values have been reached. The values leading to invocation will be fed to the the called programs stdin.');
+ o.depends('enable', '1');
+
+ ss = o.subsection;
+ ss.anonymous = true;
+ ss.addremove = true;
+
+ o = ss.option(form.Value, 'cmdline', _('Script'));
+ o.default = '/usr/bin/stat-dhcpusers';
+
+ o = ss.option(widgets.UserSelect, 'cmduser', _('User'));
+ o.default = 'nobody';
+ o.optional = true;
+ o.rmempty = true;
+
+ o = ss.option(widgets.GroupSelect, 'cmdgroup', _('Group'));
+ o.default = 'nogroup';
+ o.optional = true;
+ o.rmempty = true;
+ },
+
+ configSummary: function(section) {
+ return _('Command monitoring enabled');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/interface.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/interface.js
new file mode 100644
index 0000000000..178b510a2b
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/interface.js
@@ -0,0 +1,36 @@
+'use strict';
+'require form';
+'require tools.widgets as widgets';
+
+return L.Class.extend({
+ title: _('Interface Plugin Configuration'),
+ description: _('The interface plugin collects traffic statistics on selected interfaces.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(widgets.DeviceSelect, 'Interfaces', _('Monitor interfaces'));
+ o.multiple = true;
+ o.noaliases = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'IgnoreSelected', _('Monitor all except specified'));
+ o.default = '0';
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ var ifaces = L.toArray(section.Interfaces),
+ invert = section.IgnoreSelected == '1';
+
+ if (ifaces.length == 0)
+ return _('Monitoring all interfaces');
+ else if (invert)
+ return N_(ifaces.length, 'Monitoring all but one interface', 'Monitoring all but %d interfaces').format(ifaces.length);
+ else
+ return N_(ifaces.length, 'Monitoring one interface', 'Monitoring %d interfaces').format(ifaces.length);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/iptables.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/iptables.js
new file mode 100644
index 0000000000..a1b67c1b17
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/iptables.js
@@ -0,0 +1,166 @@
+'use strict';
+'require fs';
+'require uci';
+'require form';
+
+return L.Class.extend({
+ title: _('Iptables Plugin Configuration'),
+ description: _('The iptables plugin will monitor selected firewall rules and collect information about processed bytes and packets per rule.'),
+
+ addFormOptions: function(s) {
+ var o, ss;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ for (var family = 4; family <= 6; family += 2) {
+ var suffix = (family == 4 ? '' : '6');
+
+ o = s.option(form.SectionValue, '__match' + suffix, form.TableSection, 'collectd_iptables_match' + suffix,
+ suffix ? _('Match IPv6 iptables rules') : _('Match IPv4 iptables rules'),
+ _('Here you can define various criteria by which the monitored iptables rules are selected.'));
+
+ o.depends('enable', '1');
+ o.load = L.bind(function(suffix, section_id) {
+ return L.resolveDefault(fs.exec_direct('/usr/sbin/ip' + suffix + 'tables-save', []), '').then(L.bind(function(res) {
+ var lines = res.split(/\n/),
+ table, chain, count, iptables = {};
+
+ for (var i = 0; i < lines.length; i++) {
+ var m;
+
+ if ((m = lines[i].match(/^\*(\S+)$/)) != null) {
+ table = m[1];
+ count = {};
+ }
+ else if ((m = lines[i].match(/^-A (.+?) (-.+)$/)) != null) {
+ count[m[1]] = (count[m[1]] || 0) + 1;
+
+ iptables[table] = iptables[table] || {};
+ iptables[table][m[1]] = iptables[table][m[1]] || {};
+ iptables[table][m[1]][count[m[1]]] = E('span', {
+ 'style': 'overflow:hidden; text-overflow:ellipsis; max-width:200px',
+ 'data-tooltip': m[2]
+ }, [
+ '#%d: '.format(count[m[1]]),
+ m[2].replace(/-m comment --comment "(.+?)" /, '')
+ ]);
+
+ /*
+ * collectd currently does not support comments with spaces:
+ * https://github.com/collectd/collectd/issues/2766
+ */
+ var c = m[2].match(/-m comment --comment "(.+)" -/);
+ if (c && c[1] != '!fw3' && !c[1].match(/[ \t\n]/))
+ iptables[table][m[1]][c[1]] = E('span', {}, [ c[1] ]);
+ }
+ }
+
+ this.subsection.iptables = iptables;
+
+ return form.SectionValue.prototype.load.apply(this, [section_id]);
+ }, this));
+ }, o, suffix);
+
+ ss = o.subsection;
+ ss.anonymous = true;
+ ss.addremove = true;
+ ss.addbtntitle = suffix ? _('Add IPv6 rule selector') : _('Add IPv4 rule selector');
+
+ o = ss.option(form.Value, 'name', _('Instance name'));
+ o.datatype = 'maxlength(63)';
+ o.validate = function(section_id, v) {
+ var table_opt = this.section.children.filter(function(o) { return o.option == 'table' })[0],
+ table_elem = table_opt.getUIElement(section_id);
+
+ table_elem.clearChoices();
+ table_elem.addChoices(Object.keys(this.section.iptables).sort());
+
+ if (v != '' && v.match(/[ \t\n]/))
+ return _('The instance name must not contain spaces');
+
+ return true;
+ };
+
+ o = ss.option(form.Value, 'table', _('Table'));
+ o.default = 'filter';
+ o.optional = true;
+ o.rmempty = true;
+ o.transformChoices = function() { return this.super('transformChoices', []) || {} };
+ o.validate = function(section_id, table) {
+ var chain_opt = this.section.children.filter(function(o) { return o.option == 'chain' })[0],
+ chain_elem = chain_opt.getUIElement(section_id);
+
+ chain_elem.clearChoices();
+ chain_elem.addChoices(Object.keys(this.section.iptables[table]).sort());
+
+ return true;
+ };
+
+ o = ss.option(form.Value, 'chain', _('Chain'));
+ o.optional = true;
+ o.rmempty = true;
+ o.transformChoices = function() { return this.super('transformChoices', []) || {} };
+ o.validate = function(section_id, chain) {
+ var table_opt = this.section.children.filter(function(o) { return o.option == 'table' })[0],
+ rule_opt = this.section.children.filter(function(o) { return o.option == 'rule' })[0],
+ rule_elem = rule_opt.getUIElement(section_id),
+ table = table_opt.formvalue(section_id);
+
+ rule_elem.clearChoices();
+
+ if (this.section.iptables[table][chain]) {
+ var keys = Object.keys(this.section.iptables[table][chain]).sort(function(a, b) {
+ var x = a.match(/^(\d+)/),
+ y = b.match(/^(\d+)/);
+
+ if (x && y)
+ return +x[1] > +y[1];
+ else if (x || y)
+ return +!!x > +!!y;
+ else
+ return a > b;
+ });
+
+ var labels = {};
+
+ for (var i = 0; i < keys.length; i++)
+ labels[keys[i]] = this.section.iptables[table][chain][keys[i]].cloneNode(true);
+
+ rule_elem.addChoices(keys, labels);
+ }
+
+ if (chain != '' && chain.match(/[ \t\n]/))
+ return _('The chain name must not contain spaces');
+
+ return true;
+ };
+
+ o = ss.option(form.Value, 'rule', _('Comment / Rule Number'));
+ o.optional = true;
+ o.rmempty = true;
+ o.transformChoices = function() { return this.super('transformChoices', []) || {} };
+ o.load = function(section_id) {
+ var table = uci.get('luci_statistics', section_id, 'table'),
+ chain = uci.get('luci_statistics', section_id, 'chain'),
+ rule = uci.get('luci_statistics', section_id, 'rule'),
+ ipt = this.section.iptables;
+
+ if (ipt[table] && ipt[table][chain] && ipt[table][chain][rule])
+ this.value(rule, ipt[table][chain][rule].cloneNode(true));
+
+ return rule;
+ };
+ o.validate = function(section_id, rule) {
+ if (rule != '' && rule.match(/[ \t\n]/))
+ return _('The comment to match must not contain spaces');
+
+ return true;
+ };
+ }
+ },
+
+ configSummary: function(section) {
+ return _('Rule monitoring enabled');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/irq.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/irq.js
new file mode 100644
index 0000000000..073b9008a1
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/irq.js
@@ -0,0 +1,60 @@
+'use strict';
+'require fs';
+'require form';
+
+return L.Class.extend({
+ title: _('IRQ Plugin Configuration'),
+ description: _('The irq plugin will monitor the rate of issues per second for each selected interrupt. If no interrupt is selected then all interrupts are monitored.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.DynamicList, 'Irqs', _('Monitor interrupts'));
+ o.optional = true;
+ o.multiple = true;
+ o.depends('enable', '1');
+ o.load = function(section_id) {
+ return fs.trimmed('/proc/interrupts').then(L.bind(function(str) {
+ var lines = str.split(/\n/),
+ cpus = L.toArray(lines[0]);
+
+ for (var i = 1; i < lines.length; i++) {
+ var line = lines[i],
+ m = lines[i].match(/^\s*([^\s:]+):/);
+
+ if (!m)
+ continue;
+
+ line = line.replace(/^[^:]+:\s+/, '');
+
+ for (var j = 0; j < cpus.length; j++)
+ line = line.replace(/^\d+\s*/, '');
+
+ var desc = line.split(/ {2,}/).join(', ');
+
+ this.value(m[1], '%s (%s)'.format(m[1], desc || '-'));
+ }
+ }, this));
+ };
+
+ o = s.option(form.Flag, 'IgnoreSelected', _('Monitor all except specified'));
+ o.default = '0';
+ o.optional = 'true';
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ var irqs = L.toArray(section.Irqs),
+ invert = section.IgnoreSelected == '1';
+
+ if (irqs.length == 0)
+ return _('Monitoring all interrupts');
+ else if (invert)
+ return N_(irqs.length, 'Monitoring all but one interrupt', 'Monitoring all but %d interrupts').format(irqs.length);
+ else
+ return N_(irqs.length, 'Monitoring one interrupt', 'Monitoring %d interrupts').format(irqs.length);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/iwinfo.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/iwinfo.js
new file mode 100644
index 0000000000..5f9f73ad34
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/iwinfo.js
@@ -0,0 +1,41 @@
+'use strict';
+'require form';
+'require tools.widgets as widgets';
+
+return L.Class.extend({
+ title: _('Wireless iwinfo Plugin Configuration'),
+ description: _('The iwinfo plugin collects statistics about wireless signal strength, noise and quality.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(widgets.DeviceSelect, 'Interfaces', _('Monitor interfaces'), _('Leave unselected to automatically determine interfaces to monitor.'));
+ o.multiple = true;
+ o.noaliases = true;
+ o.noinactive = true;
+ o.depends('enable', '1');
+ o.filter = function(section_id, name) {
+ var dev = this.devices.filter(function(dev) { return dev.getName() == name })[0];
+ return (dev && dev.getType() == 'wifi');
+ };
+
+ o = s.option(form.Flag, 'IgnoreSelected', _('Monitor all except specified'));
+ o.default = '0';
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ var ifaces = L.toArray(section.Interfaces),
+ invert = section.IgnoreSelected == '1';
+
+ if (ifaces.length == 0)
+ return _('Monitoring all interfaces');
+ else if (invert)
+ return N_(ifaces.length, 'Monitoring all but one interface', 'Monitoring all but %d interfaces').format(ifaces.length);
+ else
+ return N_(ifaces.length, 'Monitoring one interface', 'Monitoring %d interfaces').format(ifaces.length);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/load.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/load.js
new file mode 100644
index 0000000000..be6aba44cd
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/load.js
@@ -0,0 +1,11 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('Load Plugin Configuration'),
+ description: _('The load plugin collects statistics about the general system load.'),
+
+ configSummary: function(section) {
+ return _('Load monitoring enabled');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/memory.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/memory.js
new file mode 100644
index 0000000000..cba3a7bdf7
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/memory.js
@@ -0,0 +1,30 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('Memory Plugin Configuration'),
+ description: _('The memory plugin collects statistics about the memory usage.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.Flag, 'ValuesAbsolute', _('Absolute values'),
+ _('When set to true, we request absolute values'));
+ o.default = '1';
+ o.optional = false;
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'ValuesPercentage', _('Percent values'),
+ _('When set to true, we request percentage values'));
+ o.default = '0';
+ o.optional = false;
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ return _('Memory monitoring enabled');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/netlink.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/netlink.js
new file mode 100644
index 0000000000..ab51632750
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/netlink.js
@@ -0,0 +1,58 @@
+'use strict';
+'require form';
+'require tools.widgets as widgets';
+
+return L.Class.extend({
+ title: _('Netlink Plugin Configuration'),
+ description: _('The netlink plugin collects extended information like qdisc-, class- and filter-statistics for selected interfaces.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(widgets.DeviceSelect, 'Interfaces', _('Basic monitoring'));
+ o.multiple = true;
+ o.noaliases = true;
+ o.depends('enable', '1');
+
+ o = s.option(widgets.DeviceSelect, 'VerboseInterfaces', _('Verbose monitoring'));
+ o.multiple = true;
+ o.noaliases = true;
+ o.depends('enable', '1');
+
+ o = s.option(widgets.DeviceSelect, 'QDiscs', _('Qdisc monitoring'));
+ o.multiple = true;
+ o.noaliases = true;
+ o.depends('enable', '1');
+
+ o = s.option(widgets.DeviceSelect, 'Classes', _('Shaping class monitoring'));
+ o.multiple = true;
+ o.noaliases = true;
+ o.depends('enable', '1');
+
+ o = s.option(widgets.DeviceSelect, 'Filters', _('Filter class monitoring'));
+ o.multiple = true;
+ o.noaliases = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'IgnoreSelected', _('Monitor all except specified'));
+ o.default = '0';
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ var basic = L.toArray(section.Interfaces),
+ verbose = L.toArray(section.VerboseInterfaces),
+ count = basic.length + verbose.length,
+ invert = section.IgnoreSelected == '1';
+
+ if (invert && count == 0)
+ return _('Monitoring all interfaces');
+ else if (invert)
+ return N_(count, 'Monitoring all but one interface', 'Monitoring all but %d interfaces').format(count);
+ else if (count)
+ return N_(count, 'Monitoring one interface', 'Monitoring %d interfaces').format(count);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/network.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/network.js
new file mode 100644
index 0000000000..5fd42ab1e3
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/network.js
@@ -0,0 +1,72 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('Network Plugin Configuration'),
+ description: _('The network plugin provides network based communication between different collectd instances. Collectd can operate both in client and server mode. In client mode locally collected data is transferred to a collectd server instance, in server mode the local instance receives data from other hosts.'),
+
+ addFormOptions: function(s) {
+ var o, ss;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.Value, 'TimeToLive', _('TTL for network packets'));
+ o.default = '128';
+ o.datatype = 'range(0, 255)';
+ o.optional = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'Forward', _('Forwarding between listen and server addresses'));
+ o.default = '0';
+ o.optional = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Value, 'CacheFlush', _('Cache flush interval'),
+ _('Seconds'));
+ o.default = '86400';
+ o.datatype = 'uinteger';
+ o.optional = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.SectionValue, '__listeners', form.TableSection, 'collectd_network_listen');
+ o.title = _('Listener interfaces');
+ o.description = _('This section defines on which interfaces collectd will wait for incoming connections.');
+ o.depends('enable', '1');
+
+ ss = o.subsection;
+ ss.anonymous = true;
+ ss.addremove = true;
+
+ o = ss.option(form.Value, 'host', _('Listen host'));
+ o.default = '0.0.0.0';
+ o.datatype = 'ipaddr("nomask")';
+
+ o = ss.option(form.Value, 'port', _('Listen port'));
+ o.default = '25826';
+ o.datatype = 'port';
+ //o.optional = true;
+
+ o = s.option(form.SectionValue, '__servers', form.TableSection, 'collectd_network_server');
+ o.title = _('Server interfaces');
+ o.description = _('This section defines to which servers the locally collected data is sent to.');
+ o.depends('enable', '1');
+
+ ss = o.subsection;
+ ss.anonymous = true;
+ ss.addremove = true;
+
+ o = ss.option(form.Value, 'host', _('Server host'));
+ o.default = '0.0.0.0';
+ o.datatype = 'ipaddr("nomask")';
+
+ o = ss.option(form.Value, 'port', _('Server port'));
+ o.default = '25826';
+ o.datatype = 'port';
+ //o.optional = true;
+ },
+
+ configSummary: function(section) {
+ return _('Network communication enabled');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/nut.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/nut.js
new file mode 100644
index 0000000000..09845dd3be
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/nut.js
@@ -0,0 +1,24 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('UPS Plugin Configuration'),
+ description: _('The NUT plugin reads information about Uninterruptible Power Supplies.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.Value, 'UPS', _('UPS'), _('UPS name in NUT ups@host format'));
+ o.rmempty = true;
+ },
+
+ configSummary: function(section) {
+ var ups = L.toArray(section.UPS);
+
+ if (ups.length)
+ return N_(ups.length, 'Monitoring one UPS', 'Monitoring %d UPSes').format(ups.length);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/olsrd.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/olsrd.js
new file mode 100644
index 0000000000..72cce12656
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/olsrd.js
@@ -0,0 +1,51 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('OLSRd Plugin Configuration'),
+ description: _('The OLSRd plugin reads information about meshed networks from the txtinfo plugin of OLSRd.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.Value, 'Host', _('Host'),
+ _('IP or hostname where to get the txtinfo output from'));
+ o.datatype = 'host';
+ o.rmempty = true;
+
+ o = s.option(form.Value, 'Port', _('Port'));
+ o.datatype = 'port';
+ o.rmempty = true;
+
+ o = s.option(form.ListValue, 'CollectLinks', _('CollectLinks'),
+ _('Specifies what information to collect about links.'));
+ o.default = 'Detail';
+ o.value('No');
+ o.value('Summary');
+ o.value('Detail');
+
+ o = s.option(form.ListValue, 'CollectRoutes', _('CollectRoutes'),
+ _('Specifies what information to collect about routes.'));
+ o.default = 'Summary';
+ o.value('No');
+ o.value('Summary');
+ o.value('Detail');
+
+ o = s.option(form.ListValue, 'CollectTopology', _('CollectTopology'),
+ _('Specifies what information to collect about the global topology.'));
+ o.default = 'Summary';
+ o.value('No');
+ o.value('Summary');
+ o.value('Detail');
+ },
+
+ configSummary: function(section) {
+ return _('Monitoring OLSRd status at %s:%d').format(
+ section.Host || 'localhost',
+ section.Port || 2006
+ );
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/openvpn.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/openvpn.js
new file mode 100644
index 0000000000..882fc4c345
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/openvpn.js
@@ -0,0 +1,53 @@
+'use strict';
+'require fs';
+'require form';
+
+return L.Class.extend({
+ title: _('OpenVPN Plugin Configuration'),
+ description: _('The OpenVPN plugin gathers information about the current vpn connection status.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.Flag, 'CollectIndividualUsers', _('Generate a separate graph for each logged user'));
+ o.default = '0';
+ o.rmempty = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'CollectUserCount', _('Aggregate number of connected users'));
+ o.default = '0';
+ o.rmempty = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'CollectCompression', _('Gather compression statistics'));
+ o.default = '0';
+ o.rmempty = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'ImprovedNamingSchema', _('Use improved naming schema'));
+ o.default = '0';
+ o.rmempty = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.DynamicList, 'StatusFile', _('OpenVPN status files'));
+ o.rmempty = true;
+ o.depends('enable', '1');
+ o.load = function(section_id) {
+ return L.resolveDefault(fs.list('/var/run'), []).then(L.bind(function(entries) {
+ for (var i = 0; i < entries.length; i++)
+ if (entries[i].type == 'file' && entries[i].name.match(/^openvpn\..+\.status$/))
+ o.value('/var/run/' + entries[i].name);
+ }, this));
+ };
+ },
+
+ configSummary: function(section) {
+ var stats = L.toArray(section.StatusFile);
+
+ if (stats.length)
+ return N_(stats.length, 'Monitoring one OpenVPN instance', 'Monitoring %d OpenVPN instancees').format(stats.length);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/ping.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/ping.js
new file mode 100644
index 0000000000..62958e8488
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/ping.js
@@ -0,0 +1,43 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('Ping Plugin Configuration'),
+ description: _('The ping plugin will send icmp echo replies to selected hosts and measure the roundtrip time for each host.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.DynamicList, 'Hosts', _('Monitor hosts'));
+ o.default = '127.0.0.1';
+ o.datatype = 'ipaddr("nomask")';
+ o.depends('enable', '1');
+
+ o = s.option(form.ListValue, 'AddressFamily', _('Address family'));
+ o.default = 'any';
+ o.depends('enable', '1');
+ o.value('any');
+ o.value('ipv4');
+ o.value('ipv6');
+
+ o = s.option(form.Value, 'TTL', _('TTL for ping packets'));
+ o.default = '128';
+ o.datatype = 'range(0, 255)';
+ o.depends('enable', '1');
+
+ o = s.option(form.Value, 'Interval', _('Interval for pings'), _('Seconds'));
+ o.default = '1.0';
+ o.datatype = 'ufloat';
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ var hosts = L.toArray(section.Hosts);
+
+ if (hosts.length)
+ return N_(hosts.length, 'Monitoring one host', 'Monitoring %d hosts').format(hosts.length);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/processes.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/processes.js
new file mode 100644
index 0000000000..fe2bbccd9d
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/processes.js
@@ -0,0 +1,27 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('Processes Plugin Configuration'),
+ description: _('The processes plugin collects information like cpu time, page faults and memory usage of selected processes.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.DynamicList, 'Processes', _('Monitor processes'));
+ o.default = 'uhttpd dropbear dnsmasq';
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ var processes = L.toArray(section.Processes);
+
+ if (processes.length)
+ return N_(processes.length, 'Monitoring one process', 'Monitoring %d processes').format(processes.length);
+ else
+ return _('Basic process monitoring enabled');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/rrdtool.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/rrdtool.js
new file mode 100644
index 0000000000..82688cac68
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/rrdtool.js
@@ -0,0 +1,92 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('RRDTool Plugin Configuration'),
+ description: _('The rrdtool plugin stores the collected data in rrd database files, the foundation of the diagrams.<br /><br /><strong>Warning: Setting the wrong values will result in a very high memory consumption in the temporary directory. This can render the device unusable!</strong>'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.Value, 'DataDir', _('Storage directory'),
+ _('Note: as pages are rendered by user \'nobody\', the *.rrd files, the storage directory and all its parent directories need to be world readable.'));
+ o.default = '/tmp';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Value, 'StepSize', _('RRD step interval'),
+ _('Seconds'));
+ o.default = '30';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Value, 'HeartBeat', _('RRD heart beat interval'),
+ _('Seconds'));
+ o.default = '60';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'RRASingle', _('Only create average RRAs'),
+ _('reduces rrd size'));
+ o.default = 'true';
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'RRAMax', _('Show max values instead of averages'),
+ _('Max values for a period can be used instead of averages when not using \'only average RRAs\''));
+ o.default = 'false';
+ o.rmempty = true;
+ o.depends('RRASingle', '0');
+
+ o = s.option(form.DynamicList, 'RRATimespans', _('Stored timespans'));
+ o.default = '10min 1day 1week 1month 1year';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+ o.validate = function(section_id, value) {
+ if (value == '')
+ return true;
+
+ if (value.match(/^[0-9]+(?:y|m|w|d|h|min|years?|months?|weeks?|days?|hours?)?$/))
+ return true;
+
+ return _('Expecting valid time range');
+ };
+
+ o = s.option(form.Value, 'RRARows', _('Rows per RRA'));
+ o.default = '100';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Value, 'XFF', _('RRD XFiles Factor'));
+ o.default = '0.1';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Value, 'CacheTimeout', _('Cache collected data for'),
+ _('Seconds'));
+ o.default = '100';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Value, 'CacheFlush', _('Flush cache after'),
+ _('Seconds'));
+ o.default = '100';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ if (section.DataDir)
+ return _('Writing *.rrd files to %s').format(section.DataDir);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/sensors.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/sensors.js
new file mode 100644
index 0000000000..0cf8482539
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/sensors.js
@@ -0,0 +1,64 @@
+'use strict';
+'require fs';
+'require form';
+
+var sensorTypes = [
+ /^[0-9]+(?:\.[0-9]+)?v$/, 'voltage',
+ /^(?:ain|in|vccp|vdd|vid|vin|volt|voltbatt|vrm)[0-9]*$/, 'voltage',
+ /^(?:cpu_temp|remote_temp|temp)[0-9]*$/, 'temperature',
+ /^(?:fan)[0-9]*$/, 'fanspeed',
+ /^(?:power)[0-9]*$/, 'power'
+];
+
+return L.Class.extend({
+ title: _('Sensors Plugin Configuration'),
+ description: _('The sensors plugin uses the Linux Sensors framework to gather environmental statistics.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.DynamicList, 'Sensor', _('Sensor list'));
+ o.rmempty = true;
+ o.size = 18;
+ o.depends('enable', '1');
+ o.load = function(section_id) {
+ return fs.exec_direct('/usr/sbin/sensors', ['-j'], 'json').then(L.bind(function(output) {
+ for (var bus in output) {
+ for (var sensor in output[bus]) {
+ if (!L.isObject(output[bus][sensor]))
+ continue;
+
+ for (var j = 0; j < sensorTypes.length; j += 2) {
+ if (sensor.match(sensorTypes[j])) {
+ this.value('%s/%s-%s'.format(bus, sensorTypes[j + 1], sensor));
+ break;
+ }
+ }
+ }
+ }
+
+ return this.super('load', [section_id]);
+ }, this));
+ };
+
+ o = s.option(form.Flag, 'IgnoreSelected', _('Monitor all except specified'));
+ o.default = '0';
+ o.rmempty = true;
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ var sensors = L.toArray(section.Sensor),
+ invert = section.IgnoreSelected == '1';
+
+ if (invert && sensors.length)
+ return N_(sensors.length, 'Monitoring all but one sensor', 'Monitoring all but %d sensors').format(sensors.length);
+ else if (sensors.length)
+ return N_(sensors.length, 'Monitoring one sensor', 'Monitoring %d sensors').format(sensors.length);
+ else
+ return _('Monitoring all sensors');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/splash_leases.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/splash_leases.js
new file mode 100644
index 0000000000..9db7388608
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/splash_leases.js
@@ -0,0 +1,11 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('Splash Leases Plugin Configuration'),
+ description: _('The splash leases plugin uses libuci to collect statistics about splash leases.'),
+
+ configSummary: function(section) {
+ return _('Monitoring spash leases');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/tcpconns.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/tcpconns.js
new file mode 100644
index 0000000000..2040f86bc4
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/tcpconns.js
@@ -0,0 +1,39 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('TCPConns Plugin Configuration'),
+ description: _('The tcpconns plugin collects information about open tcp connections on selected ports.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.Flag, 'ListeningPorts', _('Monitor all local listen ports'));
+ o.default = '1';
+ o.depends('enable', '1');
+
+ o = s.option(form.Value, 'LocalPorts', _('Monitor local ports'));
+ o.optional = true;
+ o.depends({ enable: '1', ListeningPorts: '0' });
+
+ o = s.option(form.Value, 'RemotePorts', _('Monitor remote ports'));
+ o.optional = true;
+ o.depends({ enable: '1', ListeningPorts: '0' });
+ },
+
+ configSummary: function(section) {
+ var lports = L.toArray(section.LocalPorts),
+ rports = L.toArray(section.RemotePorts);
+
+ if (section.ListeningPorts == '1')
+ return _('Monitoring local listen ports');
+ else
+ return _('Monitoring %s and %s').format(
+ N_(lports.length, 'one local port', '%d local ports').format(lports.length),
+ N_(rports.length, 'one remote port', '%d remote ports').format(rports.length)
+ );
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/thermal.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/thermal.js
new file mode 100644
index 0000000000..bd83944b46
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/thermal.js
@@ -0,0 +1,52 @@
+'use strict';
+'require fs';
+'require form';
+
+return L.Class.extend({
+ title: _('Thermal Plugin Configuration'),
+ description: _('The thermal plugin will monitor temperature of the system. Data is typically read from /sys/class/thermal/*/temp ( \'*\' denotes the thermal device to be read, e.g. thermal_zone1 )'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.DynamicList, 'Device', _('Monitor device(s) / thermal zone(s)'), _('Empty value = monitor all'));
+ o.load = function(section_id) {
+ return Promise.all([
+ L.resolveDefault(fs.list('/sys/class/thermal'), []),
+ L.resolveDefault(fs.list('/proc/acpi/thermal_zone'), [])
+ ]).then(L.bind(function(res) {
+ var entries = res[0].concat(res[1]);
+
+ for (var i = 0; i < entries.length; i++)
+ if (entries[i].type == 'directory' && !entries[i].name.match(/^cooling_device/))
+ o.value(entries[i].name);
+
+ return this.super('load', [ section_id ]);
+ }, this));
+ };
+
+ o.optional = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Flag, 'IgnoreSelected', _('Monitor all except specified'));
+ o.default = '0';
+ o.optional = true;
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ var zones = L.toArray(section.Device),
+ invert = section.IgnoreSelected == '1';
+
+ if (zones.length)
+ return (invert
+ ? _('Monitoring all thermal zones except %s')
+ : _('Monitoring thermal zones %s')
+ ).format(zones.join(', '));
+ else
+ return _('Monitoring all thermal zones');
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/unixsock.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/unixsock.js
new file mode 100644
index 0000000000..1cbdb5f867
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/unixsock.js
@@ -0,0 +1,36 @@
+'use strict';
+'require form';
+'require tools.widgets as widgets';
+
+return L.Class.extend({
+ title: _('Unixsock Plugin Configuration'),
+ description: _('The unixsock plugin creates a unix socket which can be used to read collected data from a running collectd instance.'),
+
+ addFormOptions: function(s) {
+ var o;
+
+ o = s.option(form.Flag, 'enable', _('Enable this plugin'));
+ o.default = '0';
+
+ o = s.option(form.Value, 'SocketFile', _('Socket path'));
+ o.default = '/var/run/collect-query.socket';
+ o.depends('enable', '1');
+
+ o = s.option(widgets.GroupSelect, 'SocketGroup', _('Socket group'), _('Change the ownership of the socket file to the specified group.'));
+ o.placeholder = 'nogroup';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+
+ o = s.option(form.Value, 'SocketPerms', _('Socket permissions'));
+ o.placeholder = '0770';
+ o.optional = true;
+ o.rmempty = true;
+ o.depends('enable', '1');
+ },
+
+ configSummary: function(section) {
+ if (section.SocketFile)
+ return _('Socket %s active').format(section.SocketFile);
+ }
+});
diff --git a/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/uptime.js b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/uptime.js
new file mode 100644
index 0000000000..c31cfd2e90
--- /dev/null
+++ b/applications/luci-app-statistics/htdocs/luci-static/resources/view/statistics/plugins/uptime.js
@@ -0,0 +1,11 @@
+'use strict';
+'require form';
+
+return L.Class.extend({
+ title: _('Uptime Plugin Configuration'),
+ description: _('The uptime plugin collects statistics about the uptime of the system.'),
+
+ configSummary: function(section) {
+ return _('Uptime monitoring enabled');
+ }
+});