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