]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/storage/ContentView.js
1 Ext
.define('PVE.grid.TemplateSelector', {
2 extend
: 'Ext.grid.GridPanel',
4 alias
: 'widget.pveTemplateSelector',
7 stateId
: 'grid-template-selector',
11 initComponent : function() {
15 throw "no node name specified";
18 var baseurl
= "/nodes/" + me
.nodename
+ "/aplinfo";
19 var store
= new Ext
.data
.Store({
21 groupField
: 'section',
24 url
: '/api2/json' + baseurl
28 var sm
= Ext
.create('Ext.selection.RowModel', {});
30 var groupingFeature
= Ext
.create('Ext.grid.feature.Grouping',{
31 groupHeaderTpl
: '{[ "Section: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
34 var reload = function() {
38 Proxmox
.Utils
.monStoreErrors(me
, store
);
49 enableKeyEvents
: true,
52 keyup: function(field
) {
53 var value
= field
.getValue().toLowerCase();
54 store
.clearFilter(true);
55 store
.filterBy(function(rec
) {
56 return (rec
.data
['package'].toLowerCase().indexOf(value
) !== -1)
57 || (rec
.data
.headline
.toLowerCase().indexOf(value
) !== -1);
63 features
: [ groupingFeature
],
66 header
: gettext('Type'),
71 header
: gettext('Package'),
76 header
: gettext('Version'),
81 header
: gettext('Description'),
83 renderer
: Ext
.String
.htmlEncode
,
97 Ext
.define('pve-aplinfo', {
98 extend
: 'Ext.data.Model',
100 'template', 'type', 'package', 'version', 'headline', 'infopage',
101 'description', 'os', 'section'
103 idProperty
: 'template'
108 Ext
.define('PVE.storage.TemplateDownload', {
109 extend
: 'Ext.window.Window',
110 alias
: 'widget.pveTemplateDownload',
113 title
: gettext('Templates'),
117 initComponent : function() {
120 var grid
= Ext
.create('PVE.grid.TemplateSelector', {
123 nodename
: me
.nodename
126 var sm
= grid
.getSelectionModel();
128 var submitBtn
= Ext
.create('Proxmox.button.Button', {
129 text
: gettext('Download'),
132 handler: function(button
, event
, rec
) {
133 Proxmox
.Utils
.API2Request({
134 url
: '/nodes/' + me
.nodename
+ '/aplinfo',
137 template
: rec
.data
.template
140 failure: function (response
, opts
) {
141 Ext
.Msg
.alert(gettext('Error'), response
.htmlStatus
);
143 success: function(response
, options
) {
144 var upid
= response
.result
.data
;
146 Ext
.create('Proxmox.window.TaskViewer', {
149 destroy
: me
.reloadGrid
161 buttons
: [ submitBtn
]
168 Ext
.define('PVE.storage.Upload', {
169 extend
: 'Ext.window.Window',
170 alias
: 'widget.pveStorageUpload',
176 initComponent : function() {
182 throw "no node name specified";
186 throw "no storage ID specified";
189 var baseurl
= "/nodes/" + me
.nodename
+ "/storage/" + me
.storage
+ "/upload";
191 var pbar
= Ext
.create('Ext.ProgressBar', {
196 me
.formPanel
= Ext
.create('Ext.form.Panel', {
208 xtype
: 'pveContentTypeSelector',
210 fieldLabel
: gettext('Content'),
212 value
: me
.contents
[0] || '',
218 buttonText
: gettext('Select File...'),
221 afterrender: function(cmp
) {
222 cmp
.fileInputEl
.set({
232 var form
= me
.formPanel
.getForm();
234 var doStandardSubmit = function() {
236 url
: "/api2/htmljs" + baseurl
,
237 waitMsg
: gettext('Uploading file...'),
238 success: function(f
, action
) {
241 failure: function(f
, action
) {
242 var msg
= PVE
.Utils
.extractFormActionError(action
);
243 Ext
.Msg
.alert(gettext('Error'), msg
);
248 var updateProgress = function(per
, bytes
) {
249 var text
= (per
* 100).toFixed(2) + '%';
251 text
+= " (" + Proxmox
.Utils
.format_size(bytes
) + ')';
253 pbar
.updateProgress(per
, text
);
256 var abortBtn
= Ext
.create('Ext.Button', {
257 text
: gettext('Abort'),
259 handler: function() {
264 var submitBtn
= Ext
.create('Ext.Button', {
265 text
: gettext('Upload'),
267 handler: function(button
) {
276 button
.setDisabled(true);
277 abortBtn
.setDisabled(false);
279 var field
= form
.findField('content');
280 fd
.append("content", field
.getValue());
281 field
.setDisabled(true);
283 field
= form
.findField('filename');
284 var file
= field
.fileInputEl
.dom
;
285 fd
.append("filename", file
.files
[0]);
286 field
.setDisabled(true);
288 pbar
.setVisible(true);
291 xhr
= new XMLHttpRequest();
293 xhr
.addEventListener("load", function(e
) {
294 if (xhr
.status
== 200) {
297 var msg
= gettext('Error') + " " + xhr
.status
.toString() + ": " + Ext
.htmlEncode(xhr
.statusText
);
298 if (xhr
.responseText
!== "") {
299 var result
= Ext
.decode(xhr
.responseText
);
300 result
.message
= msg
;
301 msg
= Proxmox
.Utils
.extractRequestError(result
, true);
303 Ext
.Msg
.alert(gettext('Error'), msg
, function(btn
) {
309 xhr
.addEventListener("error", function(e
) {
310 var msg
= "Error " + e
.target
.status
.toString() + " occurred while receiving the document.";
311 Ext
.Msg
.alert(gettext('Error'), msg
, function(btn
) {
316 xhr
.upload
.addEventListener("progress", function(evt
) {
317 if (evt
.lengthComputable
) {
318 var percentComplete
= evt
.loaded
/ evt
.total
;
319 updateProgress(percentComplete
, evt
.loaded
);
323 xhr
.open("POST", "/api2/json" + baseurl
, true);
328 form
.on('validitychange', function(f
, valid
) {
329 submitBtn
.setDisabled(!valid
);
333 title
: gettext('Upload'),
335 buttons
: [ abortBtn
, submitBtn
],
349 Ext
.define('PVE.storage.ContentView', {
350 extend
: 'Ext.grid.GridPanel',
352 alias
: 'widget.pveStorageContentView',
355 stateId
: 'grid-storage-content',
363 groupHeaderTpl
: '{name} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
366 initComponent : function() {
369 var nodename
= me
.pveSelNode
.data
.node
;
371 throw "no node name specified";
374 var storage
= me
.pveSelNode
.data
.storage
;
376 throw "no storage ID specified";
379 var baseurl
= "/nodes/" + nodename
+ "/storage/" + storage
+ "/content";
380 var store
= Ext
.create('Ext.data.Store',{
381 model
: 'pve-storage-content',
382 groupField
: 'content',
385 url
: '/api2/json' + baseurl
393 var sm
= Ext
.create('Ext.selection.RowModel', {});
395 var reload = function() {
397 me
.statusStore
.load();
400 Proxmox
.Utils
.monStoreErrors(me
, store
);
402 var templateButton
= Ext
.create('Proxmox.button.Button',{
404 text
: gettext('Templates'),
405 handler: function() {
406 var win
= Ext
.create('PVE.storage.TemplateDownload', {
415 var uploadButton
= Ext
.create('Proxmox.button.Button', {
416 contents
: ['iso','vztmpl'],
417 text
: gettext('Upload'),
418 handler: function() {
420 var win
= Ext
.create('PVE.storage.Upload', {
423 contents
: me
.contents
426 win
.on('destroy', reload
);
430 var imageRemoveButton
;
431 var removeButton
= Ext
.create('Proxmox.button.StdRemoveButton',{
434 enableFn: function(rec
) {
435 if (rec
&& rec
.data
.content
!== 'images') {
436 imageRemoveButton
.setVisible(false);
437 removeButton
.setVisible(true);
442 callback: function() {
445 baseurl
: baseurl
+ '/'
448 imageRemoveButton
= Ext
.create('Proxmox.button.Button',{
451 text
: gettext('Remove'),
452 enableFn: function(rec
) {
453 if (rec
&& rec
.data
.content
=== 'images') {
454 removeButton
.setVisible(false);
455 imageRemoveButton
.setVisible(true);
460 handler: function(btn
, event
, rec
) {
463 var url
= baseurl
+ '/' + rec
.data
.volid
;
464 var vmid
= rec
.data
.vmid
;
466 var store
= PVE
.data
.ResourceStore
;
468 if (vmid
&& store
.findVMID(vmid
)) {
469 var guest_node
= store
.guestNode(vmid
);
470 var storage_path
= 'storage/' + nodename
+ '/' + storage
;
472 // allow to delete local backed images if a VMID exists on another node.
473 if (store
.storageIsShared(storage_path
) || guest_node
== nodename
) {
474 var msg
= Ext
.String
.format(
475 gettext("Cannot remove image, a guest with VMID '{0}' exists!"), vmid
);
476 msg
+= '<br />' + gettext("You can delete the image from the guest's hardware pane");
479 title
: gettext('Cannot remove disk image.'),
486 var win
= Ext
.create('PVE.window.SafeDestroy', {
487 title
: Ext
.String
.format(gettext("Destroy '{0}'"), rec
.data
.volid
),
490 item
: { type
: 'Image', id
: vmid
}
492 win
.on('destroy', function() {
493 me
.statusStore
= Ext
.create('Proxmox.data.ObjectStore', {
494 url
: '/api2/json/nodes/' + nodename
+ '/storage/' + storage
+ '/status'
502 me
.statusStore
= Ext
.create('Proxmox.data.ObjectStore', {
503 url
: '/api2/json/nodes/' + nodename
+ '/storage/' + storage
+ '/status'
511 xtype
: 'proxmoxButton',
512 text
: gettext('Restore'),
515 enableFn: function(rec
) {
516 return rec
&& rec
.data
.content
=== 'backup';
518 handler: function(b
, e
, rec
) {
520 if (PVE
.Utils
.volume_is_qemu_backup(rec
.data
.volid
, rec
.data
.format
)) {
522 } else if (PVE
.Utils
.volume_is_lxc_backup(rec
.data
.volid
, rec
.data
.format
)) {
528 var win
= Ext
.create('PVE.window.Restore', {
530 volid
: rec
.data
.volid
,
531 volidText
: PVE
.Utils
.render_storage_content(rec
.data
.volid
, {}, rec
),
535 win
.on('destroy', reload
);
543 xtype
: 'proxmoxButton',
544 text
: gettext('Show Configuration'),
547 enableFn: function(rec
) {
548 return rec
&& rec
.data
.content
=== 'backup';
550 handler: function(b
,e
,rec
) {
551 var win
= Ext
.create('PVE.window.BackupConfig', {
552 volume
: rec
.data
.volid
,
553 pveSelNode
: me
.pveSelNode
560 gettext('Search') + ':', ' ',
564 enableKeyEvents
: true,
567 keyup: function(field
) {
568 store
.clearFilter(true);
572 value
: field
.getValue(),
583 header
: gettext('Name'),
586 renderer
: PVE
.Utils
.render_storage_content
,
590 header
: gettext('Date'),
595 header
: gettext('Format'),
600 header
: gettext('Type'),
602 dataIndex
: 'content',
603 renderer
: PVE
.Utils
.format_content_types
606 header
: gettext('Size'),
608 renderer
: Proxmox
.Utils
.format_size
,
619 // disable the buttons/restrict the upload window
620 // if templates or uploads are not allowed
621 me
.mon(me
.statusStore
, 'load', function(s
, records
, success
) {
622 var availcontent
= [];
623 Ext
.Array
.each(records
, function(item
){
624 if (item
.id
=== 'content') {
625 availcontent
= item
.data
.value
.split(',');
632 Ext
.Array
.each(availcontent
, function(content
) {
633 if (content
=== 'vztmpl') {
636 } else if (content
=== 'iso') {
642 if (templ
!== upload
) {
643 uploadButton
.contents
= cts
;
646 templateButton
.setDisabled(!templ
);
647 uploadButton
.setDisabled(!upload
&& !templ
);
652 Ext
.define('pve-storage-content', {
653 extend
: 'Ext.data.Model',
655 'volid', 'content', 'format', 'size', 'used', 'vmid',
656 'channel', 'id', 'lun',
659 convert: function(value
, record
) {
660 // check for volid, because if you click on a grouping header,
661 // it calls convert (but with an empty volid)
662 if (value
|| record
.data
.volid
=== null) {
665 return PVE
.Utils
.render_storage_content(value
, {}, record
);
670 convert: function(value
, record
) {
671 // check for volid, because if you click on a grouping header,
672 // it calls convert (but with an empty volid)
673 if (value
|| record
.data
.volid
=== null) {
676 let t
= record
.data
.content
;
677 if (t
=== "backup") {
678 let v
= record
.data
.volid
;
679 let match
= v
.match(/(\d{4}_\d{2}_\d{2})-(\d{2}_\d{2}_\d{2})/);
681 let date
= match
[1].replace(/_
/g
, '-');
682 let time
= match
[2].replace(/_
/g
, ':');
683 return date
+ " " + time
;
686 if (record
.data
.ctime
) {
687 let ctime
= new Date(record
.data
.ctime
* 1000);
688 return Ext
.Date
.format(ctime
,'Y-m-d H:i:s');