]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/storage/ContentView.js
use TimezoneStore from widget toolkit
[pve-manager.git] / www / manager6 / storage / ContentView.js
CommitLineData
4a580e60
DM
1Ext.define('PVE.grid.TemplateSelector', {
2 extend: 'Ext.grid.GridPanel',
3
3f90858a 4 alias: 'widget.pveTemplateSelector',
4a580e60 5
1b14c875
DC
6 stateful: true,
7 stateId: 'grid-template-selector',
3b422683
DC
8 viewConfig: {
9 trackOver: false
10 },
4a580e60
DM
11 initComponent : function() {
12 var me = this;
13
14 if (!me.nodename) {
15 throw "no node name specified";
16 }
17
18 var baseurl = "/nodes/" + me.nodename + "/aplinfo";
19 var store = new Ext.data.Store({
20 model: 'pve-aplinfo',
21 groupField: 'section',
22 proxy: {
23 type: 'pve',
24 url: '/api2/json' + baseurl
25 }
26 });
27
28 var sm = Ext.create('Ext.selection.RowModel', {});
29
30 var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
31 groupHeaderTpl: '{[ "Section: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
32 });
33
34 var reload = function() {
35 store.load();
36 };
37
e7ade592 38 Proxmox.Utils.monStoreErrors(me, store);
4a580e60
DM
39
40 Ext.apply(me, {
41 store: store,
42 selModel: sm,
4a580e60
DM
43 features: [ groupingFeature ],
44 columns: [
45 {
46 header: gettext('Type'),
47 width: 80,
48 dataIndex: 'type'
49 },
50 {
51 header: gettext('Package'),
52 flex: 1,
53 dataIndex: 'package'
54 },
55 {
56 header: gettext('Version'),
57 width: 80,
58 dataIndex: 'version'
59 },
60 {
61 header: gettext('Description'),
62 flex: 1.5,
91535f2b 63 renderer: Ext.String.htmlEncode,
4a580e60
DM
64 dataIndex: 'headline'
65 }
66 ],
67 listeners: {
68 afterRender: reload
69 }
70 });
71
72 me.callParent();
73 }
74
75}, function() {
76
77 Ext.define('pve-aplinfo', {
78 extend: 'Ext.data.Model',
177de3de
DC
79 fields: [
80 'template', 'type', 'package', 'version', 'headline', 'infopage',
4a580e60
DM
81 'description', 'os', 'section'
82 ],
83 idProperty: 'template'
84 });
85
86});
87
88Ext.define('PVE.storage.TemplateDownload', {
89 extend: 'Ext.window.Window',
3f90858a 90 alias: 'widget.pveTemplateDownload',
4a580e60
DM
91
92 modal: true,
3b422683
DC
93 title: gettext('Templates'),
94 layout: 'fit',
95 width: 600,
96 height: 400,
4a580e60
DM
97 initComponent : function() {
98 /*jslint confusion: true */
99 var me = this;
100
101 var grid = Ext.create('PVE.grid.TemplateSelector', {
102 border: false,
3b422683 103 scrollable: true,
4a580e60
DM
104 nodename: me.nodename
105 });
106
107 var sm = grid.getSelectionModel();
108
5720fafa 109 var submitBtn = Ext.create('Proxmox.button.Button', {
4a580e60
DM
110 text: gettext('Download'),
111 disabled: true,
112 selModel: sm,
113 handler: function(button, event, rec) {
e7ade592 114 Proxmox.Utils.API2Request({
4a580e60 115 url: '/nodes/' + me.nodename + '/aplinfo',
177de3de
DC
116 params: {
117 storage: me.storage,
4a580e60
DM
118 template: rec.data.template
119 },
120 method: 'POST',
121 failure: function (response, opts) {
122 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
123 },
124 success: function(response, options) {
125 var upid = response.result.data;
177de3de 126
8cbc11a7 127 Ext.create('Proxmox.window.TaskViewer', {
7e06d55d
EK
128 upid: upid,
129 listeners: {
130 destroy: me.reloadGrid
131 }
132 }).show();
133
4a580e60
DM
134 me.close();
135 }
136 });
137 }
138 });
139
3b422683 140 Ext.apply(me, {
4a580e60
DM
141 items: grid,
142 buttons: [ submitBtn ]
143 });
144
145 me.callParent();
146 }
147});
148
149Ext.define('PVE.storage.Upload', {
150 extend: 'Ext.window.Window',
3f90858a 151 alias: 'widget.pveStorageUpload',
4a580e60
DM
152
153 resizable: false,
154
155 modal: true,
156
157 initComponent : function() {
158 /*jslint confusion: true */
159 var me = this;
160
161 var xhr;
162
163 if (!me.nodename) {
164 throw "no node name specified";
165 }
166
177de3de 167 if (!me.storage) {
4a580e60
DM
168 throw "no storage ID specified";
169 }
170
171 var baseurl = "/nodes/" + me.nodename + "/storage/" + me.storage + "/upload";
172
173 var pbar = Ext.create('Ext.ProgressBar', {
174 text: 'Ready',
175 hidden: true
176 });
177
178 me.formPanel = Ext.create('Ext.form.Panel', {
179 method: 'POST',
180 waitMsgTarget: true,
181 bodyPadding: 10,
182 border: false,
183 width: 300,
184 fieldDefaults: {
185 labelWidth: 100,
186 anchor: '100%'
187 },
188 items: [
189 {
190 xtype: 'pveContentTypeSelector',
6c1a2b86 191 cts: me.contents,
4a580e60
DM
192 fieldLabel: gettext('Content'),
193 name: 'content',
6c1a2b86
DC
194 value: me.contents[0] || '',
195 allowBlank: false
4a580e60
DM
196 },
197 {
198 xtype: 'filefield',
199 name: 'filename',
200 buttonText: gettext('Select File...'),
22f2f9d6 201 allowBlank: false
4a580e60
DM
202 },
203 pbar
204 ]
205 });
206
207 var form = me.formPanel.getForm();
208
209 var doStandardSubmit = function() {
210 form.submit({
211 url: "/api2/htmljs" + baseurl,
212 waitMsg: gettext('Uploading file...'),
213 success: function(f, action) {
214 me.close();
215 },
216 failure: function(f, action) {
217 var msg = PVE.Utils.extractFormActionError(action);
218 Ext.Msg.alert(gettext('Error'), msg);
219 }
220 });
221 };
222
223 var updateProgress = function(per, bytes) {
224 var text = (per * 100).toFixed(2) + '%';
225 if (bytes) {
e7ade592 226 text += " (" + Proxmox.Utils.format_size(bytes) + ')';
4a580e60
DM
227 }
228 pbar.updateProgress(per, text);
229 };
177de3de 230
4a580e60
DM
231 var abortBtn = Ext.create('Ext.Button', {
232 text: gettext('Abort'),
233 disabled: true,
234 handler: function() {
235 me.close();
236 }
237 });
238
239 var submitBtn = Ext.create('Ext.Button', {
240 text: gettext('Upload'),
241 disabled: true,
242 handler: function(button) {
243 var fd;
244 try {
245 fd = new FormData();
246 } catch (err) {
247 doStandardSubmit();
248 return;
249 }
250
251 button.setDisabled(true);
252 abortBtn.setDisabled(false);
253
254 var field = form.findField('content');
255 fd.append("content", field.getValue());
256 field.setDisabled(true);
257
258 field = form.findField('filename');
259 var file = field.fileInputEl.dom;
260 fd.append("filename", file.files[0]);
261 field.setDisabled(true);
262
263 pbar.setVisible(true);
264 updateProgress(0);
265
266 xhr = new XMLHttpRequest();
267
177de3de 268 xhr.addEventListener("load", function(e) {
4a580e60
DM
269 if (xhr.status == 200) {
270 me.close();
177de3de 271 } else {
4a580e60
DM
272 var msg = gettext('Error') + " " + xhr.status.toString() + ": " + Ext.htmlEncode(xhr.statusText);
273 var result = Ext.decode(xhr.responseText);
274 result.message = msg;
e7ade592 275 var htmlStatus = Proxmox.Utils.extractRequestError(result, true);
4a580e60
DM
276 Ext.Msg.alert(gettext('Error'), htmlStatus, function(btn) {
277 me.close();
278 });
279
177de3de 280 }
4a580e60
DM
281 }, false);
282
283 xhr.addEventListener("error", function(e) {
284 var msg = "Error " + e.target.status.toString() + " occurred while receiving the document.";
285 Ext.Msg.alert(gettext('Error'), msg, function(btn) {
286 me.close();
287 });
288 });
177de3de 289
4a580e60 290 xhr.upload.addEventListener("progress", function(evt) {
177de3de
DC
291 if (evt.lengthComputable) {
292 var percentComplete = evt.loaded / evt.total;
4a580e60 293 updateProgress(percentComplete, evt.loaded);
177de3de 294 }
4a580e60
DM
295 }, false);
296
297 xhr.open("POST", "/api2/json" + baseurl, true);
177de3de 298 xhr.send(fd);
4a580e60
DM
299 }
300 });
301
302 form.on('validitychange', function(f, valid) {
303 submitBtn.setDisabled(!valid);
304 });
305
3b422683 306 Ext.apply(me, {
4a580e60
DM
307 title: gettext('Upload'),
308 items: me.formPanel,
309 buttons: [ abortBtn, submitBtn ],
310 listeners: {
311 close: function() {
312 if (xhr) {
313 xhr.abort();
314 }
315 }
316 }
317 });
318
319 me.callParent();
320 }
321});
322
323Ext.define('PVE.storage.ContentView', {
324 extend: 'Ext.grid.GridPanel',
325
3f90858a 326 alias: 'widget.pveStorageContentView',
4a580e60 327
1b14c875
DC
328 stateful: true,
329 stateId: 'grid-storage-content',
c90539de
DC
330 viewConfig: {
331 trackOver: false,
22f2f9d6 332 loadMask: false
c90539de 333 },
93cdb626
DC
334 features: [
335 {
336 ftype: 'grouping',
337 groupHeaderTpl: '{name} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
338 }
339 ],
4a580e60
DM
340 initComponent : function() {
341 var me = this;
342
343 var nodename = me.pveSelNode.data.node;
344 if (!nodename) {
345 throw "no node name specified";
346 }
347
348 var storage = me.pveSelNode.data.storage;
177de3de 349 if (!storage) {
4a580e60
DM
350 throw "no storage ID specified";
351 }
352
353 var baseurl = "/nodes/" + nodename + "/storage/" + storage + "/content";
3b422683 354 var store = Ext.create('Ext.data.Store',{
4a580e60
DM
355 model: 'pve-storage-content',
356 groupField: 'content',
357 proxy: {
358 type: 'pve',
359 url: '/api2/json' + baseurl
360 },
177de3de
DC
361 sorters: {
362 property: 'volid',
363 order: 'DESC'
4a580e60
DM
364 }
365 });
366
367 var sm = Ext.create('Ext.selection.RowModel', {});
368
4a580e60
DM
369 var reload = function() {
370 store.load();
6c1a2b86 371 me.statusStore.load();
4a580e60
DM
372 };
373
e7ade592 374 Proxmox.Utils.monStoreErrors(me, store);
4a580e60 375
5720fafa 376 var templateButton = Ext.create('Proxmox.button.Button',{
6c1a2b86
DC
377 itemId: 'tmpl-btn',
378 text: gettext('Templates'),
379 handler: function() {
380 var win = Ext.create('PVE.storage.TemplateDownload', {
381 nodename: nodename,
8b97744c
EK
382 storage: storage,
383 reloadGrid: reload
6c1a2b86
DC
384 });
385 win.show();
6c1a2b86
DC
386 }
387 });
388
5720fafa 389 var uploadButton = Ext.create('Proxmox.button.Button', {
6c1a2b86
DC
390 contents : ['iso','vztmpl'],
391 text: gettext('Upload'),
392 handler: function() {
393 var me = this;
394 var win = Ext.create('PVE.storage.Upload', {
395 nodename: nodename,
396 storage: storage,
22f2f9d6 397 contents: me.contents
6c1a2b86
DC
398 });
399 win.show();
400 win.on('destroy', reload);
401 }
402 });
403
404 me.statusStore = Ext.create('PVE.data.ObjectStore', {
22f2f9d6 405 url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
6c1a2b86
DC
406 });
407
4a580e60
DM
408 Ext.apply(me, {
409 store: store,
410 selModel: sm,
4a580e60
DM
411 tbar: [
412 {
5720fafa 413 xtype: 'proxmoxButton',
4a580e60
DM
414 text: gettext('Restore'),
415 selModel: sm,
416 disabled: true,
417 enableFn: function(rec) {
418 return rec && rec.data.content === 'backup';
419 },
420 handler: function(b, e, rec) {
421 var vmtype;
422 if (rec.data.volid.match(/vzdump-qemu-/)) {
423 vmtype = 'qemu';
424 } else if (rec.data.volid.match(/vzdump-openvz-/) || rec.data.volid.match(/vzdump-lxc-/)) {
425 vmtype = 'lxc';
426 } else {
427 return;
428 }
429
430 var win = Ext.create('PVE.window.Restore', {
431 nodename: nodename,
432 volid: rec.data.volid,
433 volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
434 vmtype: vmtype
435 });
436 win.show();
437 win.on('destroy', reload);
438 }
439 },
440 {
3b1ca3ff 441 xtype: 'proxmoxStdRemoveButton',
4a580e60 442 selModel: sm,
4a580e60
DM
443 enableFn: function(rec) {
444 return rec && rec.data.content !== 'images';
445 },
3b1ca3ff
DC
446 callback: function() {
447 reload();
448 },
449 baseurl: baseurl + '/'
4a580e60 450 },
6c1a2b86
DC
451 templateButton,
452 uploadButton,
772042ea 453 {
5720fafa 454 xtype: 'proxmoxButton',
772042ea
DC
455 text: gettext('Show Configuration'),
456 disabled: true,
457 selModel: sm,
458 enableFn: function(rec) {
459 return rec && rec.data.content === 'backup';
460 },
461 handler: function(b,e,rec) {
462 var win = Ext.create('PVE.window.BackupConfig', {
463 volume: rec.data.volid,
464 pveSelNode: me.pveSelNode
465 });
466
467 win.show();
468 }
469 },
4a580e60
DM
470 '->',
471 gettext('Search') + ':', ' ',
472 {
473 xtype: 'textfield',
474 width: 200,
475 enableKeyEvents: true,
476 listeners: {
477 buffer: 500,
478 keyup: function(field) {
479 store.clearFilter(true);
480 store.filter([
481 {
482 property: 'text',
483 value: field.getValue(),
484 anyMatch: true,
485 caseSensitive: false
486 }
487 ]);
488 }
489 }
490 }
491 ],
492 columns: [
493 {
494 header: gettext('Name'),
495 flex: 1,
496 sortable: true,
497 renderer: PVE.Utils.render_storage_content,
498 dataIndex: 'text'
499 },
500 {
501 header: gettext('Format'),
502 width: 100,
503 dataIndex: 'format'
504 },
93cdb626
DC
505 {
506 header: gettext('Type'),
507 width: 100,
508 dataIndex: 'content',
509 renderer: PVE.Utils.format_content_types
510 },
4a580e60
DM
511 {
512 header: gettext('Size'),
513 width: 100,
e7ade592 514 renderer: Proxmox.Utils.format_size,
4a580e60
DM
515 dataIndex: 'size'
516 }
517 ],
518 listeners: {
3b422683 519 activate: reload
4a580e60
DM
520 }
521 });
522
523 me.callParent();
6c1a2b86 524
3d9bc0a2 525 // disable the buttons/restrict the upload window
6c1a2b86 526 // if templates or uploads are not allowed
540fdc8b 527 me.mon(me.statusStore, 'load', function(s,records,succes) {
6c1a2b86
DC
528 var availcontent = [];
529 Ext.Array.each(records, function(item){
530 if (item.id === 'content') {
531 availcontent = item.data.value.split(',');
532 }
533 });
534 var templ = false;
535 var upload = false;
536 var cts = [];
537
538 Ext.Array.each(availcontent, function(content) {
539 if (content === 'vztmpl') {
540 templ = true;
541 cts.push('vztmpl');
542 } else if (content === 'iso') {
543 upload = true;
544 cts.push('iso');
545 }
546 });
547
548 if (templ !== upload) {
549 uploadButton.contents = cts;
550 }
551
552 templateButton.setDisabled(!templ);
553 uploadButton.setDisabled(!upload && !templ);
554 });
4a580e60
DM
555 }
556}, function() {
557
558 Ext.define('pve-storage-content', {
559 extend: 'Ext.data.Model',
177de3de
DC
560 fields: [
561 'volid', 'content', 'format', 'size', 'used', 'vmid',
4a580e60 562 'channel', 'id', 'lun',
177de3de
DC
563 {
564 name: 'text',
4a580e60 565 convert: function(value, record) {
86cc7049
DC
566 // check for volid, because if you click on a grouping header,
567 // it calls convert (but with an empty volid)
568 if (value || record.data.volid === null) {
4a580e60
DM
569 return value;
570 }
571 return PVE.Utils.render_storage_content(value, {}, record);
572 }
573 }
574 ],
575 idProperty: 'volid'
576 });
577
578});