]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/dc/Backup.js
1 Ext
.define('PVE.dc.BackupEdit', {
2 extend
: 'Proxmox.window.Edit',
3 alias
: ['widget.pveDcBackupEdit'],
5 defaultFocus
: undefined,
7 initComponent : function() {
10 me
.isCreate
= !me
.jobid
;
16 url
= '/api2/extjs/cluster/backup';
19 url
= '/api2/extjs/cluster/backup/' + me
.jobid
;
23 var vmidField
= Ext
.create('Ext.form.field.Hidden', {
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',
32 ['include', gettext('Include selected VMs')],
33 ['all', gettext('All')],
34 ['exclude', gettext('Exclude selected VMs')],
35 ['pool', gettext('Pool based')]
37 fieldLabel
: gettext('Selection mode'),
42 var sm
= Ext
.create('Ext.selection.CheckboxModel', {
45 selectionchange: function(model
, selected
) {
47 Ext
.Array
.each(selected
, function(record
) {
48 sel
.push(record
.data
.vmid
);
51 // to avoid endless recursion suspend the vmidField change
52 // event temporary as it calls us again
53 vmidField
.suspendEvent('change');
54 vmidField
.setValue(sel
);
55 vmidField
.resumeEvent('change');
60 var storagesel
= Ext
.create('PVE.form.StorageSelector', {
61 fieldLabel
: gettext('Storage'),
62 nodename
: 'localhost',
63 storageContent
: 'backup',
68 var store
= new Ext
.data
.Store({
69 model
: 'PVEResources',
76 var vmgrid
= Ext
.createWidget('grid', {
89 header
: gettext('Node'),
93 header
: gettext('Status'),
95 renderer: function(value
) {
97 return Proxmox
.Utils
.runningText
;
99 return Proxmox
.Utils
.stoppedText
;
104 header
: gettext('Name'),
109 header
: gettext('Type'),
115 var selectPoolMembers = function(poolid
) {
119 sm
.deselectAll(true);
130 var selPool
= Ext
.create('PVE.form.PoolSelector', {
131 fieldLabel
: gettext('Pool to backup'),
136 change: function( selpool
, newValue
, oldValue
) {
137 selectPoolMembers(newValue
);
142 var nodesel
= Ext
.create('PVE.form.NodeSelector', {
144 fieldLabel
: gettext('Node'),
148 emptyText
: '-- ' + gettext('All') + ' --',
150 change: function(f
, value
) {
151 storagesel
.setNodename(value
|| 'localhost');
152 var mode
= selModeField
.getValue();
154 store
.filterBy(function(rec
) {
155 return (!value
|| rec
.get('node') === value
);
157 if (mode
=== 'all') {
161 if (mode
=== 'pool') {
162 selectPoolMembers(selPool
.value
);
172 xtype
: 'pveDayOfWeekSelector',
174 fieldLabel
: gettext('Day of week'),
181 fieldLabel
: gettext('Start Time'),
195 fieldLabel
: gettext('Send email to'),
199 xtype
: 'pveEmailNotificationSelector',
200 fieldLabel
: gettext('Email notification'),
201 name
: 'mailnotification',
202 deleteEmpty
: me
.isCreate
? false : true,
203 value
: me
.isCreate
? 'always' : ''
206 xtype
: 'pveCompressionSelector',
207 fieldLabel
: gettext('Compression'),
209 deleteEmpty
: me
.isCreate
? false : true,
213 xtype
: 'pveBackupModeSelector',
214 fieldLabel
: gettext('Mode'),
219 xtype
: 'proxmoxcheckbox',
220 fieldLabel
: gettext('Enable'),
228 /*jslint confusion: false*/
230 var ipanel
= Ext
.create('Proxmox.panel.InputPanel', {
231 onlineHelp
: 'chapter_vzdump',
234 onGetValues: function(values
) {
237 Proxmox
.Utils
.assemble_field_data(values
, { 'delete': 'node' });
242 var selMode
= values
.selMode
;
243 delete values
.selMode
;
245 if (selMode
=== 'all') {
249 } else if (selMode
=== 'exclude') {
251 values
.exclude
= values
.vmid
;
253 } else if (selMode
=== 'pool') {
257 if (selMode
!== 'pool') {
264 var update_vmid_selection = function(list
, mode
) {
265 if (mode
!== 'all' && mode
!== 'pool') {
266 sm
.deselectAll(true);
268 Ext
.Array
.each(list
.split(','), function(vmid
) {
269 var rec
= store
.findRecord('vmid', vmid
);
271 sm
.select(rec
, true);
278 vmidField
.on('change', function(f
, value
) {
279 var mode
= selModeField
.getValue();
280 update_vmid_selection(value
, mode
);
283 selModeField
.on('change', function(f
, value
, oldValue
) {
284 if (oldValue
=== 'pool') {
285 store
.removeFilter('poolFilter');
288 if (oldValue
=== 'all') {
289 sm
.deselectAll(true);
290 vmidField
.setValue('');
293 if (value
=== 'all') {
295 vmgrid
.setDisabled(true);
297 vmgrid
.setDisabled(false);
300 if (value
=== 'pool') {
301 vmgrid
.setDisabled(true);
302 vmidField
.setValue('');
303 selPool
.setVisible(true);
304 selPool
.allowBlank
= false;
305 selectPoolMembers(selPool
.value
);
308 selPool
.setVisible(false);
309 selPool
.allowBlank
= true;
311 var list
= vmidField
.getValue();
312 update_vmid_selection(list
, value
);
315 var reload = function() {
317 params
: { type
: 'vm' },
318 callback: function() {
319 var node
= nodesel
.getValue();
321 store
.filterBy(function(rec
) {
322 return (!node
|| node
.length
=== 0 || rec
.get('node') === node
);
324 var list
= vmidField
.getValue();
325 var mode
= selModeField
.getValue();
326 if (mode
=== 'all') {
328 } else if (mode
=== 'pool'){
329 selectPoolMembers(selPool
.value
);
331 update_vmid_selection(list
, mode
);
338 subject
: gettext("Backup Job"),
341 items
: [ ipanel
, vmgrid
]
347 selModeField
.setValue('include');
350 success: function(response
, options
) {
351 var data
= response
.result
.data
;
353 data
.dow
= data
.dow
.split(',');
355 if (data
.all
|| data
.exclude
) {
357 data
.vmid
= data
.exclude
;
358 data
.selMode
= 'exclude';
361 data
.selMode
= 'all';
363 } else if (data
.pool
) {
364 data
.selMode
= 'pool';
365 data
.selPool
= data
.pool
;
367 data
.selMode
= 'include';
380 Ext
.define('PVE.dc.BackupView', {
381 extend
: 'Ext.grid.GridPanel',
383 alias
: ['widget.pveDcBackupView'],
385 onlineHelp
: 'chapter_vzdump',
387 allText
: '-- ' + gettext('All') + ' --',
388 allExceptText
: gettext('All except {0}'),
390 initComponent : function() {
393 var store
= new Ext
.data
.Store({
394 model
: 'pve-cluster-backup',
397 url
: "/api2/json/cluster/backup"
401 var reload = function() {
405 var sm
= Ext
.create('Ext.selection.RowModel', {});
407 var run_editor = function() {
408 var rec
= sm
.getSelection()[0];
413 var win
= Ext
.create('PVE.dc.BackupEdit', {
416 win
.on('destroy', reload
);
420 var run_backup_now = function(job
) {
421 job
= Ext
.clone(job
);
423 var allNodes
= PVE
.data
.ResourceStore
.getNodes();
424 var jobNode
= job
.node
;
426 // Remove properties related to scheduling
428 delete job
.starttime
;
432 job
.all
= job
.all
=== true ? 1 : 0;
435 var inProgress
= allNodes
.length
;
438 title
: gettext('Please wait...'),
442 Ext
.Msg
.updateProgress(0, '0/' + allNodes
.length
);
444 var postRequest = function () {
447 Ext
.Msg
.updateProgress(inProgress
/allNodes
.length
,
448 inProgress
+ '/' + allNodes
.length
);
450 if (inProgress
== allNodes
.length
) {
452 if (errors
!== undefined && errors
.length
> 0) {
453 Ext
.Msg
.alert('Error', 'Some errors have been encountered:<br />---<br />'
454 + errors
.join('<br />---<br />'));
459 allNodes
.forEach(node
=> {
460 if (node
.status
!== 'online' ||
461 (jobNode
!== undefined && jobNode
!== node
.node
)) {
462 errors
.push(node
.node
+ ": " + gettext("Node is offline"));
468 Proxmox
.Utils
.API2Request({
469 url
: '/nodes/' + node
.node
+ '/vzdump',
472 failure: function (response
, opts
) {
473 errors
.push(node
.node
+ ': ' + response
.htmlStatus
);
481 var edit_btn
= new Proxmox
.button
.Button({
482 text
: gettext('Edit'),
488 var run_btn
= new Proxmox
.button
.Button({
489 text
: gettext('Run now'),
492 handler: function() {
493 var rec
= sm
.getSelection()[0];
499 title
: gettext('Confirm'),
500 icon
: Ext
.Msg
.QUESTION
,
501 msg
: gettext('Start the selected backup job now?'),
502 buttons
: Ext
.Msg
.YESNO
,
503 callback: function(btn
) {
507 run_backup_now(rec
.data
);
513 var remove_btn
= Ext
.create('Proxmox.button.StdRemoveButton', {
515 baseurl
: '/cluster/backup',
516 callback: function() {
521 Proxmox
.Utils
.monStoreErrors(me
, store
);
527 stateId
: 'grid-dc-backup',
533 text
: gettext('Add'),
534 handler: function() {
535 var win
= Ext
.create('PVE.dc.BackupEdit',{});
536 win
.on('destroy', reload
);
546 header
: gettext('Enabled'),
548 dataIndex
: 'enabled',
549 xtype
: 'checkcolumn',
552 disabledCls
: 'x-item-enabled',
556 header
: gettext('Node'),
560 renderer: function(value
) {
568 header
: gettext('Day of week'),
572 renderer: function(val
) {
573 var dows
= ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
576 val
.split(',').forEach(function(day
){
578 var dow
= (dows
.indexOf(day
)+6)%7;
580 if (selected
.length
=== 0 || selected
[selected
.length
-1] === 0) {
583 selected
[selected
.length
-1]++;
596 selected
.forEach(function(item
) {
599 days
.push(Ext
.Date
.dayNames
[(cur
+1)] + '-' + Ext
.Date
.dayNames
[(cur
+item
)%7]);
601 } else if (item
== 2) {
602 days
.push(Ext
.Date
.dayNames
[cur
+1]);
603 days
.push(Ext
.Date
.dayNames
[(cur
+2)%7]);
605 } else if (item
== 1) {
606 days
.push(Ext
.Date
.dayNames
[(cur
+1)%7]);
609 return days
.join(', ');
613 header
: gettext('Start Time'),
616 dataIndex
: 'starttime'
619 header
: gettext('Storage'),
625 header
: gettext('Selection'),
629 renderer: function(value
, metaData
, record
) {
630 /*jslint confusion: true */
631 if (record
.data
.all
) {
632 if (record
.data
.exclude
) {
633 return Ext
.String
.format(me
.allExceptText
, record
.data
.exclude
);
637 if (record
.data
.vmid
) {
638 return record
.data
.vmid
;
641 if (record
.data
.pool
) {
642 return "Pool '"+ record
.data
.pool
+ "'";
651 itemdblclick
: run_editor
659 Ext
.define('pve-cluster-backup', {
660 extend
: 'Ext.data.Model',
662 'id', 'starttime', 'dow',
663 'storage', 'node', 'vmid', 'exclude',
664 'mailto', 'pool', 'compress', 'mode',
665 { name
: 'enabled', type
: 'boolean' },
666 { name
: 'all', type
: 'boolean' }