]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/dc/CorosyncLinkEdit.js
ui: eslint: enforce "no-extra-parens" rule
[pve-manager.git] / www / manager6 / dc / CorosyncLinkEdit.js
1 Ext.define('PVE.form.CorosyncLinkEditorController', {
2 extend: 'Ext.app.ViewController',
3 alias: 'controller.pveCorosyncLinkEditorController',
4
5 addLinkIfEmpty: function() {
6 let view = this.getView();
7 if (view.items || view.items.length == 0) {
8 this.addLink();
9 }
10 },
11
12 addEmptyLink: function() {
13 // discard parameters to allow being called from 'handler'
14 this.addLink();
15 },
16
17 addLink: function(link) {
18 let me = this;
19 let view = me.getView();
20 let vm = view.getViewModel();
21
22 let linkCount = vm.get('linkCount');
23 if (linkCount >= vm.get('maxLinkCount')) {
24 return;
25 }
26
27 link = link || {};
28
29 if (link.number === undefined) {
30 link.number = me.getNextFreeNumber();
31 }
32 if (link.value === undefined) {
33 link.value = me.getNextFreeNetwork();
34 }
35
36 let linkSelector = Ext.create('PVE.form.CorosyncLinkSelector', {
37 maxLinkNumber: vm.get('maxLinkCount') - 1,
38 allowNumberEdit: vm.get('allowNumberEdit'),
39 allowBlankNetwork: link.allowBlank,
40 initNumber: link.number,
41 initNetwork: link.value,
42 text: link.text,
43 emptyText: link.emptyText,
44
45 // needs to be set here, because we need to update the viewmodel
46 removeBtnHandler: function() {
47 let curLinkCount = vm.get('linkCount');
48
49 if (curLinkCount <= 1) {
50 return;
51 }
52
53 vm.set('linkCount', curLinkCount - 1);
54
55 // 'this' is the linkSelector here
56 view.remove(this);
57
58 me.updateDeleteButtonState();
59 },
60 });
61
62 view.add(linkSelector);
63
64 linkCount++;
65 vm.set('linkCount', linkCount);
66
67 me.updateDeleteButtonState();
68 },
69
70 // ExtJS trips on binding this for some reason, so do it manually
71 updateDeleteButtonState: function() {
72 let view = this.getView();
73 let vm = view.getViewModel();
74
75 let disabled = vm.get('linkCount') <= 1;
76
77 let deleteButtons = view.query('button[cls=removeLinkBtn]');
78 Ext.Array.each(deleteButtons, btn => {
79 btn.setDisabled(disabled);
80 });
81 },
82
83 getNextFreeNetwork: function() {
84 let view = this.getView();
85 let vm = view.getViewModel();
86 let netsInUse = Ext.Array.map(
87 view.query('proxmoxNetworkSelector'), selector => selector.value);
88
89 // default to empty field, user has to set up link manually
90 let retval = undefined;
91
92 let nets = vm.get('networks');
93 Ext.Array.each(nets, net => {
94 if (!Ext.Array.contains(netsInUse, net)) {
95 retval = net;
96 return false; // break
97 }
98 });
99
100 return retval;
101 },
102
103 getNextFreeNumber: function() {
104 let view = this.getView();
105 let vm = view.getViewModel();
106 let numbersInUse = Ext.Array.map(
107 view.query('numberfield'), field => field.value);
108
109 for (let i = 0; i < vm.get('maxLinkCount'); i++) {
110 if (!Ext.Array.contains(numbersInUse, i)) {
111 return i;
112 }
113 }
114
115 // all numbers in use, this should never happen since add button is
116 // disabled automatically
117 return 0;
118 },
119 });
120
121 Ext.define('PVE.form.CorosyncLinkSelector', {
122 extend: 'Ext.panel.Panel',
123 xtype: 'pveCorosyncLinkSelector',
124
125 mixins: ['Proxmox.Mixin.CBind'],
126 cbindData: [],
127
128 // config
129 maxLinkNumber: 7,
130 allowNumberEdit: true,
131 allowBlankNetwork: false,
132 removeBtnHandler: undefined,
133 emptyText: '',
134
135 // values
136 initNumber: 0,
137 initNetwork: '',
138 text: '',
139
140 layout: 'hbox',
141 bodyPadding: 5,
142 border: 0,
143
144 items: [
145 {
146 xtype: 'displayfield',
147 fieldLabel: 'Link',
148 cbind: {
149 hidden: '{allowNumberEdit}',
150 value: '{initNumber}',
151 },
152 width: 45,
153 labelWidth: 30,
154 allowBlank: false,
155 },
156 {
157 xtype: 'numberfield',
158 fieldLabel: 'Link',
159 cbind: {
160 maxValue: '{maxLinkNumber}',
161 hidden: '{!allowNumberEdit}',
162 value: '{initNumber}',
163 },
164 width: 80,
165 labelWidth: 30,
166 minValue: 0,
167 submitValue: false, // see getSubmitValue of network selector
168 allowBlank: false,
169 },
170 {
171 xtype: 'proxmoxNetworkSelector',
172 cbind: {
173 allowBlank: '{allowBlankNetwork}',
174 value: '{initNetwork}',
175 emptyText: '{emptyText}',
176 },
177 autoSelect: false,
178 valueField: 'address',
179 displayField: 'address',
180 width: 220,
181 margin: '0 5px 0 5px',
182 getSubmitValue: function() {
183 // link number is encoded into key, so we need to set field
184 // name before value retrieval
185 let me = this;
186 let numSelect = me.prev('numberfield'); // always the correct one
187 let linkNumber = numSelect.getValue();
188 me.name = 'link' + linkNumber;
189 return me.getValue();
190 },
191 },
192 {
193 xtype: 'button',
194 iconCls: 'fa fa-trash-o',
195 cls: 'removeLinkBtn',
196 cbind: {
197 hidden: '{!allowNumberEdit}',
198 },
199 handler: function() {
200 let me = this;
201 let parent = me.up('pveCorosyncLinkSelector');
202 if (parent.removeBtnHandler !== undefined) {
203 parent.removeBtnHandler();
204 }
205 },
206 },
207 {
208 xtype: 'label',
209 margin: '-1px 0 0 5px',
210
211 // for muted effect
212 cls: 'x-form-item-label-default',
213
214 cbind: {
215 text: '{text}',
216 },
217 },
218 ],
219
220 initComponent: function() {
221 let me = this;
222
223 me.callParent();
224
225 let numSelect = me.down('numberfield');
226 let netSelect = me.down('proxmoxNetworkSelector');
227
228 numSelect.validator = this.createNoDuplicatesValidator(
229 'numberfield',
230 gettext("Duplicate link number not allowed."),
231 );
232
233 netSelect.validator = this.createNoDuplicatesValidator(
234 'proxmoxNetworkSelector',
235 gettext("Duplicate link address not allowed."),
236 );
237 },
238
239 createNoDuplicatesValidator: function(queryString, errorMsg) {
240 // linkSelector
241 let me = this;
242
243 return function(val) {
244 let curField = this;
245 let form = me.up('form');
246 let linkEditor = me.up('pveCorosyncLinkEditor');
247
248 if (!form.validating) {
249 // avoid recursion/double validation by setting temporary states
250 curField.validating = true;
251 form.validating = true;
252
253 // validate all other fields as well, to always mark both
254 // parties involved in a 'duplicate' error
255 form.isValid();
256
257 form.validating = false;
258 curField.validating = false;
259 } else if (curField.validating) {
260 // we'll be validated by the original call in the other
261 // if-branch, avoid double work
262 return true;
263 }
264
265 if (val === undefined || val instanceof String && val.length === 0) {
266 // let this be caught by allowBlank, if at all
267 return true;
268 }
269
270 let allFields = linkEditor.query(queryString);
271 let err = undefined;
272 Ext.Array.each(allFields, field => {
273 if (field != curField && field.getValue() == val) {
274 err = errorMsg;
275 return false; // break
276 }
277 });
278
279 return err || true;
280 };
281 },
282 });
283
284 Ext.define('PVE.form.CorosyncLinkEditor', {
285 extend: 'Ext.panel.Panel',
286 xtype: 'pveCorosyncLinkEditor',
287
288 controller: 'pveCorosyncLinkEditorController',
289
290 // only initial config, use setter otherwise
291 allowNumberEdit: true,
292
293 viewModel: {
294 data: {
295 linkCount: 0,
296 maxLinkCount: 8,
297 networks: null,
298 allowNumberEdit: true,
299 infoText: '',
300 },
301 formulas: {
302 addDisabled: function(get) {
303 return !get('allowNumberEdit') ||
304 get('linkCount') >= get('maxLinkCount');
305 },
306 dockHidden: function(get) {
307 return !(get('allowNumberEdit') || get('infoText'));
308 },
309 },
310 },
311
312 dockedItems: [{
313 xtype: 'toolbar',
314 dock: 'bottom',
315 defaultButtonUI: 'default',
316 border: false,
317 padding: '6 0 6 0',
318 bind: {
319 hidden: '{dockHidden}',
320 },
321 items: [
322 {
323 xtype: 'button',
324 text: gettext('Add'),
325 bind: {
326 disabled: '{addDisabled}',
327 hidden: '{!allowNumberEdit}',
328 },
329 handler: 'addEmptyLink',
330 },
331 {
332 xtype: 'label',
333 bind: {
334 text: '{infoText}',
335 },
336 },
337 ],
338 }],
339
340 setInfoText: function(text) {
341 let me = this;
342 let vm = me.getViewModel();
343
344 vm.set('infoText', text || '');
345 },
346
347 setLinks: function(links) {
348 let me = this;
349 let controller = me.getController();
350 let vm = me.getViewModel();
351
352 me.removeAll();
353 vm.set('linkCount', 0);
354
355 Ext.Array.each(links, link => controller.addLink(link));
356 },
357
358 setDefaultLinks: function() {
359 let me = this;
360 let controller = me.getController();
361 let vm = me.getViewModel();
362
363 me.removeAll();
364 vm.set('linkCount', 0);
365 controller.addLink();
366 },
367
368 // clears all links
369 setAllowNumberEdit: function(allow) {
370 let me = this;
371 let vm = me.getViewModel();
372 vm.set('allowNumberEdit', allow);
373 me.removeAll();
374 vm.set('linkCount', 0);
375 },
376
377 items: [{
378 // No links is never a valid scenario, but can occur during a slow load
379 xtype: 'hiddenfield',
380 submitValue: false,
381 isValid: function() {
382 let me = this;
383 let vm = me.up('pveCorosyncLinkEditor').getViewModel();
384 return vm.get('linkCount') > 0;
385 },
386 }],
387
388 initComponent: function() {
389 let me = this;
390 let vm = me.getViewModel();
391 let controller = me.getController();
392
393 vm.set('allowNumberEdit', me.allowNumberEdit);
394 vm.set('infoText', me.infoText || '');
395
396 me.callParent();
397
398 // Request local node networks to pre-populate first link.
399 Proxmox.Utils.API2Request({
400 url: '/nodes/localhost/network',
401 method: 'GET',
402 waitMsgTarget: me,
403 success: response => {
404 let data = response.result.data;
405 if (data.length > 0) {
406 data.sort((a, b) => a.iface.localeCompare(b.iface));
407 let addresses = [];
408 for (let net of data) {
409 if (net.address) {
410 addresses.push(net.address);
411 }
412 if (net.address6) {
413 addresses.push(net.address6);
414 }
415 }
416
417 vm.set('networks', addresses);
418 }
419
420 // Always have at least one link, but account for delay in API,
421 // someone might have called 'setLinks' in the meantime -
422 // except if 'allowNumberEdit' is false, in which case we're
423 // probably waiting for the user to input the join info
424 if (vm.get('allowNumberEdit')) {
425 controller.addLinkIfEmpty();
426 }
427 },
428 failure: () => {
429 if (vm.get('allowNumberEdit')) {
430 controller.addLinkIfEmpty();
431 }
432 },
433 });
434 },
435 });
436