]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/window/Backup.js
ui: bulk actions: reorder fields and drop local-storage warning
[pve-manager.git] / www / manager6 / window / Backup.js
CommitLineData
56c8ef92
DM
1Ext.define('PVE.window.Backup', {
2 extend: 'Ext.window.Window',
3
4 resizable: false,
5
8058410f 6 initComponent: function() {
56c8ef92
DM
7 var me = this;
8
9 if (!me.nodename) {
10 throw "no node name specified";
11 }
12
13 if (!me.vmid) {
14 throw "no VM ID specified";
15 }
16
17 if (!me.vmtype) {
18 throw "no VM type specified";
19 }
20
5265a2d1 21 let compressionSelector = Ext.create('PVE.form.BackupCompressionSelector', {
62ce8928
TL
22 name: 'compress',
23 value: 'zstd',
24 fieldLabel: gettext('Compression'),
25 });
26
fddb0412
FE
27 let modeSelector = Ext.create('PVE.form.BackupModeSelector', {
28 fieldLabel: gettext('Mode'),
29 value: 'snapshot',
30 name: 'mode',
31 });
32
d7e19768
LW
33 let notificationTargetSelector = Ext.create('PVE.form.NotificationTargetSelector', {
34 fieldLabel: gettext('Notification target'),
35 name: 'notification-target',
36 emptyText: Proxmox.Utils.noneText,
37 hidden: true,
38 });
39
fddb0412
FE
40 let mailtoField = Ext.create('Ext.form.field.Text', {
41 fieldLabel: gettext('Send email to'),
42 name: 'mailto',
43 emptyText: Proxmox.Utils.noneText,
44 });
45
d7e19768
LW
46 let notificationModeSelector = Ext.create('PVE.form.NotificationModeSelector', {
47 fieldLabel: gettext('Notify via'),
48 value: 'mailto',
49 name: 'notification-mode',
50 listeners: {
51 change: function(f, v) {
52 let mailSelected = v === 'mailto';
53 notificationTargetSelector.setHidden(mailSelected);
54 mailtoField.setHidden(!mailSelected);
55 },
56 },
57 });
58
170f8fb4
FE
59 const keepNames = [
60 ['keep-last', gettext('Keep Last')],
61 ['keep-hourly', gettext('Keep Hourly')],
62 ['keep-daily', gettext('Keep Daily')],
63 ['keep-weekly', gettext('Keep Weekly')],
64 ['keep-monthly', gettext('Keep Monthly')],
65 ['keep-yearly', gettext('Keep Yearly')],
66 ];
67
68 let pruneSettings = keepNames.map(
69 name => Ext.create('Ext.form.field.Display', {
70 name: name[0],
71 fieldLabel: name[1],
72 hidden: true,
73 }),
74 );
75
76 let removeCheckbox = Ext.create('Proxmox.form.Checkbox', {
77 name: 'remove',
78 checked: false,
79 hidden: true,
80 uncheckedValue: 0,
81 fieldLabel: gettext('Prune'),
82 autoEl: {
83 tag: 'div',
84 'data-qtip': gettext('Prune older backups afterwards'),
85 },
86 handler: function(checkbox, value) {
87 pruneSettings.forEach(field => field.setHidden(!value));
f2e174da 88 me.down('label[name="pruneLabel"]').setHidden(!value);
170f8fb4
FE
89 },
90 });
91
fddb0412
FE
92 let initialDefaults = false;
93
56c8ef92
DM
94 var storagesel = Ext.create('PVE.form.StorageSelector', {
95 nodename: me.nodename,
96 name: 'storage',
56c8ef92
DM
97 fieldLabel: gettext('Storage'),
98 storageContent: 'backup',
62ce8928
TL
99 allowBlank: false,
100 listeners: {
101 change: function(f, v) {
5ad3fbfa
FE
102 if (!initialDefaults) {
103 me.setLoading(false);
104 }
105
6d52223b
FE
106 if (v === null || v === undefined || v === '') {
107 return;
108 }
109
62ce8928 110 let store = f.getStore();
8267aa63 111 let rec = store.findRecord('storage', v, 0, false, true, true);
62ce8928
TL
112
113 if (rec && rec.data && rec.data.type === 'pbs') {
114 compressionSelector.setValue('zstd');
115 compressionSelector.setDisabled(true);
116 } else if (!compressionSelector.getEditable()) {
117 compressionSelector.setDisabled(false);
118 }
fddb0412
FE
119
120 Proxmox.Utils.API2Request({
121 url: `/nodes/${me.nodename}/vzdump/defaults`,
122 method: 'GET',
123 params: {
124 storage: v,
125 },
126 waitMsgTarget: me,
127 success: function(response, opts) {
128 const data = response.result.data;
129
d7e19768
LW
130 if (!initialDefaults && data['notification-mode'] !== undefined) {
131 notificationModeSelector.setValue(data['notification-mode']);
132 }
133 if (!initialDefaults && data['notification-channel'] !== undefined) {
134 notificationTargetSelector.setValue(data['notification-channel']);
135 }
fddb0412
FE
136 if (!initialDefaults && data.mailto !== undefined) {
137 mailtoField.setValue(data.mailto);
138 }
139 if (!initialDefaults && data.mode !== undefined) {
140 modeSelector.setValue(data.mode);
141 }
c4dca88b 142 if (!initialDefaults && (data['notes-template'] ?? false)) {
6a3052b2
FE
143 me.down('field[name=notes-template]').setValue(
144 PVE.Utils.unEscapeNotesTemplate(data['notes-template']),
145 );
c4dca88b 146 }
fddb0412
FE
147
148 initialDefaults = true;
170f8fb4
FE
149
150 // always update storage dependent properties
151 if (data['prune-backups'] !== undefined) {
152 const keepParams = PVE.Parser.parsePropertyString(
153 data["prune-backups"],
154 );
155 if (!keepParams['keep-all']) {
156 removeCheckbox.setHidden(false);
157 pruneSettings.forEach(function(field) {
158 const keep = keepParams[field.name];
159 if (keep) {
160 field.setValue(keep);
161 } else {
162 field.reset();
163 }
164 });
165 return;
166 }
167 }
168
169 // no defaults or keep-all=1
170 removeCheckbox.setHidden(true);
171 removeCheckbox.setValue(false);
172 pruneSettings.forEach(field => field.reset());
fddb0412
FE
173 },
174 failure: function(response, opts) {
b0d716e4 175 initialDefaults = true;
01a69af4
FE
176
177 removeCheckbox.setHidden(true);
178 removeCheckbox.setValue(false);
179 pruneSettings.forEach(field => field.reset());
180
fddb0412
FE
181 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
182 },
183 });
f6710aac 184 },
62ce8928 185 },
56c8ef92
DM
186 });
187
5e73ffe6
FE
188 let protectedCheckbox = Ext.create('Proxmox.form.Checkbox', {
189 name: 'protected',
190 checked: false,
191 uncheckedValue: 0,
192 fieldLabel: gettext('Protected'),
193 });
194
bef57f5c 195 me.formPanel = Ext.create('Proxmox.panel.InputPanel', {
56c8ef92
DM
196 bodyPadding: 10,
197 border: false,
0b240dbf 198 column1: [
56c8ef92 199 storagesel,
fddb0412 200 modeSelector,
5e73ffe6 201 protectedCheckbox,
0b240dbf
FE
202 ],
203 column2: [
62ce8928 204 compressionSelector,
d7e19768
LW
205 notificationModeSelector,
206 notificationTargetSelector,
fddb0412 207 mailtoField,
5e73ffe6 208 removeCheckbox,
aa396ea6 209 ],
f2e174da 210 columnB: [
5e73ffe6
FE
211 {
212 xtype: 'textareafield',
213 name: 'notes-template',
214 fieldLabel: gettext('Notes'),
215 anchor: '100%',
216 value: '{{guestname}}',
03875d7a
FE
217 },
218 {
219 xtype: 'box',
220 style: {
221 margin: '8px 0px',
222 'line-height': '1.5em',
5e73ffe6 223 },
03875d7a
FE
224 html: Ext.String.format(
225 gettext('Possible template variables are: {0}'),
226 PVE.Utils.notesTemplateVars.map(v => `<code>{{${v}}}</code>`).join(', '),
227 ),
5e73ffe6 228 },
f2e174da
TL
229 {
230 xtype: 'label',
231 name: 'pruneLabel',
232 text: gettext('Storage Retention Configuration') + ':',
233 hidden: true,
170f8fb4 234 },
f2e174da
TL
235 {
236 layout: 'hbox',
237 border: false,
238 defaults: {
239 border: false,
240 layout: 'anchor',
241 flex: 1,
170f8fb4 242 },
f2e174da
TL
243 items: [
244 {
245 padding: '0 10 0 0',
246 defaults: {
247 labelWidth: 110,
248 },
249 items: [
250 pruneSettings[0],
251 pruneSettings[2],
252 pruneSettings[4],
253 ],
170f8fb4 254 },
f2e174da
TL
255 {
256 padding: '0 0 0 10',
257 defaults: {
258 labelWidth: 110,
259 },
260 items: [
261 pruneSettings[1],
262 pruneSettings[3],
263 pruneSettings[5],
264 ],
265 },
266 ],
267 },
268 ],
56c8ef92
DM
269 });
270
56c8ef92
DM
271 var submitBtn = Ext.create('Ext.Button', {
272 text: gettext('Backup'),
8058410f 273 handler: function() {
56c8ef92 274 var storage = storagesel.getValue();
bef57f5c 275 let values = me.formPanel.getValues();
56c8ef92
DM
276 var params = {
277 storage: storage,
278 vmid: me.vmid,
279 mode: values.mode,
170f8fb4 280 remove: values.remove,
56c8ef92 281 };
8b8a4583 282
d7e19768 283 if (values.mailto && values['notification-mode'] === 'mailto') {
8b8a4583
DC
284 params.mailto = values.mailto;
285 }
286
d7e19768
LW
287 if (values['notification-target'] &&
288 values['notification-mode'] === 'notification-target') {
289 params['notification-target'] = values['notification-target'];
290 }
291
56c8ef92
DM
292 if (values.compress) {
293 params.compress = values.compress;
294 }
295
5e73ffe6
FE
296 if (values.protected) {
297 params.protected = values.protected;
298 }
299
300 if (values['notes-template']) {
301 params['notes-template'] = PVE.Utils.escapeNotesTemplate(
302 values['notes-template']);
303 }
304
e7ade592 305 Proxmox.Utils.API2Request({
56c8ef92
DM
306 url: '/nodes/' + me.nodename + '/vzdump',
307 params: params,
308 method: 'POST',
8058410f 309 failure: function(response, opts) {
f6710aac 310 Ext.Msg.alert('Error', response.htmlStatus);
56c8ef92
DM
311 },
312 success: function(response, options) {
e83e60bf
EK
313 // close later so we reload the grid
314 // after the task has completed
315 me.hide();
316
56c8ef92 317 var upid = response.result.data;
2a4971d8 318
8cbc11a7 319 var win = Ext.create('Proxmox.window.TaskViewer', {
e83e60bf
EK
320 upid: upid,
321 listeners: {
322 close: function() {
323 me.close();
f6710aac
TL
324 },
325 },
56c8ef92
DM
326 });
327 win.show();
f6710aac 328 },
56c8ef92 329 });
f6710aac 330 },
56c8ef92
DM
331 });
332
672a6270 333 var helpBtn = Ext.create('Proxmox.button.Help', {
0de33b54
EK
334 onlineHelp: 'chapter_vzdump',
335 listenToGlobalEvent: false,
f6710aac 336 hidden: false,
0de33b54
EK
337 });
338
2a4971d8 339 var title = gettext('Backup') + " " +
53e3ea84 340 (me.vmtype === 'lxc' ? "CT" : "VM") +
56c8ef92
DM
341 " " + me.vmid;
342
343 Ext.apply(me, {
344 title: title,
56c8ef92
DM
345 modal: true,
346 layout: 'auto',
347 border: false,
5e73ffe6 348 width: 600,
8058410f
TL
349 items: [me.formPanel],
350 buttons: [helpBtn, '->', submitBtn],
5ad3fbfa
FE
351 listeners: {
352 afterrender: function() {
353 /// cleared within the storage selector's change listener
354 me.setLoading(gettext('Please wait...'));
355 storagesel.setValue(me.storage);
356 },
357 },
56c8ef92
DM
358 });
359
360 me.callParent();
f6710aac 361 },
56c8ef92 362});