--- /tmp/pvemanagerlib-8.4.14-stock.js 2026-05-19 17:46:16.553917259 -0400 +++ /tmp/pvemanagerlib-8.4.14-patched-v2.js 2026-05-19 21:35:03.162563535 -0400 @@ -9745,6 +9745,7 @@ alias: ['widget.pveiScsiProviderSelector'], comboItems: [ ['comstar', 'Comstar'], + ['freenas', 'FreeNAS/TrueNAS API'], ['istgt', 'istgt'], ['iet', 'IET'], ['LIO', 'LIO'], @@ -62673,10 +62674,17 @@ viewModel: { parent: null, data: { - isLIO: false, isComstar: true, + isFreeNAS: false, + isLIO: false, + isToken: false, hasWriteCacheOption: true, }, + formulas: { + hideUsername: function(get) { + return (!get('isFreeNAS') || !(get('isFreeNAS') && !get('isToken'))); + }, + }, }, controller: { @@ -62685,12 +62693,41 @@ 'field[name=iscsiprovider]': { change: 'changeISCSIProvider', }, + 'field[name=truenas_token_auth]': { + change: 'changeUsername', + }, }, changeISCSIProvider: function (f, newVal, oldVal) { + var me = this; var vm = this.getViewModel(); vm.set('isLIO', newVal === 'LIO'); vm.set('isComstar', newVal === 'comstar'); - vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'istgt'); + vm.set('isFreeNAS', newVal === 'freenas'); + vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'freenas' || newVal === 'istgt'); + if (newVal !== 'freenas') { + me.lookupReference('freenas_use_ssl_field').setValue(false); + me.lookupReference('truenas_token_auth_field').setValue(false); + me.lookupReference('freenas_apiv4_host_field').setValue(''); + me.lookupReference('freenas_user_field').setValue(''); + me.lookupReference('freenas_user_field').allowBlank = true; + me.lookupReference('truenas_secret_field').setValue(''); + me.lookupReference('truenas_secret_field').allowBlank = true; + me.lookupReference('truenas_confirm_secret_field').setValue(''); + me.lookupReference('truenas_confirm_secret_field').allowBlank = true; + } else { + me.lookupReference('freenas_user_field').allowBlank = false; + me.lookupReference('truenas_secret_field').allowBlank = false; + me.lookupReference('truenas_confirm_secret_field').allowBlank = false; + } + }, + changeUsername: function (f, newVal, oldVal) { + var me = this; + var vm = me.getViewModel(); + vm.set('isToken', newVal); + me.lookupReference('freenas_user_field').allowBlank = newVal; + if (newVal) { + me.lookupReference('freenas_user_field').setValue(''); + } }, }, @@ -62703,11 +62740,18 @@ values.nowritecache = values.writecache ? 0 : 1; delete values.writecache; + if (values.freenas_password) { + values.truenas_secret = values.freenas_password; + } return me.callParent([values]); }, setValues: function (values) { + if (values.freenas_password) { + values.truenas_secret = values.freenas_password; + } + values.truenas_confirm_secret = values.truenas_secret; values.writecache = values.nowritecache ? 0 : 1; this.callParent([values]); }, @@ -62715,6 +62759,47 @@ initComponent: function () { var me = this; + var tnsecret = Ext.create('Ext.form.TextField', { + xtype: 'proxmoxtextfield', + name: 'truenas_secret', + reference: 'truenas_secret_field', + inputType: me.isCreate ? '' : 'password', + value: '', + editable: true, + emptyText: Proxmox.Utils.noneText, + bind: { + hidden: '{!isFreeNAS}', + }, + fieldLabel: gettext('API Password'), + change: function (f, value) { + if (f.rendered) { + f.up().down('field[name=truenas_confirm_secret]').validate(); + } + }, + }); + + var tnconfirmsecret = Ext.create('Ext.form.TextField', { + xtype: 'proxmoxtextfield', + name: 'truenas_confirm_secret', + reference: 'truenas_confirm_secret_field', + inputType: me.isCreate ? '' : 'password', + value: '', + editable: true, + submitValue: false, + emptyText: Proxmox.Utils.noneText, + bind: { + hidden: '{!isFreeNAS}', + }, + fieldLabel: gettext('Confirm API Password'), + validator: function (value) { + var pw = me.up().down('field[name=truenas_secret]').getValue(); + if (pw !== value) { + return 'Secrets do not match!'; + } + return true; + }, + }); + me.column1 = [ { xtype: me.isCreate ? 'textfield' : 'displayfield', @@ -62749,9 +62834,60 @@ name: 'comstar_tg', value: '', fieldLabel: gettext('Target group'), - bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' }, + bind: { + hidden: '{!isComstar}', + }, allowBlank: true, }, + { + xtype: 'proxmoxcheckbox', + name: 'freenas_use_ssl', + reference: 'freenas_use_ssl_field', + inputId: 'freenas_use_ssl_field', + checked: false, + bind: { + hidden: '{!isFreeNAS}', + }, + uncheckedValue: 0, + fieldLabel: gettext('API use SSL'), + }, + { + xtype: 'proxmoxcheckbox', + name: 'truenas_token_auth', + reference: 'truenas_token_auth_field', + inputId: 'truenas_use_token_auth_field', + checked: false, + listeners: { + change: function (field, newValue) { + if (newValue === true) { + tnsecret.labelEl.update('API Token'); + tnconfirmsecret.labelEl.update('Confirm API Token'); + me.lookupReference('freenas_user_field').setValue(''); + me.lookupReference('freenas_user_field').allowBlank = true; + } else { + tnsecret.labelEl.update('API Password'); + tnconfirmsecret.labelEl.update('Confirm API Password'); + me.lookupReference('freenas_user_field').allowBlank = false; + } + }, + }, + bind: { + hidden: '{!isFreeNAS}', + }, + uncheckedValue: 0, + fieldLabel: gettext('API Token Auth'), + }, + { + xtype: 'textfield', + name: 'freenas_user', + reference: 'freenas_user_field', + inputId: 'freenas_user_field', + value: '', + fieldLabel: gettext('API Username'), + bind: { + hidden: '{hideUsername}', + }, + }, ]; me.column2 = [ @@ -62783,7 +62919,9 @@ xtype: me.isCreate ? 'textfield' : 'displayfield', name: 'comstar_hg', value: '', - bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' }, + bind: { + hidden: '{!isComstar}', + }, fieldLabel: gettext('Host group'), allowBlank: true, }, @@ -62791,10 +62929,26 @@ xtype: me.isCreate ? 'textfield' : 'displayfield', name: 'lio_tpg', value: '', - bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' }, - allowBlank: false, + bind: { + hidden: '{!isLIO}', + }, + allowBlank: true, fieldLabel: gettext('Target portal group'), }, + { + xtype: 'proxmoxtextfield', + name: 'freenas_apiv4_host', + reference: 'freenas_apiv4_host_field', + value: '', + editable: true, + emptyText: Proxmox.Utils.noneText, + bind: { + hidden: '{!isFreeNAS}', + }, + fieldLabel: gettext('API IPv4 Host'), + }, + tnsecret, + tnconfirmsecret, ]; me.callParent();