luci-app-statistics: grammar fixes
[project/luci.git] / applications / luci-app-statistics / htdocs / luci-static / resources / view / statistics / graphs.js
1 'use strict';
2 'require view';
3 'require dom';
4 'require poll';
5 'require ui';
6 'require uci';
7 'require statistics.rrdtool as rrdtool';
8
9 var pollFn = null,
10 activePlugin = null,
11 activeInstance = null;
12
13 return view.extend({
14 load: function() {
15 return rrdtool.load();
16 },
17
18 updatePluginTab: function(host, span, time, ev) {
19 var container = ev.target,
20 width = Math.max(200, container.offsetWidth - 100),
21 plugin = ev.detail.tab,
22 render_instances = [],
23 plugin_instances = rrdtool.pluginInstances(host.value, plugin),
24 cache = {};
25
26 activePlugin = plugin;
27
28 dom.content(container, [
29 E('p', {}, [
30 E('em', { 'class': 'spinning' }, [ _('Loading data…') ])
31 ])
32 ]);
33
34 for (var i = 0; i < plugin_instances.length; i++) {
35 if (rrdtool.hasInstanceDetails(host.value, plugin, plugin_instances[i])) {
36 render_instances.push([
37 plugin_instances[i],
38 plugin_instances[i] ? '%s: %s'.format(rrdtool.pluginTitle(plugin), plugin_instances[i]) : rrdtool.pluginTitle(plugin)
39 ]);
40 }
41 }
42
43 if (render_instances.length == 0 || render_instances.length > 1) {
44 render_instances.unshift([
45 '-',
46 '%s: %s'.format(rrdtool.pluginTitle(plugin), _('Overview'))
47 ]);
48 }
49
50 Promise.all(render_instances.map(function(instance) {
51 if (instance[0] == '-') {
52 var tasks = [];
53
54 for (var i = 0; i < plugin_instances.length; i++)
55 tasks.push(rrdtool.render(plugin, plugin_instances[i], true, host.value, span.value, width, null, cache));
56
57 return Promise.all(tasks).then(function(blobs) {
58 return Array.prototype.concat.apply([], blobs);
59 });
60 }
61 else {
62 return rrdtool.render(plugin, instance[0], false, host.value, span.value, width, null, cache);
63 }
64 })).then(function(blobs) {
65 var multiple = blobs.length > 1;
66
67 dom.content(container, E('div', {}, blobs.map(function(blobs, i) {
68 var plugin_instance = i ? render_instances[i][0] : plugin_instances.join('|'),
69 title = render_instances[i][1];
70
71 return E('div', {
72 'class': 'center',
73 'data-tab': multiple ? i : null,
74 'data-tab-title': multiple ? title : null,
75 'data-plugin': plugin,
76 'data-plugin-instance': plugin_instance,
77 'data-is-index': i ? null : true,
78 'cbi-tab-active': function(ev) { activeInstance = ev.target.getAttribute('data-plugin-instance') }
79 }, blobs.map(function(blob) {
80 return E('img', {
81 'src': URL.createObjectURL(new Blob([blob], { type: 'image/png' }))
82 });
83 }));
84 })));
85
86 if (multiple)
87 ui.tabs.initTabGroup(container.lastElementChild.childNodes);
88 else
89 activeInstance = plugin_instances.join('|');
90 });
91 },
92
93 updateGraphs: function(host, span, time, container, ev) {
94 var plugin_names = rrdtool.pluginNames(host.value);
95
96 container.querySelectorAll('img').forEach(function(img) {
97 URL.revokeObjectURL(img.src);
98 });
99
100 dom.content(container, null);
101
102 if (container.hasAttribute('data-initialized')) {
103 container.removeAttribute('data-initialized');
104 container.parentNode.removeChild(container.previousElementSibling);
105 }
106
107 for (var i = 0; i < plugin_names.length; i++) {
108 if (!rrdtool.hasDefinition(plugin_names[i]))
109 continue;
110
111 container.appendChild(E('div', {
112 'data-tab': plugin_names[i],
113 'data-tab-title': rrdtool.pluginTitle(plugin_names[i]),
114 'cbi-tab-active': L.bind(this.updatePluginTab, this, host, span, time)
115 }, [
116 E('p', {}, [
117 E('em', { 'class': 'spinning' }, [ _('Loading data…') ])
118 ])
119 ]));
120 }
121
122 ui.tabs.initTabGroup(container.childNodes);
123 },
124
125 refreshGraphs: function(host, span, time, container) {
126 var div = document.querySelector('[data-plugin="%s"][data-plugin-instance="%s"]'.format(activePlugin, activeInstance || '')),
127 width = Math.max(200, container.offsetWidth - 100),
128 render_instances = activeInstance.split(/\|/);
129
130 return Promise.all(render_instances.map(function(render_instance) {
131 return rrdtool.render(activePlugin, render_instance || '', div.hasAttribute('data-is-index'), host.value, span.value, width);
132 })).then(function(blobs) {
133 return Array.prototype.concat.apply([], blobs);
134 }).then(function(blobs) {
135 return Promise.all(blobs.map(function(blob) {
136 return new Promise(function(resolveFn, rejectFn) {
137 var img = E('img', { 'src': URL.createObjectURL(new Blob([blob], { type: 'image/png' })) });
138 img.onload = function(ev) { resolveFn(img) };
139 img.onerror = function(ev) { resolveFn(img) };
140 });
141 })).then(function(imgs) {
142 while (div.childNodes.length > imgs.length)
143 div.removeChild(div.lastElementChild);
144
145 for (var i = 0; i < imgs.length; i++) {
146 if (i < div.childNodes.length) {
147 URL.revokeObjectURL(div.childNodes[i].src);
148 div.childNodes[i].src = imgs[i].src;
149 }
150 else {
151 div.appendChild(E('img', { 'src': imgs[i].src }));
152 }
153 }
154 });
155 });
156 },
157
158 togglePolling: function(host, span, time, container, ev) {
159 var btn = ev.currentTarget;
160
161 if (pollFn) {
162 poll.remove(pollFn);
163 pollFn = null;
164 }
165
166 if (time.value != '0') {
167 pollFn = L.bind(this.refreshGraphs, this, host, span, time, container);
168 poll.add(pollFn, +time.value);
169 }
170 },
171
172 render: function() {
173 var hosts = rrdtool.hostInstances();
174 return hosts.length ? this.renderGraphs() : this.renderNoData();
175 },
176
177 renderNoData: function() {
178 ui.showModal(_('No RRD data found'), [
179 E('p', {}, _('There is no RRD data available yet to render graphs.')),
180 E('p', {}, _('You need to configure <em>collectd</em> to gather data into <em>.rrd</em> files.')),
181 E('div', { 'class': 'right' }, [
182 E('button', {
183 'class': 'cbi-button',
184 'click': function(ev) { location.href = 'collectd' }
185 }, [ _('Set up collectd') ])
186 ])
187 ]);
188 },
189
190 renderGraphs: function() {
191 var hostSel = E('select', { 'style': 'max-width:170px', 'data-name': 'host' }, rrdtool.hostInstances().map(function(host) {
192 return E('option', {
193 'selected': (rrdtool.opts.host == host) ? 'selected' : null
194 }, [ host ])
195 }));
196
197 var spanSel = E('select', { 'style': 'max-width:170px', 'data-name': 'timespan' }, L.toArray(uci.get('luci_statistics', 'collectd_rrdtool', 'RRATimespans')).map(function(span) {
198 return E('option', {
199 'selected': (rrdtool.opts.timespan == span) ? 'selected' : null
200 }, [ span ])
201 }));
202
203 var timeSel = E('select', { 'style': 'max-width:170px', 'data-name': 'refresh' }, [
204 E('option', { 'value': 0 }, [ _('Do not refresh') ]),
205 E('option', { 'value': 5 }, [ _('Every 5 seconds') ]),
206 E('option', { 'value': 30 }, [ _('Every 30 seconds') ]),
207 E('option', { 'value': 60 }, [ _('Every minute') ])
208 ]);
209
210 var graphDiv = E('div', { 'data-name': 'graphs' });
211
212 var view = E([], [
213 E('h2', {}, [ _('Statistics') ]),
214 E('div', {}, [
215 E('p', { 'class': 'controls' }, [
216 E('span', { 'class': 'nowrap' }, [
217 hostSel,
218 E('button', {
219 'class': 'cbi-button cbi-button-apply',
220 'click': ui.createHandlerFn(this, 'updateGraphs', hostSel, spanSel, timeSel, graphDiv, )
221 }, [ _('Display Host »') ]),
222 ]),
223 ' ',
224 E('span', { 'class': 'nowrap' }, [
225 spanSel,
226 E('button', {
227 'class': 'cbi-button cbi-button-apply',
228 'click': ui.createHandlerFn(this, 'updateGraphs', hostSel, spanSel, timeSel, graphDiv)
229 }, [ _('Display timespan »') ]),
230 ]),
231 ' ',
232 E('span', { 'class': 'nowrap' }, [
233 timeSel,
234 E('button', {
235 'class': 'cbi-button cbi-button-apply',
236 'click': ui.createHandlerFn(this, 'togglePolling', hostSel, spanSel, timeSel, graphDiv)
237 }, [ _('Apply interval »') ])
238 ])
239 ]),
240 E('hr'),
241 graphDiv
242 ])
243 ]);
244
245 requestAnimationFrame(L.bind(this.updateGraphs, this, hostSel, spanSel, timeSel, graphDiv));
246
247 return view;
248 },
249
250 handleSave: null,
251 handleSaveApply: null,
252 handleReset: null
253 });