]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/dc/CorosyncLinkEdit.js
1 Ext
.define('PVE.form.CorosyncLinkEditorController', {
2 extend
: 'Ext.app.ViewController',
3 alias
: 'controller.pveCorosyncLinkEditorController',
5 addLinkIfEmpty: function() {
6 let view
= this.getView();
7 if (view
.items
|| view
.items
.length
=== 0) {
12 addEmptyLink: function() {
13 this.addLink(); // discard parameters to allow being called from 'handler'
16 addLink: function(link
) {
18 let view
= me
.getView();
19 let vm
= view
.getViewModel();
21 let linkCount
= vm
.get('linkCount');
22 if (linkCount
>= vm
.get('maxLinkCount')) {
28 if (link
.number
=== undefined) {
29 link
.number
= me
.getNextFreeNumber();
31 if (link
.value
=== undefined) {
32 link
.value
= me
.getNextFreeNetwork();
35 let linkSelector
= Ext
.create('PVE.form.CorosyncLinkSelector', {
36 maxLinkNumber
: vm
.get('maxLinkCount') - 1,
37 allowNumberEdit
: vm
.get('allowNumberEdit'),
38 allowBlankNetwork
: link
.allowBlank
,
39 initNumber
: link
.number
,
40 initNetwork
: link
.value
,
42 emptyText
: link
.emptyText
,
44 // needs to be set here, because we need to update the viewmodel
45 removeBtnHandler: function() {
46 let curLinkCount
= vm
.get('linkCount');
48 if (curLinkCount
<= 1) {
52 vm
.set('linkCount', curLinkCount
- 1);
54 // 'this' is the linkSelector here
57 me
.updateDeleteButtonState();
61 view
.add(linkSelector
);
64 vm
.set('linkCount', linkCount
);
66 me
.updateDeleteButtonState();
69 // ExtJS trips on binding this for some reason, so do it manually
70 updateDeleteButtonState: function() {
71 let view
= this.getView();
72 let vm
= view
.getViewModel();
74 let disabled
= vm
.get('linkCount') <= 1;
76 let deleteButtons
= view
.query('button[cls=removeLinkBtn]');
77 Ext
.Array
.each(deleteButtons
, btn
=> {
78 btn
.setDisabled(disabled
);
82 getNextFreeNetwork: function() {
83 let view
= this.getView();
84 let vm
= view
.getViewModel();
86 let networksInUse
= view
.query('proxmoxNetworkSelector').map(selector
=> selector
.value
);
88 for (const network
of vm
.get('networks')) {
89 if (!networksInUse
.includes(network
)) {
93 return undefined; // default to empty field, user has to set up link manually
96 getNextFreeNumber: function() {
97 let view
= this.getView();
98 let vm
= view
.getViewModel();
100 let numbersInUse
= view
.query('numberfield').map(field
=> field
.value
);
102 for (let i
= 0; i
< vm
.get('maxLinkCount'); i
++) {
103 if (!numbersInUse
.includes(i
)) {
107 // all numbers in use, this should never happen since add button is disabled automatically
112 Ext
.define('PVE.form.CorosyncLinkSelector', {
113 extend
: 'Ext.panel.Panel',
114 xtype
: 'pveCorosyncLinkSelector',
116 mixins
: ['Proxmox.Mixin.CBind'],
121 allowNumberEdit
: true,
122 allowBlankNetwork
: false,
123 removeBtnHandler
: undefined,
137 xtype
: 'displayfield',
140 hidden
: '{allowNumberEdit}',
141 value
: '{initNumber}',
148 xtype
: 'numberfield',
151 maxValue
: '{maxLinkNumber}',
152 hidden
: '{!allowNumberEdit}',
153 value
: '{initNumber}',
158 submitValue
: false, // see getSubmitValue of network selector
162 xtype
: 'proxmoxNetworkSelector',
164 allowBlank
: '{allowBlankNetwork}',
165 value
: '{initNetwork}',
166 emptyText
: '{emptyText}',
169 valueField
: 'address',
170 displayField
: 'address',
172 margin
: '0 5px 0 5px',
173 getSubmitValue: function() {
175 // link number is encoded into key, so we need to set field name before value retrieval
176 let linkNumber
= me
.prev('numberfield').getValue(); // always the correct one
177 me
.name
= 'link' + linkNumber
;
178 return me
.getValue();
183 iconCls
: 'fa fa-trash-o',
184 cls
: 'removeLinkBtn',
186 hidden
: '{!allowNumberEdit}',
188 handler: function() {
190 let parent
= me
.up('pveCorosyncLinkSelector');
191 if (parent
.removeBtnHandler
!== undefined) {
192 parent
.removeBtnHandler();
198 margin
: '-1px 0 0 5px',
201 cls
: 'x-form-item-label-default',
209 initComponent: function() {
214 let numSelect
= me
.down('numberfield');
215 let netSelect
= me
.down('proxmoxNetworkSelector');
217 numSelect
.validator
= me
.createNoDuplicatesValidator(
219 gettext("Duplicate link number not allowed."),
222 netSelect
.validator
= me
.createNoDuplicatesValidator(
223 'proxmoxNetworkSelector',
224 gettext("Duplicate link address not allowed."),
228 createNoDuplicatesValidator: function(queryString
, errorMsg
) { // linkSelector generator
229 let view
= this; // eslint-disable-line consistent-this
230 /** @this is the field itself, as the validator this is called from scopes it that way */
231 return function(val
) {
233 let form
= view
.up('form');
234 let linkEditor
= view
.up('pveCorosyncLinkEditor');
236 if (!form
.validating
) {
237 // avoid recursion/double validation by setting temporary states
238 me
.validating
= true;
239 form
.validating
= true;
241 // validate all other fields as well, to always mark both
242 // parties involved in a 'duplicate' error
245 form
.validating
= false;
246 me
.validating
= false;
247 } else if (me
.validating
) {
248 // we'll be validated by the original call in the other if-branch, avoid double work
252 if (val
=== undefined || (val
instanceof String
&& val
.length
=== 0)) {
253 return true; // let this be caught by allowBlank, if at all
256 let allFields
= linkEditor
.query(queryString
);
257 for (const field
of allFields
) {
258 if (field
!== me
&& String(field
.getValue()) === String(val
)) {
267 Ext
.define('PVE.form.CorosyncLinkEditor', {
268 extend
: 'Ext.panel.Panel',
269 xtype
: 'pveCorosyncLinkEditor',
271 controller
: 'pveCorosyncLinkEditorController',
273 // only initial config, use setter otherwise
274 allowNumberEdit
: true,
281 allowNumberEdit
: true,
285 addDisabled: function(get) {
286 return !get('allowNumberEdit') ||
287 get('linkCount') >= get('maxLinkCount');
289 dockHidden: function(get) {
290 return !(get('allowNumberEdit') || get('infoText'));
298 defaultButtonUI
: 'default',
302 hidden
: '{dockHidden}',
307 text
: gettext('Add'),
309 disabled
: '{addDisabled}',
310 hidden
: '{!allowNumberEdit}',
312 handler
: 'addEmptyLink',
323 setInfoText: function(text
) {
325 let vm
= me
.getViewModel();
327 vm
.set('infoText', text
|| '');
330 setLinks: function(links
) {
332 let controller
= me
.getController();
333 let vm
= me
.getViewModel();
336 vm
.set('linkCount', 0);
338 Ext
.Array
.each(links
, link
=> controller
.addLink(link
));
341 setDefaultLinks: function() {
343 let controller
= me
.getController();
344 let vm
= me
.getViewModel();
347 vm
.set('linkCount', 0);
348 controller
.addLink();
352 setAllowNumberEdit: function(allow
) {
354 let vm
= me
.getViewModel();
355 vm
.set('allowNumberEdit', allow
);
357 vm
.set('linkCount', 0);
361 // No links is never a valid scenario, but can occur during a slow load
362 xtype
: 'hiddenfield',
364 isValid: function() {
366 let vm
= me
.up('pveCorosyncLinkEditor').getViewModel();
367 return vm
.get('linkCount') > 0;
371 initComponent: function() {
373 let vm
= me
.getViewModel();
374 let controller
= me
.getController();
376 vm
.set('allowNumberEdit', me
.allowNumberEdit
);
377 vm
.set('infoText', me
.infoText
|| '');
381 // Request local node networks to pre-populate first link.
382 Proxmox
.Utils
.API2Request({
383 url
: '/nodes/localhost/network',
386 success
: response
=> {
387 let data
= response
.result
.data
;
388 if (data
.length
> 0) {
389 data
.sort((a
, b
) => a
.iface
.localeCompare(b
.iface
));
391 for (let net
of data
) {
393 addresses
.push(net
.address
);
396 addresses
.push(net
.address6
);
400 vm
.set('networks', addresses
);
403 // Always have at least one link, but account for delay in API,
404 // someone might have called 'setLinks' in the meantime -
405 // except if 'allowNumberEdit' is false, in which case we're
406 // probably waiting for the user to input the join info
407 if (vm
.get('allowNumberEdit')) {
408 controller
.addLinkIfEmpty();
412 if (vm
.get('allowNumberEdit')) {
413 controller
.addLinkIfEmpty();