all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [RFC PATCH pve-manager 0/2] add reload/upload buttons to iso selector
@ 2026-07-13 11:36 Dominik Csapak
  2026-07-13 11:36 ` [RFC PATCH pve-manager 1/2] ui: iso selector: add 'reload' button Dominik Csapak
  2026-07-13 11:37 ` [RFC PATCH pve-manager 2/2] ui: iso selector: add 'upload' button in the create VM wizard Dominik Csapak
  0 siblings, 2 replies; 3+ messages in thread
From: Dominik Csapak @ 2026-07-13 11:36 UTC (permalink / raw)
  To: pve-devel

It often happens that one forgot to upload an iso before starting the vm
wizard. instead of having to navigate to the storage and upload there,
add an inline upload button to the create wizard.

Using this space, we can add a general 'reload' button which reloads the
storage list as well as the file list for the selected storage.

Sending this as RFC for multiple reasons:
* This shows a modal window over another (upload over wizard), which is
  a pattern we don't usually use. IMO it's fine here since it's a rather
  minor use case, but still.
* Placement of the buttons: I tried with inline buttons as well as
  'triggers', but both have serious disadvantages:
  - inline buttons: don't count to the field width and it's hard with
    extjs' layout to achieve a consistent size for storage and file
    selector
  - triggers: we'd have to handroll the svg/png images (like pmx-clear),
    and i'm not very good with svgs in general. I tried to extract the
    font-awesome icons into standalone svgs, but could not get a result
    that was good enough (for me). Maybe someone else has more luck with
    that? Aside from the icons this has another problem: it makes the
    file selector content very narrow when there are multiple triggers
    and the user might not see what is actually selected.

Dominik Csapak (2):
  ui: iso selector: add 'reload' button
  ui: iso selector: add 'upload' button in the create VM wizard

 www/manager6/form/FileSelector.js    | 12 +++++
 www/manager6/form/IsoSelector.js     | 75 ++++++++++++++++++++++++++++
 www/manager6/form/StorageSelector.js | 11 +++-
 www/manager6/qemu/CDEdit.js          |  1 +
 www/manager6/qemu/OSPanel.js         |  1 +
 5 files changed, 98 insertions(+), 2 deletions(-)

-- 
2.47.3





^ permalink raw reply	[flat|nested] 3+ messages in thread

* [RFC PATCH pve-manager 1/2] ui: iso selector: add 'reload' button
  2026-07-13 11:36 [RFC PATCH pve-manager 0/2] add reload/upload buttons to iso selector Dominik Csapak
@ 2026-07-13 11:36 ` Dominik Csapak
  2026-07-13 11:37 ` [RFC PATCH pve-manager 2/2] ui: iso selector: add 'upload' button in the create VM wizard Dominik Csapak
  1 sibling, 0 replies; 3+ messages in thread
From: Dominik Csapak @ 2026-07-13 11:36 UTC (permalink / raw)
  To: pve-devel

so a user can manually reload the storage list as well as the file list.
This sometimes comes up when e.g. creating a new guest and a user
uploads a new ISO in a different tab.

The new button is added in a new row beneath the file selector and shows
the loading progress until the storage as well as the file selector are
done loading.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 www/manager6/form/FileSelector.js    | 12 ++++++++++++
 www/manager6/form/IsoSelector.js     | 27 +++++++++++++++++++++++++++
 www/manager6/form/StorageSelector.js | 11 +++++++++--
 3 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/www/manager6/form/FileSelector.js b/www/manager6/form/FileSelector.js
index b8f6a8c2..af4e4be8 100644
--- a/www/manager6/form/FileSelector.js
+++ b/www/manager6/form/FileSelector.js
@@ -15,6 +15,18 @@ Ext.define('PVE.form.FileSelector', {
         },
     },
 
+    reload: function (finishCb) {
+        let me = this;
+        finishCb ??= Ext.emptyFn;
+        if (!me.storage || !me.nodename || me.isDisabled()) {
+            finishCb();
+            return;
+        }
+        me.store.load(() => {
+            finishCb();
+        });
+    },
+
     setStorage: function (storage, nodename) {
         var me = this;
 
diff --git a/www/manager6/form/IsoSelector.js b/www/manager6/form/IsoSelector.js
index b2d94ed3..48c10427 100644
--- a/www/manager6/form/IsoSelector.js
+++ b/www/manager6/form/IsoSelector.js
@@ -110,5 +110,32 @@ Ext.define('PVE.form.IsoSelector', {
                 },
             },
         },
+        {
+            xtype: 'container',
+            layout: 'hbox',
+            items: [
+                { xtype: 'box', flex: 1 }, // just a spacer
+                {
+                    xtype: 'button',
+                    reference: 'reloadBtn',
+                    iconCls: 'fa fa-refresh',
+                    text: gettext('Reload'),
+                    handler: function () {
+                        let me = this;
+                        me.setDisabled(true);
+                        me.setIconCls('fa fa-refresh fa-spin');
+                        let selector = me.up('pveIsoSelector');
+                        let storage = selector.lookup('storage');
+                        let fileSelector = selector.lookup('file');
+                        storage.reloadStorageList(() => {
+                            fileSelector.reload(() => {
+                                me.setDisabled(false);
+                                me.setIconCls('fa fa-refresh');
+                            });
+                        });
+                    },
+                },
+            ],
+        },
     ],
 });
diff --git a/www/manager6/form/StorageSelector.js b/www/manager6/form/StorageSelector.js
index 0b5e10da..42961f72 100644
--- a/www/manager6/form/StorageSelector.js
+++ b/www/manager6/form/StorageSelector.js
@@ -68,9 +68,11 @@ Ext.define(
             ],
         },
 
-        reloadStorageList: function () {
+        reloadStorageList: function (finishCb) {
             let me = this;
 
+            finishCb ??= Ext.emptyFn;
+
             if (me.clusterView) {
                 me.getStore().setProxy({
                     type: 'proxmox',
@@ -97,6 +99,7 @@ Ext.define(
                 me.getStore().setFilters(filters);
             } else {
                 if (!me.nodename) {
+                    finishCb();
                     return;
                 }
 
@@ -117,7 +120,11 @@ Ext.define(
                 });
             }
 
-            me.store.load(() => me.validate());
+            me.store.load(() => {
+                let result = me.validate();
+                finishCb();
+                return result;
+            });
         },
 
         setTargetNode: function (targetNode) {
-- 
2.47.3





^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [RFC PATCH pve-manager 2/2] ui: iso selector: add 'upload' button in the create VM wizard
  2026-07-13 11:36 [RFC PATCH pve-manager 0/2] add reload/upload buttons to iso selector Dominik Csapak
  2026-07-13 11:36 ` [RFC PATCH pve-manager 1/2] ui: iso selector: add 'reload' button Dominik Csapak
@ 2026-07-13 11:37 ` Dominik Csapak
  1 sibling, 0 replies; 3+ messages in thread
From: Dominik Csapak @ 2026-07-13 11:37 UTC (permalink / raw)
  To: pve-devel

When first opening the VM create wizard on a new install, it often
happens that no ISO is uploaded yet. Currently this either requires a
second tab to upload it (or doing it manually via the cli) or closing
the wizard, uploading the ISO to the correct storage and then
re-starting the wizard.

Instead, having a direct upload button here, simplifies this by enabling
users to directly upload an iso to the selected storage (if permissions
allow) and automatically select it.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 www/manager6/form/IsoSelector.js | 48 ++++++++++++++++++++++++++++++++
 www/manager6/qemu/CDEdit.js      |  1 +
 www/manager6/qemu/OSPanel.js     |  1 +
 3 files changed, 50 insertions(+)

diff --git a/www/manager6/form/IsoSelector.js b/www/manager6/form/IsoSelector.js
index 48c10427..f42cd4ba 100644
--- a/www/manager6/form/IsoSelector.js
+++ b/www/manager6/form/IsoSelector.js
@@ -8,6 +8,10 @@ Ext.define('PVE.form.IsoSelector', {
         align: 'stretch',
     },
 
+    // enable an upload button for the currently selected storage, requires the
+    // user to have the Datastore.AllocateTemplate privilege
+    allowUpload: false,
+
     nodename: undefined,
     insideWizard: false,
     labelWidth: undefined,
@@ -15,7 +19,14 @@ Ext.define('PVE.form.IsoSelector', {
 
     cbindData: function () {
         let me = this;
+
+        let caps = Ext.state.Manager.get('GuiCap');
+        if (!caps.storage['Datastore.AllocateTemplate']) {
+            me.allowUpload = false;
+        }
+
         return {
+            hideUploadButton: !me.allowUpload,
             nodename: me.nodename,
             insideWizard: me.insideWizard,
         };
@@ -54,6 +65,7 @@ Ext.define('PVE.form.IsoSelector', {
         let me = this;
         me.lookup('storage').setNodename(nodename);
         me.lookup('file').setStorage(undefined, nodename);
+        me.nodename = nodename;
     },
 
     setDisabled: function (disabled) {
@@ -87,6 +99,7 @@ Ext.define('PVE.form.IsoSelector', {
                     let selector = me.up('pveIsoSelector');
                     selector.lookup('file').setStorage(value);
                     selector.checkChange();
+                    selector.lookup('uploadBtn').setDisabled(!value);
                 },
             },
         },
@@ -115,6 +128,41 @@ Ext.define('PVE.form.IsoSelector', {
             layout: 'hbox',
             items: [
                 { xtype: 'box', flex: 1 }, // just a spacer
+                {
+                    xtype: 'button',
+                    reference: 'uploadBtn',
+                    iconCls: 'fa fa-upload',
+                    text: gettext('Upload'),
+                    disabled: true,
+                    cbind: {
+                        hidden: '{hideUploadButton}',
+                    },
+                    handler: function () {
+                        let me = this;
+                        let selector = me.up('pveIsoSelector');
+                        let storage = selector.lookup('storage').getValue();
+                        let nodename = selector.nodename;
+                        if (!storage) {
+                            return;
+                        }
+                        let fileSelector = selector.lookup('file');
+                        let win = Ext.create('PVE.window.UploadToStorage', {
+                            nodename,
+                            storage,
+                            content: 'iso',
+                            autoShow: true,
+                            taskDone: (success) => {
+                                if (!success) {
+                                    return;
+                                }
+                                fileSelector.reload(() => {
+                                    let filename = win.getViewModel().get('filename');
+                                    fileSelector.setValue(`${storage}:iso/${filename}`);
+                                });
+                            },
+                        });
+                    },
+                },
                 {
                     xtype: 'button',
                     reference: 'reloadBtn',
diff --git a/www/manager6/qemu/CDEdit.js b/www/manager6/qemu/CDEdit.js
index c185de53..c8e87d97 100644
--- a/www/manager6/qemu/CDEdit.js
+++ b/www/manager6/qemu/CDEdit.js
@@ -100,6 +100,7 @@ Ext.define('PVE.qemu.CDInputPanel', {
         me.isosel = Ext.create('PVE.form.IsoSelector', {
             nodename: me.nodename,
             insideWizard: me.insideWizard,
+            allowUpload: me.insideWizard,
             name: 'cdimage',
         });
 
diff --git a/www/manager6/qemu/OSPanel.js b/www/manager6/qemu/OSPanel.js
index 556ad4c3..81508b64 100644
--- a/www/manager6/qemu/OSPanel.js
+++ b/www/manager6/qemu/OSPanel.js
@@ -160,6 +160,7 @@ Ext.define('PVE.qemu.OSPanel', {
                             xtype: 'pveIsoSelector',
                             reference: 'isoSelector',
                             name: 'ide0',
+                            allowUpload: true,
                             insideWizard: true,
                             hidden: true,
                             disabled: true,
-- 
2.47.3





^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-07-13 11:42 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-13 11:36 [RFC PATCH pve-manager 0/2] add reload/upload buttons to iso selector Dominik Csapak
2026-07-13 11:36 ` [RFC PATCH pve-manager 1/2] ui: iso selector: add 'reload' button Dominik Csapak
2026-07-13 11:37 ` [RFC PATCH pve-manager 2/2] ui: iso selector: add 'upload' button in the create VM wizard Dominik Csapak

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal