]>
Commit | Line | Data |
---|---|---|
4a580e60 DM |
1 | Ext.define('PVE.grid.TemplateSelector', { |
2 | extend: 'Ext.grid.GridPanel', | |
3 | ||
4 | alias: ['widget.pveTemplateSelector'], | |
5 | ||
6 | initComponent : function() { | |
7 | var me = this; | |
8 | ||
9 | if (!me.nodename) { | |
10 | throw "no node name specified"; | |
11 | } | |
12 | ||
13 | var baseurl = "/nodes/" + me.nodename + "/aplinfo"; | |
14 | var store = new Ext.data.Store({ | |
15 | model: 'pve-aplinfo', | |
16 | groupField: 'section', | |
17 | proxy: { | |
18 | type: 'pve', | |
19 | url: '/api2/json' + baseurl | |
20 | } | |
21 | }); | |
22 | ||
23 | var sm = Ext.create('Ext.selection.RowModel', {}); | |
24 | ||
25 | var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{ | |
26 | groupHeaderTpl: '{[ "Section: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})' | |
27 | }); | |
28 | ||
29 | var reload = function() { | |
30 | store.load(); | |
31 | }; | |
32 | ||
33 | PVE.Utils.monStoreErrors(me, store); | |
34 | ||
35 | Ext.apply(me, { | |
36 | store: store, | |
37 | selModel: sm, | |
38 | stateful: false, | |
39 | viewConfig: { | |
40 | trackOver: false | |
41 | }, | |
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, | |
62 | dataIndex: 'headline' | |
63 | } | |
64 | ], | |
65 | listeners: { | |
66 | afterRender: reload | |
67 | } | |
68 | }); | |
69 | ||
70 | me.callParent(); | |
71 | } | |
72 | ||
73 | }, function() { | |
74 | ||
75 | Ext.define('pve-aplinfo', { | |
76 | extend: 'Ext.data.Model', | |
77 | fields: [ | |
78 | 'template', 'type', 'package', 'version', 'headline', 'infopage', | |
79 | 'description', 'os', 'section' | |
80 | ], | |
81 | idProperty: 'template' | |
82 | }); | |
83 | ||
84 | }); | |
85 | ||
86 | Ext.define('PVE.storage.TemplateDownload', { | |
87 | extend: 'Ext.window.Window', | |
88 | alias: ['widget.pveTemplateDownload'], | |
89 | ||
90 | modal: true, | |
91 | ||
92 | initComponent : function() { | |
93 | /*jslint confusion: true */ | |
94 | var me = this; | |
95 | ||
96 | var grid = Ext.create('PVE.grid.TemplateSelector', { | |
97 | border: false, | |
98 | autoScroll: true, | |
99 | nodename: me.nodename | |
100 | }); | |
101 | ||
102 | var sm = grid.getSelectionModel(); | |
103 | ||
104 | var submitBtn = Ext.create('PVE.button.Button', { | |
105 | text: gettext('Download'), | |
106 | disabled: true, | |
107 | selModel: sm, | |
108 | handler: function(button, event, rec) { | |
109 | PVE.Utils.API2Request({ | |
110 | url: '/nodes/' + me.nodename + '/aplinfo', | |
111 | params: { | |
112 | storage: me.storage, | |
113 | template: rec.data.template | |
114 | }, | |
115 | method: 'POST', | |
116 | failure: function (response, opts) { | |
117 | Ext.Msg.alert(gettext('Error'), response.htmlStatus); | |
118 | }, | |
119 | success: function(response, options) { | |
120 | var upid = response.result.data; | |
121 | ||
122 | var win = Ext.create('PVE.window.TaskViewer', { | |
123 | upid: upid | |
124 | }); | |
125 | win.show(); | |
126 | me.close(); | |
127 | } | |
128 | }); | |
129 | } | |
130 | }); | |
131 | ||
132 | Ext.applyIf(me, { | |
133 | title: gettext('Templates'), | |
134 | layout: 'fit', | |
135 | width: 600, | |
136 | height: 400, | |
137 | items: grid, | |
138 | buttons: [ submitBtn ] | |
139 | }); | |
140 | ||
141 | me.callParent(); | |
142 | } | |
143 | }); | |
144 | ||
145 | Ext.define('PVE.storage.Upload', { | |
146 | extend: 'Ext.window.Window', | |
147 | alias: ['widget.pveStorageUpload'], | |
148 | ||
149 | resizable: false, | |
150 | ||
151 | modal: true, | |
152 | ||
153 | initComponent : function() { | |
154 | /*jslint confusion: true */ | |
155 | var me = this; | |
156 | ||
157 | var xhr; | |
158 | ||
159 | if (!me.nodename) { | |
160 | throw "no node name specified"; | |
161 | } | |
162 | ||
163 | if (!me.storage) { | |
164 | throw "no storage ID specified"; | |
165 | } | |
166 | ||
167 | var baseurl = "/nodes/" + me.nodename + "/storage/" + me.storage + "/upload"; | |
168 | ||
169 | var pbar = Ext.create('Ext.ProgressBar', { | |
170 | text: 'Ready', | |
171 | hidden: true | |
172 | }); | |
173 | ||
174 | me.formPanel = Ext.create('Ext.form.Panel', { | |
175 | method: 'POST', | |
176 | waitMsgTarget: true, | |
177 | bodyPadding: 10, | |
178 | border: false, | |
179 | width: 300, | |
180 | fieldDefaults: { | |
181 | labelWidth: 100, | |
182 | anchor: '100%' | |
183 | }, | |
184 | items: [ | |
185 | { | |
186 | xtype: 'pveContentTypeSelector', | |
187 | cts: ['iso', 'vztmpl'], | |
188 | fieldLabel: gettext('Content'), | |
189 | name: 'content', | |
190 | value: 'iso' | |
191 | }, | |
192 | { | |
193 | xtype: 'filefield', | |
194 | name: 'filename', | |
195 | buttonText: gettext('Select File...'), | |
196 | allowBlank: false | |
197 | }, | |
198 | pbar | |
199 | ] | |
200 | }); | |
201 | ||
202 | var form = me.formPanel.getForm(); | |
203 | ||
204 | var doStandardSubmit = function() { | |
205 | form.submit({ | |
206 | url: "/api2/htmljs" + baseurl, | |
207 | waitMsg: gettext('Uploading file...'), | |
208 | success: function(f, action) { | |
209 | me.close(); | |
210 | }, | |
211 | failure: function(f, action) { | |
212 | var msg = PVE.Utils.extractFormActionError(action); | |
213 | Ext.Msg.alert(gettext('Error'), msg); | |
214 | } | |
215 | }); | |
216 | }; | |
217 | ||
218 | var updateProgress = function(per, bytes) { | |
219 | var text = (per * 100).toFixed(2) + '%'; | |
220 | if (bytes) { | |
221 | text += " (" + PVE.Utils.format_size(bytes) + ')'; | |
222 | } | |
223 | pbar.updateProgress(per, text); | |
224 | }; | |
225 | ||
226 | var abortBtn = Ext.create('Ext.Button', { | |
227 | text: gettext('Abort'), | |
228 | disabled: true, | |
229 | handler: function() { | |
230 | me.close(); | |
231 | } | |
232 | }); | |
233 | ||
234 | var submitBtn = Ext.create('Ext.Button', { | |
235 | text: gettext('Upload'), | |
236 | disabled: true, | |
237 | handler: function(button) { | |
238 | var fd; | |
239 | try { | |
240 | fd = new FormData(); | |
241 | } catch (err) { | |
242 | doStandardSubmit(); | |
243 | return; | |
244 | } | |
245 | ||
246 | button.setDisabled(true); | |
247 | abortBtn.setDisabled(false); | |
248 | ||
249 | var field = form.findField('content'); | |
250 | fd.append("content", field.getValue()); | |
251 | field.setDisabled(true); | |
252 | ||
253 | field = form.findField('filename'); | |
254 | var file = field.fileInputEl.dom; | |
255 | fd.append("filename", file.files[0]); | |
256 | field.setDisabled(true); | |
257 | ||
258 | pbar.setVisible(true); | |
259 | updateProgress(0); | |
260 | ||
261 | xhr = new XMLHttpRequest(); | |
262 | ||
263 | xhr.addEventListener("load", function(e) { | |
264 | if (xhr.status == 200) { | |
265 | me.close(); | |
266 | } else { | |
267 | var msg = gettext('Error') + " " + xhr.status.toString() + ": " + Ext.htmlEncode(xhr.statusText); | |
268 | var result = Ext.decode(xhr.responseText); | |
269 | result.message = msg; | |
270 | var htmlStatus = PVE.Utils.extractRequestError(result, true); | |
271 | Ext.Msg.alert(gettext('Error'), htmlStatus, function(btn) { | |
272 | me.close(); | |
273 | }); | |
274 | ||
275 | } | |
276 | }, false); | |
277 | ||
278 | xhr.addEventListener("error", function(e) { | |
279 | var msg = "Error " + e.target.status.toString() + " occurred while receiving the document."; | |
280 | Ext.Msg.alert(gettext('Error'), msg, function(btn) { | |
281 | me.close(); | |
282 | }); | |
283 | }); | |
284 | ||
285 | xhr.upload.addEventListener("progress", function(evt) { | |
286 | if (evt.lengthComputable) { | |
287 | var percentComplete = evt.loaded / evt.total; | |
288 | updateProgress(percentComplete, evt.loaded); | |
289 | } | |
290 | }, false); | |
291 | ||
292 | xhr.open("POST", "/api2/json" + baseurl, true); | |
293 | xhr.send(fd); | |
294 | } | |
295 | }); | |
296 | ||
297 | form.on('validitychange', function(f, valid) { | |
298 | submitBtn.setDisabled(!valid); | |
299 | }); | |
300 | ||
301 | Ext.applyIf(me, { | |
302 | title: gettext('Upload'), | |
303 | items: me.formPanel, | |
304 | buttons: [ abortBtn, submitBtn ], | |
305 | listeners: { | |
306 | close: function() { | |
307 | if (xhr) { | |
308 | xhr.abort(); | |
309 | } | |
310 | } | |
311 | } | |
312 | }); | |
313 | ||
314 | me.callParent(); | |
315 | } | |
316 | }); | |
317 | ||
318 | Ext.define('PVE.storage.ContentView', { | |
319 | extend: 'Ext.grid.GridPanel', | |
320 | ||
321 | alias: ['widget.pveStorageContentView'], | |
322 | ||
323 | initComponent : function() { | |
324 | var me = this; | |
325 | ||
326 | var nodename = me.pveSelNode.data.node; | |
327 | if (!nodename) { | |
328 | throw "no node name specified"; | |
329 | } | |
330 | ||
331 | var storage = me.pveSelNode.data.storage; | |
332 | if (!storage) { | |
333 | throw "no storage ID specified"; | |
334 | } | |
335 | ||
336 | var baseurl = "/nodes/" + nodename + "/storage/" + storage + "/content"; | |
337 | var store = new Ext.data.Store({ | |
338 | model: 'pve-storage-content', | |
339 | groupField: 'content', | |
340 | proxy: { | |
341 | type: 'pve', | |
342 | url: '/api2/json' + baseurl | |
343 | }, | |
344 | sorters: { | |
345 | property: 'volid', | |
346 | order: 'DESC' | |
347 | } | |
348 | }); | |
349 | ||
350 | var sm = Ext.create('Ext.selection.RowModel', {}); | |
351 | ||
352 | var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{ | |
353 | groupHeaderTpl: '{[ PVE.Utils.format_content_types(values.name) ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})' | |
354 | }); | |
355 | ||
356 | var reload = function() { | |
357 | store.load(); | |
358 | }; | |
359 | ||
360 | PVE.Utils.monStoreErrors(me, store); | |
361 | ||
362 | Ext.apply(me, { | |
363 | store: store, | |
364 | selModel: sm, | |
365 | stateful: false, | |
366 | viewConfig: { | |
367 | trackOver: false | |
368 | }, | |
369 | features: [ groupingFeature ], | |
370 | tbar: [ | |
371 | { | |
372 | xtype: 'pveButton', | |
373 | text: gettext('Restore'), | |
374 | selModel: sm, | |
375 | disabled: true, | |
376 | enableFn: function(rec) { | |
377 | return rec && rec.data.content === 'backup'; | |
378 | }, | |
379 | handler: function(b, e, rec) { | |
380 | var vmtype; | |
381 | if (rec.data.volid.match(/vzdump-qemu-/)) { | |
382 | vmtype = 'qemu'; | |
383 | } else if (rec.data.volid.match(/vzdump-openvz-/) || rec.data.volid.match(/vzdump-lxc-/)) { | |
384 | vmtype = 'lxc'; | |
385 | } else { | |
386 | return; | |
387 | } | |
388 | ||
389 | var win = Ext.create('PVE.window.Restore', { | |
390 | nodename: nodename, | |
391 | volid: rec.data.volid, | |
392 | volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec), | |
393 | vmtype: vmtype | |
394 | }); | |
395 | win.show(); | |
396 | win.on('destroy', reload); | |
397 | } | |
398 | }, | |
399 | { | |
400 | xtype: 'pveButton', | |
401 | text: gettext('Remove'), | |
402 | selModel: sm, | |
403 | disabled: true, | |
404 | confirmMsg: function(rec) { | |
405 | return Ext.String.format(gettext('Are you sure you want to remove entry {0}'), | |
406 | "'" + rec.data.volid + "'"); | |
407 | }, | |
408 | enableFn: function(rec) { | |
409 | return rec && rec.data.content !== 'images'; | |
410 | }, | |
411 | handler: function(b, e, rec) { | |
412 | PVE.Utils.API2Request({ | |
413 | url: baseurl + '/' + rec.data.volid, | |
414 | method: 'DELETE', | |
415 | waitMsgTarget: me, | |
416 | callback: function() { | |
417 | reload(); | |
418 | }, | |
419 | failure: function (response, opts) { | |
420 | Ext.Msg.alert(gettext('Error'), response.htmlStatus); | |
421 | } | |
422 | }); | |
423 | } | |
424 | }, | |
425 | { | |
426 | text: gettext('Templates'), | |
427 | handler: function() { | |
428 | var win = Ext.create('PVE.storage.TemplateDownload', { | |
429 | nodename: nodename, | |
430 | storage: storage | |
431 | }); | |
432 | win.show(); | |
433 | win.on('destroy', reload); | |
434 | } | |
435 | }, | |
436 | { | |
437 | text: gettext('Upload'), | |
438 | handler: function() { | |
439 | var win = Ext.create('PVE.storage.Upload', { | |
440 | nodename: nodename, | |
441 | storage: storage | |
442 | }); | |
443 | win.show(); | |
444 | win.on('destroy', reload); | |
445 | } | |
446 | }, | |
447 | '->', | |
448 | gettext('Search') + ':', ' ', | |
449 | { | |
450 | xtype: 'textfield', | |
451 | width: 200, | |
452 | enableKeyEvents: true, | |
453 | listeners: { | |
454 | buffer: 500, | |
455 | keyup: function(field) { | |
456 | store.clearFilter(true); | |
457 | store.filter([ | |
458 | { | |
459 | property: 'text', | |
460 | value: field.getValue(), | |
461 | anyMatch: true, | |
462 | caseSensitive: false | |
463 | } | |
464 | ]); | |
465 | } | |
466 | } | |
467 | } | |
468 | ], | |
469 | columns: [ | |
470 | { | |
471 | header: gettext('Name'), | |
472 | flex: 1, | |
473 | sortable: true, | |
474 | renderer: PVE.Utils.render_storage_content, | |
475 | dataIndex: 'text' | |
476 | }, | |
477 | { | |
478 | header: gettext('Format'), | |
479 | width: 100, | |
480 | dataIndex: 'format' | |
481 | }, | |
482 | { | |
483 | header: gettext('Size'), | |
484 | width: 100, | |
485 | renderer: PVE.Utils.format_size, | |
486 | dataIndex: 'size' | |
487 | } | |
488 | ], | |
489 | listeners: { | |
490 | show: reload | |
491 | } | |
492 | }); | |
493 | ||
494 | me.callParent(); | |
495 | } | |
496 | }, function() { | |
497 | ||
498 | Ext.define('pve-storage-content', { | |
499 | extend: 'Ext.data.Model', | |
500 | fields: [ | |
501 | 'volid', 'content', 'format', 'size', 'used', 'vmid', | |
502 | 'channel', 'id', 'lun', | |
503 | { | |
504 | name: 'text', | |
505 | convert: function(value, record) { | |
506 | if (value) { | |
507 | return value; | |
508 | } | |
509 | return PVE.Utils.render_storage_content(value, {}, record); | |
510 | } | |
511 | } | |
512 | ], | |
513 | idProperty: 'volid' | |
514 | }); | |
515 | ||
516 | }); |