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