]> git.proxmox.com Git - proxmox-backup.git/blob - www/window/SyncJobEdit.js
ui: sync job: don't send delete value on creation
[proxmox-backup.git] / www / window / SyncJobEdit.js
1 Ext.define('PBS.window.SyncJobEdit', {
2 extend: 'Proxmox.window.Edit',
3 alias: 'widget.pbsSyncJobEdit',
4 mixins: ['Proxmox.Mixin.CBind'],
5
6 userid: undefined,
7
8 onlineHelp: 'syncjobs',
9
10 isAdd: true,
11
12 subject: gettext('Sync Job'),
13
14 bodyPadding: 0,
15
16 fieldDefaults: { labelWidth: 120 },
17 defaultFocus: 'proxmoxtextfield[name=comment]',
18
19 cbindData: function(initialConfig) {
20 let me = this;
21
22 let baseurl = '/api2/extjs/config/sync';
23 let id = initialConfig.id;
24
25 me.isCreate = !id;
26 me.url = id ? `${baseurl}/${id}` : baseurl;
27 me.method = id ? 'PUT' : 'POST';
28 me.autoLoad = !!id;
29 me.scheduleValue = id ? null : 'hourly';
30 me.authid = id ? null : Proxmox.UserName;
31 me.editDatastore = me.datastore === undefined && me.isCreate;
32 return { };
33 },
34
35 controller: {
36 xclass: 'Ext.app.ViewController',
37 control: {
38 'pbsDataStoreSelector[name=store]': {
39 change: 'storeChange',
40 },
41 },
42
43 storeChange: function(field, value) {
44 let view = this.getView();
45 let nsSelector = view.down('pbsNamespaceSelector[name=ns]');
46 nsSelector.setDatastore(value);
47 },
48 },
49
50 setValues: function(values) {
51 let me = this;
52 if (values.id && !values.remote) {
53 values.location = 'local';
54 } else {
55 values.location = 'remote';
56 }
57 me.callParent([values]);
58 },
59
60 items: {
61 xtype: 'tabpanel',
62 bodyPadding: 10,
63 border: 0,
64 items: [
65 {
66 title: 'Options',
67 xtype: 'inputpanel',
68 onGetValues: function(values) {
69 let me = this;
70
71 if (!values.id && me.up('pbsSyncJobEdit').isCreate) {
72 values.id = 's-' + Ext.data.identifier.Uuid.Global.generate().slice(0, 13);
73 }
74 if (!me.isCreate) {
75 PBS.Utils.delete_if_default(values, 'rate-in');
76 PBS.Utils.delete_if_default(values, 'remote');
77 if (typeof values.delete === 'string') {
78 values.delete = values.delete.split(',');
79 }
80 }
81 return values;
82 },
83 cbind: {
84 isCreate: '{isCreate}', // pass it through
85 },
86 column1: [
87 {
88 xtype: 'pmxDisplayEditField',
89 fieldLabel: gettext('Local Datastore'),
90 name: 'store',
91 submitValue: true,
92 cbind: {
93 editable: '{editDatastore}',
94 value: '{datastore}',
95 },
96 editConfig: {
97 xtype: 'pbsDataStoreSelector',
98 allowBlank: false,
99 },
100 },
101 {
102 xtype: 'pbsNamespaceSelector',
103 fieldLabel: gettext('Local Namespace'),
104 name: 'ns',
105 cbind: {
106 datastore: '{datastore}',
107 },
108 listeners: {
109 change: function(field, localNs) {
110 let me = this;
111 let view = me.up('pbsSyncJobEdit');
112
113 let remoteNs = view.down('pbsRemoteNamespaceSelector[name=remote-ns]').getValue();
114 let maxDepthField = view.down('field[name=max-depth]');
115 maxDepthField.setLimit(localNs, remoteNs);
116 maxDepthField.validate();
117 },
118 },
119 },
120 {
121 fieldLabel: gettext('Local Owner'),
122 xtype: 'pbsAuthidSelector',
123 name: 'owner',
124 cbind: {
125 value: '{authid}',
126 deleteEmpty: '{!isCreate}',
127 },
128 },
129 {
130 fieldLabel: gettext('Sync Schedule'),
131 xtype: 'pbsCalendarEvent',
132 name: 'schedule',
133 emptyText: gettext('none (disabled)'),
134 cbind: {
135 deleteEmpty: '{!isCreate}',
136 value: '{scheduleValue}',
137 },
138 },
139 {
140 xtype: 'pmxBandwidthField',
141 name: 'rate-in',
142 fieldLabel: gettext('Rate Limit'),
143 emptyText: gettext('Unlimited'),
144 submitAutoScaledSizeUnit: true,
145 // NOTE: handle deleteEmpty in onGetValues due to bandwidth field having a cbind too
146 },
147 ],
148
149 column2: [
150 {
151 xtype: 'radiogroup',
152 fieldLabel: gettext('Location'),
153 defaultType: 'radiofield',
154 items: [
155 {
156 boxLabel: 'Local',
157 name: 'location',
158 inputValue: 'local',
159 submitValue: false,
160 },
161 {
162 boxLabel: 'Remote',
163 name: 'location',
164 inputValue: 'remote',
165 submitValue: false,
166 checked: true,
167 },
168 ],
169 listeners: {
170 change: function(_group, radio) {
171 let me = this;
172 let form = me.up('pbsSyncJobEdit');
173 let nsField = form.down('field[name=remote-ns]');
174 let rateLimitField = form.down('field[name=rate-in]');
175 let remoteField = form.down('field[name=remote]');
176 let storeField = form.down('field[name=remote-store]');
177
178 if (!storeField.value) {
179 nsField.clearValue();
180 nsField.setDisabled(true);
181 }
182
183 let isLocalSync = radio.location === 'local';
184 rateLimitField.setDisabled(isLocalSync);
185 remoteField.allowBlank = isLocalSync;
186 remoteField.setDisabled(isLocalSync);
187 storeField.setDisabled(!isLocalSync && !remoteField.value);
188 if (isLocalSync === !!remoteField.value) {
189 remoteField.clearValue();
190 }
191
192 if (isLocalSync) {
193 storeField.setDisabled(false);
194 rateLimitField.setValue(null);
195 storeField.setRemote(null, true);
196 } else {
197 storeField.clearValue();
198 remoteField.validate();
199 }
200 },
201 },
202 },
203 {
204 fieldLabel: gettext('Source Remote'),
205 xtype: 'pbsRemoteSelector',
206 allowBlank: false,
207 name: 'remote',
208 skipEmptyText: true,
209 listeners: {
210 change: function(f, value) {
211 let me = this;
212 let remoteStoreField = me.up('pbsSyncJobEdit').down('field[name=remote-store]');
213 remoteStoreField.setRemote(value);
214 let rateLimitField = me.up('pbsSyncJobEdit').down('field[name=rate-in]');
215 rateLimitField.setDisabled(!value);
216 if (!value) {
217 rateLimitField.setValue(null);
218 }
219 let remoteNamespaceField = me.up('pbsSyncJobEdit').down('field[name=remote-ns]');
220 remoteNamespaceField.setRemote(value);
221 },
222 },
223 },
224 {
225 fieldLabel: gettext('Source Datastore'),
226 xtype: 'pbsRemoteStoreSelector',
227 allowBlank: false,
228 autoSelect: false,
229 name: 'remote-store',
230 cbind: {
231 datastore: '{datastore}',
232 },
233 listeners: {
234 change: function(field, value) {
235 let me = this;
236 let remoteField = me.up('pbsSyncJobEdit').down('field[name=remote]');
237 let remote = remoteField.getValue();
238 let remoteNamespaceField = me.up('pbsSyncJobEdit').down('field[name=remote-ns]');
239 remoteNamespaceField.setRemote(remote);
240 remoteNamespaceField.setRemoteStore(value);
241 me.up('tabpanel').down('pbsGroupFilter').setRemoteDatastore(remote, value);
242 },
243 },
244 },
245 {
246 fieldLabel: gettext('Source Namespace'),
247 xtype: 'pbsRemoteNamespaceSelector',
248 allowBlank: true,
249 autoSelect: false,
250 name: 'remote-ns',
251 disabled: true,
252 listeners: {
253 change: function(field, remoteNs) {
254 let me = this;
255 let view = me.up('pbsSyncJobEdit');
256
257 let remote = view.down('field[name=remote]').getValue();
258 let remoteStore = view.down('field[name=remote-store]').getValue();
259 me.up('tabpanel').down('pbsGroupFilter').setRemoteNamespace(remote, remoteStore, remoteNs);
260
261 let localNs = view.down('pbsNamespaceSelector[name=ns]').getValue();
262 let maxDepthField = view.down('field[name=max-depth]');
263 maxDepthField.setLimit(localNs, remoteNs);
264 maxDepthField.validate();
265 },
266 },
267 },
268 {
269 xtype: 'pbsNamespaceMaxDepthReduced',
270 name: 'max-depth',
271 fieldLabel: gettext('Max. Depth'),
272 cbind: {
273 deleteEmpty: '{!isCreate}',
274 },
275 },
276 {
277 fieldLabel: gettext('Remove vanished'),
278 xtype: 'proxmoxcheckbox',
279 name: 'remove-vanished',
280 autoEl: {
281 tag: 'div',
282 'data-qtip': gettext('Remove snapshots from local datastore if they vanished from source datastore?'),
283 },
284 uncheckedValue: false,
285 value: false,
286 },
287 ],
288
289 columnB: [
290 {
291 fieldLabel: gettext('Comment'),
292 xtype: 'proxmoxtextfield',
293 name: 'comment',
294 cbind: {
295 deleteEmpty: '{!isCreate}',
296 },
297 },
298 ],
299 advancedColumn1: [
300 {
301 xtype: 'pmxDisplayEditField',
302 fieldLabel: gettext('Job ID'),
303 emptyText: gettext('Autogenerate'),
304 name: 'id',
305 allowBlank: true,
306 regex: PBS.Utils.SAFE_ID_RE,
307 cbind: {
308 editable: '{isCreate}',
309 },
310 },
311 {
312 fieldLabel: gettext('Transfer Last'),
313 xtype: 'pbsPruneKeepInput',
314 name: 'transfer-last',
315 emptyText: gettext('all'),
316 autoEl: {
317 tag: 'div',
318 'data-qtip': gettext('The maximum amount of snapshots to be transferred (per group)'),
319 },
320 cbind: {
321 deleteEmpty: '{!isCreate}',
322 },
323 },
324 ],
325 },
326 {
327 xtype: 'inputpanel',
328 onGetValues: function(values) {
329 let me = this;
330 PBS.Utils.delete_if_default(values, 'group-filter');
331 if (Ext.isArray(values['group-filter'])) {
332 if (values['group-filter'].length === 0) {
333 delete values['group-filter'];
334 values.delete = 'group-filter';
335 } else {
336 // merge duplicates
337 values['group-filter'] = [...new Set(values['group-filter'])];
338 }
339 }
340 if (me.isCreate) {
341 delete values.delete;
342 }
343 return values;
344 },
345 cbind: {
346 isCreate: '{isCreate}', // pass it through
347 },
348 title: gettext('Group Filter'),
349 items: [
350 {
351 xtype: 'pbsGroupFilter',
352 name: 'group-filter',
353 },
354 ],
355 },
356 ],
357 },
358 });