]> git.proxmox.com Git - proxmox-backup.git/blob - www/DataStoreSummary.js
ui: datastore: used fixed-width icons for summary
[proxmox-backup.git] / www / DataStoreSummary.js
1 Ext.define('pve-rrd-datastore', {
2 extend: 'Ext.data.Model',
3 fields: [
4 'used',
5 'total',
6 'read_ios',
7 'read_bytes',
8 'write_ios',
9 'write_bytes',
10 'io_ticks',
11 {
12 name: 'io_delay', calculate: function(data) {
13 let ios = 0;
14 if (data.read_ios !== undefined) { ios += data.read_ios; }
15 if (data.write_ios !== undefined) { ios += data.write_ios; }
16 if (data.io_ticks === undefined) {
17 return undefined;
18 } else if (ios === 0) {
19 return 0;
20 }
21 return (data.io_ticks*1000.0)/ios;
22 },
23 },
24 { type: 'date', dateFormat: 'timestamp', name: 'time' },
25 ],
26 });
27
28 Ext.define('PBS.DataStoreInfo', {
29 extend: 'Ext.panel.Panel',
30 alias: 'widget.pbsDataStoreInfo',
31
32 viewModel: {
33 data: {
34 countstext: '',
35 usage: {},
36 stillbad: 0,
37 removedbytes: 0,
38 mountpoint: "",
39 },
40 },
41
42 controller: {
43 xclass: 'Ext.app.ViewController',
44
45 onLoad: function(store, data, success) {
46 if (!success) return;
47 let me = this;
48 let vm = me.getViewModel();
49
50 let counts = store.getById('counts').data.value;
51 let storage = store.getById('storage').data.value;
52
53 let used = Proxmox.Utils.format_size(storage.used);
54 let total = Proxmox.Utils.format_size(storage.total);
55 let percent = 100*storage.used/storage.total;
56 if (storage.total === 0) {
57 percent = 0;
58 }
59 let used_percent = `${percent.toFixed(2)}%`;
60
61 let usage = used_percent + ' (' +
62 Ext.String.format(gettext('{0} of {1}'),
63 used, total) + ')';
64 vm.set('usagetext', usage);
65 vm.set('usage', storage.used/storage.total);
66
67 let gcstatus = store.getById('gc-status').data.value;
68
69 let dedup = (gcstatus['index-data-bytes'] || 0)/
70 (gcstatus['disk-bytes'] || Infinity);
71
72 let countstext = function(count) {
73 return `${count[0]} ${gettext('Groups')}, ${count[1]} ${gettext('Snapshots')}`;
74 };
75
76 vm.set('ctcount', countstext(counts.ct || [0, 0]));
77 vm.set('vmcount', countstext(counts.vm || [0, 0]));
78 vm.set('hostcount', countstext(counts.host || [0, 0]));
79 vm.set('deduplication', dedup.toFixed(2));
80 vm.set('stillbad', gcstatus['still-bad']);
81 vm.set('removedbytes', Proxmox.Utils.format_size(gcstatus['removed-bytes']));
82 },
83
84 startStore: function() { this.store.startUpdate(); },
85 stopStore: function() { this.store.stopUpdate(); },
86
87 init: function(view) {
88 let me = this;
89 let datastore = encodeURIComponent(view.datastore);
90 me.store = Ext.create('Proxmox.data.ObjectStore', {
91 interval: 5*1000,
92 url: `/api2/json/admin/datastore/${datastore}/status`,
93 });
94 me.store.on('load', me.onLoad, me);
95 },
96 },
97
98 listeners: {
99 activate: 'startStore',
100 destroy: 'stopStore',
101 deactivate: 'stopStore',
102 },
103
104 defaults: {
105 xtype: 'pmxInfoWidget',
106 },
107
108 bodyPadding: 20,
109
110 items: [
111 {
112 iconCls: 'fa fa-fw fa-hdd-o',
113 title: gettext('Usage'),
114 bind: {
115 data: {
116 usage: '{usage}',
117 text: '{usagetext}',
118 },
119 },
120 },
121 {
122 xtype: 'box',
123 html: `<b>${gettext('Backup Count')}</b>`,
124 padding: '10 0 5 0',
125 },
126 {
127 iconCls: 'fa fa-fw fa-cube',
128 title: gettext('CT'),
129 printBar: false,
130 bind: {
131 data: {
132 text: '{ctcount}',
133 },
134 },
135 },
136 {
137 iconCls: 'fa fa-fw fa-building',
138 title: gettext('Host'),
139 printBar: false,
140 bind: {
141 data: {
142 text: '{hostcount}',
143 },
144 },
145 },
146 {
147 iconCls: 'fa fa-fw fa-desktop',
148 title: gettext('VM'),
149 printBar: false,
150 bind: {
151 data: {
152 text: '{vmcount}',
153 },
154 },
155 },
156 {
157 xtype: 'box',
158 html: `<b>${gettext('Stats from last Garbage Collection')}</b>`,
159 padding: '10 0 5 0',
160 },
161 {
162 iconCls: 'fa fa-fw fa-compress',
163 title: gettext('Deduplication'),
164 printBar: false,
165 bind: {
166 data: {
167 text: '{deduplication}',
168 },
169 },
170 },
171 {
172 iconCls: 'fa fa-fw fa-trash-o',
173 title: gettext('Removed Bytes'),
174 printBar: false,
175 bind: {
176 data: {
177 text: '{removedbytes}',
178 },
179 },
180 },
181 {
182 iconCls: 'fa critical fa-fw fa-exclamation-triangle',
183 title: gettext('Bad Chunks'),
184 printBar: false,
185 bind: {
186 data: {
187 text: '{stillbad}',
188 },
189 visible: '{stillbad}',
190 },
191 },
192 ],
193 });
194
195 Ext.define('PBS.DataStoreSummary', {
196 extend: 'Ext.panel.Panel',
197 alias: 'widget.pbsDataStoreSummary',
198 mixins: ['Proxmox.Mixin.CBind'],
199
200 layout: 'column',
201 scrollable: true,
202
203 bodyPadding: 5,
204 defaults: {
205 columnWidth: 1,
206 padding: 5,
207 },
208
209 tbar: ['->', { xtype: 'proxmoxRRDTypeSelector' }],
210
211 items: [
212 {
213 xtype: 'container',
214 height: 300,
215 layout: {
216 type: 'hbox',
217 align: 'stretch',
218 },
219 items: [
220 {
221 xtype: 'pbsDataStoreInfo',
222 flex: 1,
223 padding: '0 10 0 0',
224 cbind: {
225 title: '{datastore}',
226 datastore: '{datastore}',
227 },
228 },
229 {
230 xtype: 'pbsDataStoreNotes',
231 flex: 1,
232 cbind: {
233 datastore: '{datastore}',
234 },
235 },
236 ],
237 },
238 {
239 xtype: 'proxmoxRRDChart',
240 title: gettext('Storage usage (bytes)'),
241 fields: ['total', 'used'],
242 fieldTitles: [gettext('Total'), gettext('Storage usage')],
243 },
244 {
245 xtype: 'proxmoxRRDChart',
246 title: gettext('Transfer Rate (bytes/second)'),
247 fields: ['read_bytes', 'write_bytes'],
248 fieldTitles: [gettext('Read'), gettext('Write')],
249 },
250 {
251 xtype: 'proxmoxRRDChart',
252 title: gettext('Input/Output Operations per Second (IOPS)'),
253 fields: ['read_ios', 'write_ios'],
254 fieldTitles: [gettext('Read'), gettext('Write')],
255 },
256 {
257 xtype: 'proxmoxRRDChart',
258 title: gettext('IO Delay (ms)'),
259 fields: ['io_delay'],
260 fieldTitles: [gettext('IO Delay')],
261 },
262 ],
263
264 listeners: {
265 activate: function() { this.rrdstore.startUpdate(); },
266 deactivate: function() { this.rrdstore.stopUpdate(); },
267 destroy: function() { this.rrdstore.stopUpdate(); },
268 },
269
270 initComponent: function() {
271 let me = this;
272
273 me.rrdstore = Ext.create('Proxmox.data.RRDStore', {
274 rrdurl: "/api2/json/admin/datastore/" + me.datastore + "/rrd",
275 model: 'pve-rrd-datastore',
276 });
277
278 me.callParent();
279
280 Proxmox.Utils.API2Request({
281 url: `/config/datastore/${me.datastore}`,
282 waitMsgTarget: me.down('pbsDataStoreInfo'),
283 success: function(response) {
284 let path = Ext.htmlEncode(response.result.data.path);
285 me.down('pbsDataStoreInfo').setTitle(`${me.datastore} (${path})`);
286 me.down('pbsDataStoreNotes').setNotes(response.result.data.comment);
287 },
288 });
289
290 me.query('proxmoxRRDChart').forEach((chart) => {
291 chart.setStore(me.rrdstore);
292 });
293
294 me.down('pbsDataStoreInfo').relayEvents(me, ['activate', 'deactivate']);
295 },
296 });