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