7 'require statistics.rrdtool as rrdtool';
11 activeInstance
= null;
15 return rrdtool
.load();
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
),
26 activePlugin
= plugin
;
28 dom
.content(container
, [
30 E('em', { 'class': 'spinning' }, [ _('Loading data…') ])
34 for (var i
= 0; i
< plugin_instances
.length
; i
++) {
35 if (rrdtool
.hasInstanceDetails(host
.value
, plugin
, plugin_instances
[i
])) {
36 render_instances
.push([
38 plugin_instances
[i
] ? '%s: %s'.format(rrdtool
.pluginTitle(plugin
), plugin_instances
[i
]) : rrdtool
.pluginTitle(plugin
)
43 if (render_instances
.length
== 0 || render_instances
.length
> 1) {
44 render_instances
.unshift([
46 '%s: %s'.format(rrdtool
.pluginTitle(plugin
), _('Overview'))
50 Promise
.all(render_instances
.map(function(instance
) {
51 if (instance
[0] == '-') {
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
));
57 return Promise
.all(tasks
).then(function(blobs
) {
58 return Array
.prototype.concat
.apply([], blobs
);
62 return rrdtool
.render(plugin
, instance
[0], false, host
.value
, span
.value
, width
, null, cache
);
64 })).then(function(blobs
) {
65 var multiple
= blobs
.length
> 1;
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];
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
) {
81 'src': URL
.createObjectURL(new Blob([blob
], { type
: 'image/png' }))
87 ui
.tabs
.initTabGroup(container
.lastElementChild
.childNodes
);
89 activeInstance
= plugin_instances
.join('|');
93 updateGraphs: function(host
, span
, time
, container
, ev
) {
94 var plugin_names
= rrdtool
.pluginNames(host
.value
);
96 container
.querySelectorAll('img').forEach(function(img
) {
97 URL
.revokeObjectURL(img
.src
);
100 dom
.content(container
, null);
102 if (container
.hasAttribute('data-initialized')) {
103 container
.removeAttribute('data-initialized');
104 container
.parentNode
.removeChild(container
.previousElementSibling
);
107 for (var i
= 0; i
< plugin_names
.length
; i
++) {
108 if (!rrdtool
.hasDefinition(plugin_names
[i
]))
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
)
117 E('em', { 'class': 'spinning' }, [ _('Loading data…') ])
122 ui
.tabs
.initTabGroup(container
.childNodes
);
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(/\|/);
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
) };
141 })).then(function(imgs
) {
142 while (div
.childNodes
.length
> imgs
.length
)
143 div
.removeChild(div
.lastElementChild
);
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
;
151 div
.appendChild(E('img', { 'src': imgs
[i
].src
}));
158 togglePolling: function(host
, span
, time
, container
, ev
) {
159 var btn
= ev
.currentTarget
;
166 if (time
.value
!= '0') {
167 pollFn
= L
.bind(this.refreshGraphs
, this, host
, span
, time
, container
);
168 poll
.add(pollFn
, +time
.value
);
173 var hosts
= rrdtool
.hostInstances();
174 return hosts
.length
? this.renderGraphs() : this.renderNoData();
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' }, [
183 'class': 'cbi-button',
184 'click': function(ev
) { location
.href
= 'collectd' }
185 }, [ _('Set up collectd') ])
190 renderGraphs: function() {
191 var hostSel
= E('select', { 'style': 'max-width:170px', 'data-name': 'host' }, rrdtool
.hostInstances().map(function(host
) {
193 'selected': (rrdtool
.opts
.host
== host
) ? 'selected' : null
197 var spanSel
= E('select', { 'style': 'max-width:170px', 'data-name': 'timespan' }, L
.toArray(uci
.get('luci_statistics', 'collectd_rrdtool', 'RRATimespans')).map(function(span
) {
199 'selected': (rrdtool
.opts
.timespan
== span
) ? 'selected' : null
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') ])
210 var graphDiv
= E('div', { 'data-name': 'graphs' });
213 E('h2', {}, [ _('Statistics') ]),
215 E('p', { 'class': 'controls' }, [
216 E('span', { 'class': 'nowrap' }, [
219 'class': 'cbi-button cbi-button-apply',
220 'click': ui
.createHandlerFn(this, 'updateGraphs', hostSel
, spanSel
, timeSel
, graphDiv
, )
221 }, [ _('Display Host »') ]),
224 E('span', { 'class': 'nowrap' }, [
227 'class': 'cbi-button cbi-button-apply',
228 'click': ui
.createHandlerFn(this, 'updateGraphs', hostSel
, spanSel
, timeSel
, graphDiv
)
229 }, [ _('Display timespan »') ]),
232 E('span', { 'class': 'nowrap' }, [
235 'class': 'cbi-button cbi-button-apply',
236 'click': ui
.createHandlerFn(this, 'togglePolling', hostSel
, spanSel
, timeSel
, graphDiv
)
237 }, [ _('Apply interval »') ])
245 requestAnimationFrame(L
.bind(this.updateGraphs
, this, hostSel
, spanSel
, timeSel
, graphDiv
));
251 handleSaveApply
: null,