[pve-devel] [PATCH manager 2/6] ui: storage: move node scan selector inside combobox

Dominik Csapak d.csapak at proxmox.com
Wed Jan 18 14:12:59 CET 2023


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 <t.lamprecht at proxmox.com>
Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 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






More information about the pve-devel mailing list