]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/window/UploadToStorage.js
ui: guest import: auto activate virtio preparation for win + ovmf
[pve-manager.git] / www / manager6 / window / UploadToStorage.js
1 Ext.define('PVE.window.UploadToStorage', {
2 extend: 'Ext.window.Window',
3 alias: 'widget.pveStorageUpload',
4 mixins: ['Proxmox.Mixin.CBind'],
5
6 resizable: false,
7 modal: true,
8
9 title: gettext('Upload'),
10
11 acceptedExtensions: {
12 iso: ['.img', '.iso'],
13 vztmpl: ['.tar.gz', '.tar.xz', '.tar.zst'],
14 },
15
16 cbindData: function(initialConfig) {
17 const me = this;
18 const ext = me.acceptedExtensions[me.content] || [];
19
20 me.url = `/nodes/${me.nodename}/storage/${me.storage}/upload`;
21
22 return {
23 extensions: ext.join(', '),
24 filenameRegex: RegExp('^.*(?:' + ext.join('|').replaceAll('.', '\\.') + ')$', 'i'),
25 };
26 },
27
28 viewModel: {
29 data: {
30 size: '-',
31 mimetype: '-',
32 filename: '',
33 },
34 },
35
36 controller: {
37 submit: function(button) {
38 const view = this.getView();
39 const form = this.lookup('formPanel').getForm();
40 const abortBtn = this.lookup('abortBtn');
41 const pbar = this.lookup('progressBar');
42
43 const updateProgress = function(per, bytes) {
44 let text = (per * 100).toFixed(2) + '%';
45 if (bytes) {
46 text += " (" + Proxmox.Utils.format_size(bytes) + ')';
47 }
48 pbar.updateProgress(per, text);
49 };
50
51 const fd = new FormData();
52
53 button.setDisabled(true);
54 abortBtn.setDisabled(false);
55
56 fd.append("content", view.content);
57
58 const fileField = form.findField('file');
59 const file = fileField.fileInputEl.dom.files[0];
60 fileField.setDisabled(true);
61
62 const filenameField = form.findField('filename');
63 const filename = filenameField.getValue();
64 filenameField.setDisabled(true);
65
66 const algorithmField = form.findField('checksum-algorithm');
67 algorithmField.setDisabled(true);
68 if (algorithmField.getValue() !== '__default__') {
69 fd.append("checksum-algorithm", algorithmField.getValue());
70
71 const checksumField = form.findField('checksum');
72 fd.append("checksum", checksumField.getValue()?.trim());
73 checksumField.setDisabled(true);
74 }
75
76 fd.append("filename", file, filename);
77
78 pbar.setVisible(true);
79 updateProgress(0);
80
81 const xhr = new XMLHttpRequest();
82 view.xhr = xhr;
83
84 xhr.addEventListener("load", function(e) {
85 if (xhr.status === 200) {
86 view.hide();
87
88 const result = JSON.parse(xhr.response);
89 const upid = result.data;
90 Ext.create('Proxmox.window.TaskViewer', {
91 autoShow: true,
92 upid: upid,
93 taskDone: view.taskDone,
94 listeners: {
95 destroy: function() {
96 view.close();
97 },
98 },
99 });
100
101 return;
102 }
103 const err = Ext.htmlEncode(xhr.statusText);
104 let msg = `${gettext('Error')} ${xhr.status.toString()}: ${err}`;
105 if (xhr.responseText !== "") {
106 const result = Ext.decode(xhr.responseText);
107 result.message = msg;
108 msg = Proxmox.Utils.extractRequestError(result, true);
109 }
110 Ext.Msg.alert(gettext('Error'), msg, btn => view.close());
111 }, false);
112
113 xhr.addEventListener("error", function(e) {
114 const err = e.target.status.toString();
115 const msg = `Error '${err}' occurred while receiving the document.`;
116 Ext.Msg.alert(gettext('Error'), msg, btn => view.close());
117 });
118
119 xhr.upload.addEventListener("progress", function(evt) {
120 if (evt.lengthComputable) {
121 const percentComplete = evt.loaded / evt.total;
122 updateProgress(percentComplete, evt.loaded);
123 }
124 }, false);
125
126 xhr.open("POST", `/api2/json${view.url}`, true);
127 xhr.send(fd);
128 },
129
130 validitychange: function(f, valid) {
131 const submitBtn = this.lookup('submitBtn');
132 submitBtn.setDisabled(!valid);
133 },
134
135 fileChange: function(input) {
136 const vm = this.getViewModel();
137 const name = input.value.replace(/^.*(\/|\\)/, '');
138 const fileInput = input.fileInputEl.dom;
139 vm.set('filename', name);
140 vm.set('size', (fileInput.files[0] && Proxmox.Utils.format_size(fileInput.files[0].size)) || '-');
141 vm.set('mimetype', (fileInput.files[0] && fileInput.files[0].type) || '-');
142 },
143
144 hashChange: function(field, value) {
145 const checksum = this.lookup('downloadUrlChecksum');
146 if (value === '__default__') {
147 checksum.setDisabled(true);
148 checksum.setValue("");
149 } else {
150 checksum.setDisabled(false);
151 }
152 },
153 },
154
155 items: [
156 {
157 xtype: 'form',
158 reference: 'formPanel',
159 method: 'POST',
160 waitMsgTarget: true,
161 bodyPadding: 10,
162 border: false,
163 width: 400,
164 fieldDefaults: {
165 labelWidth: 100,
166 anchor: '100%',
167 },
168 items: [
169 {
170 xtype: 'filefield',
171 name: 'file',
172 buttonText: gettext('Select File'),
173 allowBlank: false,
174 fieldLabel: gettext('File'),
175 cbind: {
176 accept: '{extensions}',
177 },
178 listeners: {
179 change: 'fileChange',
180 },
181 },
182 {
183 xtype: 'textfield',
184 name: 'filename',
185 allowBlank: false,
186 fieldLabel: gettext('File name'),
187 bind: {
188 value: '{filename}',
189 },
190 cbind: {
191 regex: '{filenameRegex}',
192 },
193 regexText: gettext('Wrong file extension'),
194 },
195 {
196 xtype: 'displayfield',
197 name: 'size',
198 fieldLabel: gettext('File size'),
199 bind: {
200 value: '{size}',
201 },
202 },
203 {
204 xtype: 'displayfield',
205 name: 'mimetype',
206 fieldLabel: gettext('MIME type'),
207 bind: {
208 value: '{mimetype}',
209 },
210 },
211 {
212 xtype: 'pveHashAlgorithmSelector',
213 name: 'checksum-algorithm',
214 fieldLabel: gettext('Hash algorithm'),
215 allowBlank: true,
216 hasNoneOption: true,
217 value: '__default__',
218 listeners: {
219 change: 'hashChange',
220 },
221 },
222 {
223 xtype: 'textfield',
224 name: 'checksum',
225 fieldLabel: gettext('Checksum'),
226 allowBlank: false,
227 disabled: true,
228 emptyText: gettext('none'),
229 reference: 'downloadUrlChecksum',
230 },
231 {
232 xtype: 'progressbar',
233 text: 'Ready',
234 hidden: true,
235 reference: 'progressBar',
236 },
237 {
238 xtype: 'hiddenfield',
239 name: 'content',
240 cbind: {
241 value: '{content}',
242 },
243 },
244 ],
245 listeners: {
246 validitychange: 'validitychange',
247 },
248 },
249 ],
250
251 buttons: [
252 {
253 xtype: 'button',
254 text: gettext('Abort'),
255 reference: 'abortBtn',
256 disabled: true,
257 handler: function() {
258 const me = this;
259 me.up('pveStorageUpload').close();
260 },
261 },
262 {
263 text: gettext('Upload'),
264 reference: 'submitBtn',
265 disabled: true,
266 handler: 'submit',
267 },
268 ],
269
270 listeners: {
271 close: function() {
272 const me = this;
273 if (me.xhr) {
274 me.xhr.abort();
275 delete me.xhr;
276 }
277 },
278 },
279
280 initComponent: function() {
281 const me = this;
282
283 if (!me.nodename) {
284 throw "no node name specified";
285 }
286 if (!me.storage) {
287 throw "no storage ID specified";
288 }
289 if (!me.acceptedExtensions[me.content]) {
290 throw "content type not supported";
291 }
292
293 me.callParent();
294 },
295 });