From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 8C52E956C3 for ; Wed, 18 Jan 2023 14:13:41 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id D07B520307 for ; Wed, 18 Jan 2023 14:13:10 +0100 (CET) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Wed, 18 Jan 2023 14:13:08 +0100 (CET) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 0D444450E7 for ; Wed, 18 Jan 2023 14:13:06 +0100 (CET) From: Dominik Csapak To: pve-devel@lists.proxmox.com Date: Wed, 18 Jan 2023 14:12:59 +0100 Message-Id: <20230118131303.2892050-5-d.csapak@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230118131303.2892050-1-d.csapak@proxmox.com> References: <20230118131303.2892050-1-d.csapak@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.065 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH manager 2/6] ui: storage: move node scan selector inside combobox X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 18 Jan 2023 13:13:41 -0000 by converting the relevant selection boxes to combogrids. This is done to reduce confusion for how/why to select a node, and doing it this way it is moved closer to the selection of the actual value we want. It still restricts the nodes when selecting a specific one. Show it only when there is more than one node according to PVE.data.ResourceStore Suggested-by: Thomas Lamprecht Signed-off-by: Dominik Csapak --- www/manager6/form/ComboBoxSetStoreNode.js | 45 +++++++++++++- www/manager6/storage/IScsiEdit.js | 53 +++++++++-------- www/manager6/storage/LVMEdit.js | 71 +++++++++++++++++------ www/manager6/storage/LvmThinEdit.js | 71 +++++++++++++---------- www/manager6/storage/ZFSPoolEdit.js | 29 +++++---- 5 files changed, 180 insertions(+), 89 deletions(-) diff --git a/www/manager6/form/ComboBoxSetStoreNode.js b/www/manager6/form/ComboBoxSetStoreNode.js index 3490ddd7d..a654636b7 100644 --- a/www/manager6/form/ComboBoxSetStoreNode.js +++ b/www/manager6/form/ComboBoxSetStoreNode.js @@ -1,16 +1,57 @@ Ext.define('PVE.form.ComboBoxSetStoreNode', { - extend: 'Ext.form.field.ComboBox', + extend: 'Proxmox.form.ComboGrid', config: { apiBaseUrl: '/api2/json/nodes/', apiSuffix: '', }, + showNodeSelector: false, + setNodeName: function(value) { let me = this; value ||= Proxmox.NodeName; me.getStore().getProxy().setUrl(`${me.apiBaseUrl}${value}${me.apiSuffix}`); - this.clearValue(); + me.clearValue(); + }, + + nodeChange: function(_field, value) { + let me = this; + // disable autoSelect if there is already a selection or we have the picker open + if (me.getValue() || me.isExpanded) { + let autoSelect = me.autoSelect; + me.autoSelect = false; + me.store.on('afterload', function() { + me.autoSelect = autoSelect; + }, { single: true }); + } + me.setNodeName(value); + me.fireEvent('nodechanged', value); }, + initComponent: function() { + let me = this; + + if (me.showNodeSelector && PVE.data.ResourceStore.getNodes().length > 1) { + me.errorHeight = 140; + Ext.apply(me.listConfig ?? {}, { + tbar: { + xtype: 'toolbar', + items: [ + { + xtype: "pveStorageScanNodeSelector", + autoSelect: false, + fieldLabel: gettext('Node to scan'), + listeners: { + change: (field, value) => me.nodeChange(field, value), + }, + }, + ], + }, + emptyText: me.listConfig?.emptyText ?? gettext('Nothing found'), + }); + } + + me.callParent(); + }, }); diff --git a/www/manager6/storage/IScsiEdit.js b/www/manager6/storage/IScsiEdit.js index 96c1aa28b..6a1e4aeb5 100644 --- a/www/manager6/storage/IScsiEdit.js +++ b/www/manager6/storage/IScsiEdit.js @@ -6,32 +6,43 @@ Ext.define('PVE.storage.IScsiScan', { valueField: 'target', displayField: 'target', matchFieldWidth: false, + allowBlank: false, + listConfig: { - loadingText: gettext('Scanning...'), width: 350, + columns: [ + { + dataIndex: 'target', + flex: 1, + }, + ], + emptyText: gettext('No iSCSI target found'), }, + config: { apiSuffix: '/scan/iscsi', }, - doRawQuery: function() { - // do nothing - }, - onTriggerClick: function() { - let me = this; + showNodeSelector: true, - if (!me.queryCaching || me.lastQuery !== me.portal) { - me.store.removeAll(); + reload: function() { + let me = this; + if (!me.isDisabled()) { + me.getStore().load(); } - - me.allQuery = me.portal; - - me.callParent(); }, setPortal: function(portal) { let me = this; me.portal = portal; + me.getStore().getProxy().setExtraParams({ portal }); + me.reload(); + }, + + setNodeName: function(value) { + let me = this; + me.callParent([value]); + me.reload(); }, initComponent: function() { @@ -81,19 +92,6 @@ Ext.define('PVE.storage.IScsiInputPanel', { let me = this; me.column1 = [ - { - xtype: 'pveStorageScanNodeSelector', - disabled: !me.isCreate, - hidden: !me.isCreate, - listeners: { - change: { - fn: function(field, value) { - me.lookup('iScsiTargetScan').setNodeName(value); - me.lookup('storageNodeRestriction').setValue(value); - }, - }, - }, - }, { xtype: me.isCreate ? 'textfield' : 'displayfield', name: 'portal', @@ -117,6 +115,11 @@ Ext.define('PVE.storage.IScsiInputPanel', { fieldLabel: gettext('Target'), allowBlank: false, reference: 'iScsiTargetScan', + listeners: { + nodechanged: function(value) { + me.lookup('storageNodeRestriction').setValue(value); + }, + }, }), ]; diff --git a/www/manager6/storage/LVMEdit.js b/www/manager6/storage/LVMEdit.js index b323a529d..84ee198da 100644 --- a/www/manager6/storage/LVMEdit.js +++ b/www/manager6/storage/LVMEdit.js @@ -5,10 +5,23 @@ Ext.define('PVE.storage.VgSelector', { displayField: 'vg', queryMode: 'local', editable: false, + + listConfig: { + columns: [ + { + dataIndex: 'vg', + flex: 1, + }, + ], + emptyText: gettext('No volume groups found'), + }, + config: { apiSuffix: '/scan/lvm', }, + showNodeSelector: true, + setNodeName: function(value) { let me = this; me.callParent([value]); @@ -35,9 +48,6 @@ Ext.define('PVE.storage.VgSelector', { Ext.apply(me, { store: store, - listConfig: { - loadingText: gettext('Scanning...'), - }, }); me.callParent(); @@ -93,6 +103,42 @@ Ext.define('PVE.storage.BaseStorageSelector', { }, }); +Ext.define('PVE.storage.LunSelector', { + extend: 'PVE.form.FileSelector', + alias: 'widget.pveStorageLunSelector', + + nodename: 'localhost', + storageContent: 'images', + allowBlank: false, + + initComponent: function() { + let me = this; + + if (PVE.data.ResourceStore.getNodes().length > 1) { + me.errorHeight = 140; + Ext.apply(me.listConfig ?? {}, { + tbar: { + xtype: 'toolbar', + items: [ + { + xtype: "pveStorageScanNodeSelector", + autoSelect: false, + fieldLabel: gettext('Node to scan'), + listeners: { + change: (_field, value) => me.setNodename(value), + }, + }, + ], + }, + emptyText: me.listConfig?.emptyText ?? gettext('Nothing found'), + }); + } + + me.callParent(); + }, + +}); + Ext.define('PVE.storage.LVMInputPanel', { extend: 'PVE.panel.StorageBase', @@ -118,27 +164,16 @@ Ext.define('PVE.storage.LVMInputPanel', { fieldLabel: gettext('Volume group'), reference: 'volumeGroupSelector', allowBlank: false, - }); - me.column1.push({ - xtype: 'pveStorageScanNodeSelector', - listeners: { - change: { - fn: function(field, value) { - me.lookup('volumeGroupSelector').setNodeName(value); - me.lookup('storageNodeRestriction').setValue(value); - }, - }, - }, + listeners: { + nodechanged: (value) => me.lookup('storageNodeRestriction').setValue(value), + } }); - let baseField = Ext.createWidget('pveFileSelector', { + let baseField = Ext.createWidget('pveStorageLunSelector', { name: 'base', hidden: true, disabled: true, - nodename: 'localhost', - storageContent: 'images', fieldLabel: gettext('Base volume'), - allowBlank: false, }); me.column1.push({ diff --git a/www/manager6/storage/LvmThinEdit.js b/www/manager6/storage/LvmThinEdit.js index 92e6c2962..0c288bb04 100644 --- a/www/manager6/storage/LvmThinEdit.js +++ b/www/manager6/storage/LvmThinEdit.js @@ -6,31 +6,40 @@ Ext.define('PVE.storage.TPoolSelector', { valueField: 'lv', displayField: 'lv', editable: false, + allowBlank: false, + + listConfig: { + emptyText: gettext("No thinpool found"), + columns: [ + { + dataIndex: 'lv', + flex: 1, + }, + ], + }, config: { apiSuffix: '/scan/lvmthin', }, - doRawQuery: function() { - // nothing - }, - - onTriggerClick: function() { + reload: function() { let me = this; - - if (!me.queryCaching || me.lastQuery !== me.vg) { - me.store.removeAll(); + if (!me.isDisabled()) { + me.getStore().load(); } - - me.allQuery = me.vg; - - me.callParent(); }, setVG: function(myvg) { let me = this; - me.vg = myvg; + me.getStore().getProxy().setExtraParams({ vg: myvg }); + me.reload(); + }, + + setNodeName: function(value) { + let me = this; + me.callParent([value]); + me.reload(); }, initComponent: function() { @@ -52,9 +61,6 @@ Ext.define('PVE.storage.TPoolSelector', { Ext.apply(me, { store: store, - listConfig: { - loadingText: gettext('Scanning...'), - }, }); me.callParent(); @@ -69,6 +75,19 @@ Ext.define('PVE.storage.BaseVGSelector', { displayField: 'vg', queryMode: 'local', editable: false, + allowBlank: false, + + listConfig: { + columns: [ + { + dataIndex: 'vg', + flex: 1, + }, + ], + }, + + showNodeSelector: true, + config: { apiSuffix: '/scan/lvm', }, @@ -97,9 +116,6 @@ Ext.define('PVE.storage.BaseVGSelector', { Ext.apply(me, { store: store, - listConfig: { - loadingText: gettext('Scanning...'), - }, }); me.callParent(); @@ -135,24 +151,15 @@ Ext.define('PVE.storage.LvmThinInputPanel', { }); if (me.isCreate) { - me.column1.push({ - xtype: 'pveStorageScanNodeSelector', - listeners: { - change: { - fn: function(field, value) { - me.lookup('thinPoolSelector').setNodeName(value); - me.lookup('volumeGroupSelector').setNodeName(value); - me.lookup('storageNodeRestriction').setValue(value); - }, - }, - }, - }); - me.column1.push(Ext.create('PVE.storage.BaseVGSelector', { name: 'vgname', fieldLabel: gettext('Volume group'), reference: 'volumeGroupSelector', listeners: { + nodechanged: function(value) { + me.lookup('thinPoolSelector').setNodeName(value); + me.lookup('storageNodeRestriction').setValue(value); + }, change: function(f, value) { if (me.isCreate) { let vgField = me.lookup('thinPoolSelector'); diff --git a/www/manager6/storage/ZFSPoolEdit.js b/www/manager6/storage/ZFSPoolEdit.js index 65e152beb..df12fbbc8 100644 --- a/www/manager6/storage/ZFSPoolEdit.js +++ b/www/manager6/storage/ZFSPoolEdit.js @@ -5,13 +5,24 @@ Ext.define('PVE.storage.ZFSPoolSelector', { displayField: 'pool', queryMode: 'local', editable: false, + allowBlank: false, + listConfig: { - loadingText: gettext('Scanning...'), + columns: [ + { + dataIndex: 'pool', + flex: 1, + }, + ], + emptyText: gettext('No ZFS Pools found'), }, + config: { apiSuffix: '/scan/zfs', }, + showNodeSelector: true, + setNodeName: function(value) { let me = this; me.callParent([value]); @@ -54,22 +65,16 @@ Ext.define('PVE.storage.ZFSPoolInputPanel', { me.column1 = []; if (me.isCreate) { - me.column1.push({ - xtype: 'pveStorageScanNodeSelector', - listeners: { - change: { - fn: function(field, value) { - me.lookup('zfsPoolSelector').setNodeName(value); - me.lookup('storageNodeRestriction').setValue(value); - }, - }, - }, - }); me.column1.push(Ext.create('PVE.storage.ZFSPoolSelector', { name: 'pool', fieldLabel: gettext('ZFS Pool'), reference: 'zfsPoolSelector', allowBlank: false, + listeners: { + nodechanged: function(value) { + me.lookup('storageNodeRestriction').setValue(value); + }, + }, })); } else { me.column1.push(Ext.createWidget('displayfield', { -- 2.30.2