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(plugin_instances
[i
]);
38 if (render_instances
.length
== 0 || render_instances
.length
> 1)
39 render_instances
.unshift('-');
41 Promise
.all(render_instances
.map(function(instance
) {
42 if (instance
== '-') {
45 for (var i
= 0; i
< plugin_instances
.length
; i
++)
46 tasks
.push(rrdtool
.render(plugin
, plugin_instances
[i
], true, host
.value
, span
.value
, width
, null, cache
));
48 return Promise
.all(tasks
).then(function(blobs
) {
49 return Array
.prototype.concat
.apply([], blobs
);
53 return rrdtool
.render(plugin
, instance
, false, host
.value
, span
.value
, width
, null, cache
);
55 })).then(function(blobs
) {
56 var multiple
= blobs
.length
> 1;
58 dom
.content(container
, E('div', {}, blobs
.map(function(blobs
, i
) {
59 var plugin_instance
= i
? plugin_instances
[i
-1] : plugin_instances
.join('|'),
60 title
= '%s: %s'.format(rrdtool
.pluginTitle(plugin
), i
? plugin_instance
: _('Overview'));
64 'data-tab': multiple
? i
: null,
65 'data-tab-title': multiple
? title
: null,
66 'data-plugin': plugin
,
67 'data-plugin-instance': plugin_instance
,
68 'data-is-index': i
? null : true,
69 'cbi-tab-active': function(ev
) { activeInstance
= ev
.target
.getAttribute('data-plugin-instance') }
70 }, blobs
.map(function(blob
) {
72 'src': URL
.createObjectURL(new Blob([blob
], { type
: 'image/png' }))
78 ui
.tabs
.initTabGroup(container
.lastElementChild
.childNodes
);
80 activeInstance
= plugin_instances
.join('|');
84 updateGraphs: function(host
, span
, time
, container
, ev
) {
85 var plugin_names
= rrdtool
.pluginNames(host
.value
);
87 container
.querySelectorAll('img').forEach(function(img
) {
88 URL
.revokeObjectURL(img
.src
);
91 dom
.content(container
, null);
93 if (container
.hasAttribute('data-initialized')) {
94 container
.removeAttribute('data-initialized');
95 container
.parentNode
.removeChild(container
.previousElementSibling
);
98 for (var i
= 0; i
< plugin_names
.length
; i
++) {
99 if (!rrdtool
.hasDefinition(plugin_names
[i
]))
102 container
.appendChild(E('div', {
103 'data-tab': plugin_names
[i
],
104 'data-tab-title': rrdtool
.pluginTitle(plugin_names
[i
]),
105 'cbi-tab-active': L
.bind(this.updatePluginTab
, this, host
, span
, time
)
108 E('em', { 'class': 'spinning' }, [ _('Loading data…') ])
113 ui
.tabs
.initTabGroup(container
.childNodes
);
116 refreshGraphs: function(host
, span
, time
, container
) {
117 var div
= document
.querySelector('[data-plugin="%s"][data-plugin-instance="%s"]'.format(activePlugin
, activeInstance
|| '')),
118 width
= Math
.max(200, container
.offsetWidth
- 100),
119 render_instances
= activeInstance
.split(/\|/);
121 return Promise
.all(render_instances
.map(function(render_instance
) {
122 return rrdtool
.render(activePlugin
, render_instance
|| '', div
.hasAttribute('data-is-index'), host
.value
, span
.value
, width
);
123 })).then(function(blobs
) {
124 return Array
.prototype.concat
.apply([], blobs
);
125 }).then(function(blobs
) {
126 return Promise
.all(blobs
.map(function(blob
) {
127 return new Promise(function(resolveFn
, rejectFn
) {
128 var img
= E('img', { 'src': URL
.createObjectURL(new Blob([blob
], { type
: 'image/png' })) });
129 img
.onload = function(ev
) { resolveFn(img
) };
130 img
.onerror = function(ev
) { resolveFn(img
) };
132 })).then(function(imgs
) {
133 while (div
.childNodes
.length
> imgs
.length
)
134 div
.removeChild(div
.lastElementChild
);
136 for (var i
= 0; i
< imgs
.length
; i
++) {
137 if (i
< div
.childNodes
.length
) {
138 URL
.revokeObjectURL(div
.childNodes
[i
].src
);
139 div
.childNodes
[i
].src
= imgs
[i
].src
;
142 div
.appendChild(E('img', { 'src': imgs
[i
].src
}));
149 togglePolling: function(host
, span
, time
, container
, ev
) {
150 var btn
= ev
.currentTarget
;
157 if (time
.value
!= '0') {
158 pollFn
= L
.bind(this.refreshGraphs
, this, host
, span
, time
, container
);
159 poll
.add(pollFn
, +time
.value
);
164 var hosts
= rrdtool
.hostInstances();
165 return hosts
.length
? this.renderGraphs() : this.renderNoData();
168 renderNoData: function() {
169 ui
.showModal(_('No RRD data found'), [
170 E('p', {}, _('There is no RRD data available yet to render graphs.')),
171 E('p', {}, _('You need to configure <em>collectd</em> to gather data into <em>.rrd</em> files.')),
172 E('div', { 'class': 'right' }, [
174 'class': 'cbi-button',
175 'click': function(ev
) { location
.href
= 'collectd' }
176 }, [ _('Setup collectd') ])
181 renderGraphs: function() {
182 var hostSel
= E('select', { 'style': 'max-width:170px', 'data-name': 'host' }, rrdtool
.hostInstances().map(function(host
) {
184 'selected': (rrdtool
.opts
.host
== host
) ? 'selected' : null
188 var spanSel
= E('select', { 'style': 'max-width:170px', 'data-name': 'timespan' }, L
.toArray(uci
.get('luci_statistics', 'collectd_rrdtool', 'RRATimespans')).map(function(span
) {
190 'selected': (rrdtool
.opts
.timespan
== span
) ? 'selected' : null
194 var timeSel
= E('select', { 'style': 'max-width:170px', 'data-name': 'refresh' }, [
195 E('option', { 'value': 0 }, [ _('Do not refresh') ]),
196 E('option', { 'value': 5 }, [ _('Every 5 seconds') ]),
197 E('option', { 'value': 30 }, [ _('Every 30 seconds') ]),
198 E('option', { 'value': 60 }, [ _('Every minute') ])
201 var graphDiv
= E('div', { 'data-name': 'graphs' });
204 E('h2', {}, [ _('Statistics') ]),
206 E('p', { 'class': 'controls' }, [
207 E('span', { 'class': 'nowrap' }, [
210 'class': 'cbi-button cbi-button-apply',
211 'click': ui
.createHandlerFn(this, 'updateGraphs', hostSel
, spanSel
, timeSel
, graphDiv
, )
212 }, [ _('Display Host »') ]),
215 E('span', { 'class': 'nowrap' }, [
218 'class': 'cbi-button cbi-button-apply',
219 'click': ui
.createHandlerFn(this, 'updateGraphs', hostSel
, spanSel
, timeSel
, graphDiv
)
220 }, [ _('Display timespan »') ]),
223 E('span', { 'class': 'nowrap' }, [
226 'class': 'cbi-button cbi-button-apply',
227 'click': ui
.createHandlerFn(this, 'togglePolling', hostSel
, spanSel
, timeSel
, graphDiv
)
228 }, [ _('Apply interval »') ])
236 requestAnimationFrame(L
.bind(this.updateGraphs
, this, hostSel
, spanSel
, timeSel
, graphDiv
));
242 handleSaveApply
: null,