pve-manager/www/manager6/window/UploadToStorage.js
Matthias Heiserer 0c3baeef0b ui: LXC template upload: allow zstd compressed (.tar.zst) images
Signed-off-by: Matthias Heiserer <m.heiserer@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2022-11-16 20:13:48 +01:00

296 lines
6.7 KiB
JavaScript

Ext.define('PVE.window.UploadToStorage', {
extend: 'Ext.window.Window',
alias: 'widget.pveStorageUpload',
mixins: ['Proxmox.Mixin.CBind'],
resizable: false,
modal: true,
title: gettext('Upload'),
acceptedExtensions: {
iso: ['.img', '.iso'],
vztmpl: ['.tar.gz', '.tar.xz', '.tar.zst'],
},
cbindData: function(initialConfig) {
const me = this;
const ext = me.acceptedExtensions[me.content] || [];
me.url = `/nodes/${me.nodename}/storage/${me.storage}/upload`;
return {
extensions: ext.join(', '),
filenameRegex: RegExp('^.*(?:' + ext.join('|').replaceAll('.', '\\.') + ')$', 'i'),
};
},
viewModel: {
data: {
size: '-',
mimetype: '-',
filename: '',
},
},
controller: {
submit: function(button) {
const view = this.getView();
const form = this.lookup('formPanel').getForm();
const abortBtn = this.lookup('abortBtn');
const pbar = this.lookup('progressBar');
const updateProgress = function(per, bytes) {
let text = (per * 100).toFixed(2) + '%';
if (bytes) {
text += " (" + Proxmox.Utils.format_size(bytes) + ')';
}
pbar.updateProgress(per, text);
};
const fd = new FormData();
button.setDisabled(true);
abortBtn.setDisabled(false);
fd.append("content", view.content);
const fileField = form.findField('file');
const file = fileField.fileInputEl.dom.files[0];
fileField.setDisabled(true);
const filenameField = form.findField('filename');
const filename = filenameField.getValue();
filenameField.setDisabled(true);
const algorithmField = form.findField('checksum-algorithm');
algorithmField.setDisabled(true);
if (algorithmField.getValue() !== '__default__') {
fd.append("checksum-algorithm", algorithmField.getValue());
const checksumField = form.findField('checksum');
fd.append("checksum", checksumField.getValue()?.trim());
checksumField.setDisabled(true);
}
fd.append("filename", file, filename);
pbar.setVisible(true);
updateProgress(0);
const xhr = new XMLHttpRequest();
view.xhr = xhr;
xhr.addEventListener("load", function(e) {
if (xhr.status === 200) {
view.hide();
const result = JSON.parse(xhr.response);
const upid = result.data;
Ext.create('Proxmox.window.TaskViewer', {
autoShow: true,
upid: upid,
taskDone: view.taskDone,
listeners: {
destroy: function() {
view.close();
},
},
});
return;
}
const err = Ext.htmlEncode(xhr.statusText);
let msg = `${gettext('Error')} ${xhr.status.toString()}: ${err}`;
if (xhr.responseText !== "") {
const result = Ext.decode(xhr.responseText);
result.message = msg;
msg = Proxmox.Utils.extractRequestError(result, true);
}
Ext.Msg.alert(gettext('Error'), msg, btn => view.close());
}, false);
xhr.addEventListener("error", function(e) {
const err = e.target.status.toString();
const msg = `Error '${err}' occurred while receiving the document.`;
Ext.Msg.alert(gettext('Error'), msg, btn => view.close());
});
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
const percentComplete = evt.loaded / evt.total;
updateProgress(percentComplete, evt.loaded);
}
}, false);
xhr.open("POST", `/api2/json${view.url}`, true);
xhr.send(fd);
},
validitychange: function(f, valid) {
const submitBtn = this.lookup('submitBtn');
submitBtn.setDisabled(!valid);
},
fileChange: function(input) {
const vm = this.getViewModel();
const name = input.value.replace(/^.*(\/|\\)/, '');
const fileInput = input.fileInputEl.dom;
vm.set('filename', name);
vm.set('size', (fileInput.files[0] && Proxmox.Utils.format_size(fileInput.files[0].size)) || '-');
vm.set('mimetype', (fileInput.files[0] && fileInput.files[0].type) || '-');
},
hashChange: function(field, value) {
const checksum = this.lookup('downloadUrlChecksum');
if (value === '__default__') {
checksum.setDisabled(true);
checksum.setValue("");
} else {
checksum.setDisabled(false);
}
},
},
items: [
{
xtype: 'form',
reference: 'formPanel',
method: 'POST',
waitMsgTarget: true,
bodyPadding: 10,
border: false,
width: 400,
fieldDefaults: {
labelWidth: 100,
anchor: '100%',
},
items: [
{
xtype: 'filefield',
name: 'file',
buttonText: gettext('Select File'),
allowBlank: false,
fieldLabel: gettext('File'),
cbind: {
accept: '{extensions}',
},
listeners: {
change: 'fileChange',
},
},
{
xtype: 'textfield',
name: 'filename',
allowBlank: false,
fieldLabel: gettext('File name'),
bind: {
value: '{filename}',
},
cbind: {
regex: '{filenameRegex}',
},
regexText: gettext('Wrong file extension'),
},
{
xtype: 'displayfield',
name: 'size',
fieldLabel: gettext('File size'),
bind: {
value: '{size}',
},
},
{
xtype: 'displayfield',
name: 'mimetype',
fieldLabel: gettext('MIME type'),
bind: {
value: '{mimetype}',
},
},
{
xtype: 'pveHashAlgorithmSelector',
name: 'checksum-algorithm',
fieldLabel: gettext('Hash algorithm'),
allowBlank: true,
hasNoneOption: true,
value: '__default__',
listeners: {
change: 'hashChange',
},
},
{
xtype: 'textfield',
name: 'checksum',
fieldLabel: gettext('Checksum'),
allowBlank: false,
disabled: true,
emptyText: gettext('none'),
reference: 'downloadUrlChecksum',
},
{
xtype: 'progressbar',
text: 'Ready',
hidden: true,
reference: 'progressBar',
},
{
xtype: 'hiddenfield',
name: 'content',
cbind: {
value: '{content}',
},
},
],
listeners: {
validitychange: 'validitychange',
},
},
],
buttons: [
{
xtype: 'button',
text: gettext('Abort'),
reference: 'abortBtn',
disabled: true,
handler: function() {
const me = this;
me.up('pveStorageUpload').close();
},
},
{
text: gettext('Upload'),
reference: 'submitBtn',
disabled: true,
handler: 'submit',
},
],
listeners: {
close: function() {
const me = this;
if (me.xhr) {
me.xhr.abort();
delete me.xhr;
}
},
},
initComponent: function() {
const me = this;
if (!me.nodename) {
throw "no node name specified";
}
if (!me.storage) {
throw "no storage ID specified";
}
if (!me.acceptedExtensions[me.content]) {
throw "content type not supported";
}
me.callParent();
},
});