]> git.proxmox.com Git - pve-manager.git/blob - www/manager/dc/Backup.js
7cf920d709010628a98b9bd89f82112dea056967
[pve-manager.git] / www / manager / dc / Backup.js
1 Ext.define('PVE.dc.BackupEdit', {
2 extend: 'PVE.window.Edit',
3 alias: ['widget.pveDcBackupEdit'],
4
5 initComponent : function() {
6 /*jslint confusion: true */
7 var me = this;
8
9 me.create = !me.jobid;
10
11 var url;
12 var method;
13
14 if (me.create) {
15 url = '/api2/extjs/cluster/backup';
16 method = 'POST';
17 } else {
18 url = '/api2/extjs/cluster/backup/' + me.jobid;
19 method = 'PUT';
20 }
21
22 var vmidField = Ext.create('Ext.form.field.Hidden', {
23 name: 'vmid'
24 });
25
26 var selModeField = Ext.create('PVE.form.KVComboBox', {
27 xtype: 'pveKVComboBox',
28 data: [
29 ['include', gettext('Include selected VMs')],
30 ['all', gettext('All')],
31 ['exclude', gettext('Exclude selected VMs')]
32 ],
33 fieldLabel: gettext('Selection mode'),
34 name: 'selMode',
35 value: ''
36 });
37
38 var insideUpdate = false;
39
40 var sm = Ext.create('Ext.selection.CheckboxModel', {
41 mode: 'SIMPLE',
42 listeners: {
43 selectionchange: function(model, selected) {
44 if (!insideUpdate) { // avoid endless loop
45 var sel = [];
46 Ext.Array.each(selected, function(record) {
47 sel.push(record.data.vmid);
48 });
49
50 insideUpdate = true;
51 vmidField.setValue(sel);
52 insideUpdate = false;
53 }
54 }
55 }
56 });
57
58 var storagesel = Ext.create('PVE.form.StorageSelector', {
59 fieldLabel: gettext('Storage'),
60 nodename: 'localhost',
61 storageContent: 'backup',
62 allowBlank: false,
63 name: 'storage'
64 });
65
66 var store = new Ext.data.Store({
67 model: 'PVEResources',
68 sorters: {
69 property: 'vmid',
70 order: 'ASC'
71 }
72 });
73
74 var vmgrid = Ext.createWidget('grid', {
75 store: store,
76 border: true,
77 height: 300,
78 selModel: sm,
79 disabled: true,
80 columns: [
81 {
82 header: 'ID',
83 dataIndex: 'vmid',
84 width: 60
85 },
86 {
87 header: gettext('Node'),
88 dataIndex: 'node'
89 },
90 {
91 header: gettext('Status'),
92 dataIndex: 'uptime',
93 renderer: function(value) {
94 if (value) {
95 return PVE.Utils.runningText;
96 } else {
97 return PVE.Utils.stoppedText;
98 }
99 }
100 },
101 {
102 header: gettext('Name'),
103 dataIndex: 'name',
104 flex: 1
105 },
106 {
107 header: gettext('Type'),
108 dataIndex: 'type'
109 }
110 ]
111 });
112
113 var nodesel = Ext.create('PVE.form.NodeSelector', {
114 name: 'node',
115 fieldLabel: gettext('Node'),
116 allowBlank: true,
117 editable: true,
118 autoSelect: false,
119 emptyText: '-- ' + gettext('All') + ' --',
120 listeners: {
121 change: function(f, value) {
122 storagesel.setNodename(value || 'localhost');
123 var mode = selModeField.getValue();
124 store.clearFilter();
125 store.filterBy(function(rec) {
126 return (!value || rec.get('node') === value);
127 });
128 if (mode === 'all') {
129 sm.selectAll(true);
130 }
131 }
132 }
133 });
134
135 var column1 = [
136 nodesel,
137 storagesel,
138 {
139 xtype: 'pveDayOfWeekSelector',
140 name: 'dow',
141 fieldLabel: gettext('Day of week'),
142 multiSelect: true,
143 value: ['sat'],
144 allowBlank: false
145 },
146 {
147 xtype: 'timefield',
148 fieldLabel: gettext('Start Time'),
149 name: 'starttime',
150 format: 'H:i',
151 value: '00:00',
152 allowBlank: false
153 },
154 selModeField
155 ];
156
157 var column2 = [
158 {
159 xtype: 'textfield',
160 fieldLabel: gettext('Send email to'),
161 name: 'mailto'
162 },
163 {
164 xtype: 'pveEmailNotificationSelector',
165 fieldLabel: gettext('Email notification'),
166 name: 'mailnotification',
167 deleteEmpty: me.create ? false : true,
168 value: me.create ? 'always' : ''
169 },
170 {
171 xtype: 'pveCompressionSelector',
172 fieldLabel: gettext('Compression'),
173 name: 'compress',
174 deleteEmpty: me.create ? false : true,
175 value: me.create ? 'lzo' : ''
176 },
177 {
178 xtype: 'pveBackupModeSelector',
179 fieldLabel: gettext('Mode'),
180 value: 'snapshot',
181 name: 'mode'
182 },
183 {
184 xtype: 'pvecheckbox',
185 fieldLabel: gettext('Enable'),
186 name: 'enabled',
187 uncheckedValue: 0,
188 defaultValue: 1,
189 checked: true
190 },
191 vmidField
192 ];
193
194 var ipanel = Ext.create('PVE.panel.InputPanel', {
195 column1: column1,
196 column2: column2,
197 onGetValues: function(values) {
198 if (!values.node) {
199 if (!me.create) {
200 PVE.Utils.assemble_field_data(values, { 'delete': 'node' });
201 }
202 delete values.node;
203 }
204
205 var selMode = values.selMode;
206 delete values.selMode;
207
208 if (selMode === 'all') {
209 values.all = 1;
210 values.exclude = '';
211 delete values.vmid;
212 } else if (selMode === 'exclude') {
213 values.all = 1;
214 values.exclude = values.vmid;
215 delete values.vmid;
216 }
217 return values;
218 }
219 });
220
221 var update_vmid_selection = function(list, mode) {
222 if (insideUpdate) {
223 return; // should not happen - just to be sure
224 }
225 insideUpdate = true;
226 if (mode !== 'all') {
227 sm.deselectAll(true);
228 if (list) {
229 Ext.Array.each(list.split(','), function(vmid) {
230 var rec = store.findRecord('vmid', vmid);
231 if (rec) {
232 sm.select(rec, true);
233 }
234 });
235 }
236 }
237 insideUpdate = false;
238 };
239
240 vmidField.on('change', function(f, value) {
241 var mode = selModeField.getValue();
242 update_vmid_selection(value, mode);
243 });
244
245 selModeField.on('change', function(f, value, oldValue) {
246 if (value === 'all') {
247 sm.selectAll(true);
248 vmgrid.setDisabled(true);
249 } else {
250 vmgrid.setDisabled(false);
251 }
252 if (oldValue === 'all') {
253 sm.deselectAll(true);
254 vmidField.setValue('');
255 }
256 var list = vmidField.getValue();
257 update_vmid_selection(list, value);
258 });
259
260 var reload = function() {
261 store.load({
262 params: { type: 'vm' },
263 callback: function() {
264 var node = nodesel.getValue();
265 store.clearFilter();
266 store.filterBy(function(rec) {
267 return (!node || rec.get('node') === node);
268 });
269 var list = vmidField.getValue();
270 var mode = selModeField.getValue();
271 if (mode === 'all') {
272 sm.selectAll(true);
273 } else {
274 update_vmid_selection(list, mode);
275 }
276 }
277 });
278 };
279
280 Ext.applyIf(me, {
281 subject: gettext("Backup Job"),
282 url: url,
283 method: method,
284 items: [ ipanel, vmgrid ]
285 });
286
287 me.callParent();
288
289 if (me.create) {
290 selModeField.setValue('include');
291 } else {
292 me.load({
293 success: function(response, options) {
294 var data = response.result.data;
295
296 data.dow = data.dow.split(',');
297
298 if (data.all || data.exclude) {
299 if (data.exclude) {
300 data.vmid = data.exclude;
301 data.selMode = 'exclude';
302 } else {
303 data.vmid = '';
304 data.selMode = 'all';
305 }
306 } else {
307 data.selMode = 'include';
308 }
309
310 me.setValues(data);
311 }
312 });
313 }
314
315 reload();
316 }
317 });
318
319
320 Ext.define('PVE.dc.BackupView', {
321 extend: 'Ext.grid.GridPanel',
322
323 alias: ['widget.pveDcBackupView'],
324
325 allText: '-- ' + gettext('All') + ' --',
326 allExceptText: gettext('All except {0}'),
327
328 initComponent : function() {
329 var me = this;
330
331 var store = new Ext.data.Store({
332 model: 'pve-cluster-backup',
333 proxy: {
334 type: 'pve',
335 url: "/api2/json/cluster/backup"
336 }
337 });
338
339 var reload = function() {
340 store.load();
341 };
342
343 var sm = Ext.create('Ext.selection.RowModel', {});
344
345 var run_editor = function() {
346 var rec = sm.getSelection()[0];
347 if (!rec) {
348 return;
349 }
350
351 var win = Ext.create('PVE.dc.BackupEdit',{
352 jobid: rec.data.id
353 });
354 win.on('destroy', reload);
355 win.show();
356 };
357
358 var edit_btn = new PVE.button.Button({
359 text: gettext('Edit'),
360 disabled: true,
361 selModel: sm,
362 handler: run_editor
363 });
364
365 var remove_btn = new PVE.button.Button({
366 text: gettext('Remove'),
367 disabled: true,
368 selModel: sm,
369 confirmMsg: gettext('Are you sure you want to remove this entry'),
370 handler: function(btn, event, rec) {
371 PVE.Utils.API2Request({
372 url: '/cluster/backup/' + rec.data.id,
373 method: 'DELETE',
374 waitMsgTarget: me,
375 callback: function() {
376 reload();
377 },
378 failure: function (response, opts) {
379 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
380 }
381 });
382 }
383 });
384
385 PVE.Utils.monStoreErrors(me, store);
386
387 Ext.apply(me, {
388 store: store,
389 selModel: sm,
390 stateful: false,
391 viewConfig: {
392 trackOver: false
393 },
394 tbar: [
395 {
396 text: gettext('Add'),
397 handler: function() {
398 var win = Ext.create('PVE.dc.BackupEdit',{});
399 win.on('destroy', reload);
400 win.show();
401 }
402 },
403 remove_btn,
404 edit_btn
405 ],
406 columns: [
407 {
408 header: gettext('Enabled'),
409 width: 50,
410 dataIndex: 'enabled',
411 renderer: PVE.Utils.format_boolean,
412 sortable: true
413 },
414 {
415 header: gettext('Node'),
416 width: 100,
417 sortable: true,
418 dataIndex: 'node',
419 renderer: function(value) {
420 if (value) {
421 return value;
422 }
423 return me.allText;
424 }
425 },
426 {
427 header: gettext('Day of week'),
428 width: 200,
429 sortable: false,
430 dataIndex: 'dow'
431 },
432 {
433 header: gettext('Start Time'),
434 width: 60,
435 sortable: true,
436 dataIndex: 'starttime'
437 },
438 {
439 header: gettext('Storage'),
440 width: 100,
441 sortable: true,
442 dataIndex: 'storage'
443 },
444 {
445 header: gettext('Selection'),
446 flex: 1,
447 sortable: false,
448 dataIndex: 'vmid',
449 renderer: function(value, metaData, record) {
450 /*jslint confusion: true */
451 if (record.data.all) {
452 if (record.data.exclude) {
453 return Ext.String.format(me.allExceptText, record.data.exclude);
454 }
455 return me.allText;
456 }
457 if (record.data.vmid) {
458 return record.data.vmid;
459 }
460
461 return "-";
462 }
463 }
464 ],
465 listeners: {
466 show: reload,
467 itemdblclick: run_editor
468 }
469 });
470
471 me.callParent();
472 }
473 }, function() {
474
475 Ext.define('pve-cluster-backup', {
476 extend: 'Ext.data.Model',
477 fields: [
478 'id', 'starttime', 'dow',
479 'storage', 'node', 'vmid', 'exclude',
480 'mailto',
481 { name: 'enabled', type: 'boolean' },
482 { name: 'all', type: 'boolean' },
483 { name: 'snapshot', type: 'boolean' },
484 { name: 'stop', type: 'boolean' },
485 { name: 'suspend', type: 'boolean' },
486 { name: 'compress', type: 'boolean' }
487 ]
488 });
489 });