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