public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [PATCH manager 0/3] ui: prompt users for reload when web ui version changes
@ 2026-09-23 11:35 Dominik Csapak
  2026-09-23 11:35 ` [PATCH manager 1/3] api: factor out read_pwt_version and pwt_base_dir Dominik Csapak
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Dominik Csapak @ 2026-09-23 11:35 UTC (permalink / raw)
  To: pve-devel

On some updates (like recently with ceph), the UI has new or better
information about backend states, but the user must reload the page to
get the new version, which might not be obvious.

To help users detect such outdated running UI versions, send the current
one in the index and /cluster/resources api call for the node that
the browser is connected to. The ui can then compare these and prompt
the user to reload.

Dominik Csapak (3):
  api: factor out read_pwt_version and pwt_base_dir
  api: provide GUI versions via index and /cluster/resources
  ui: workspace: prompt user for reload when UI packages were updated

 PVE/API2/Cluster.pm       | 42 +++++++++++++++++++++++++
 PVE/API2Tools.pm          | 12 +++++++
 PVE/Service/pveproxy.pm   |  6 ++--
 www/index.html.tpl        |  6 +++-
 www/manager6/Workspace.js | 66 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 128 insertions(+), 4 deletions(-)

-- 
2.47.3





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

* [PATCH manager 1/3] api: factor out read_pwt_version and pwt_base_dir
  2026-09-23 11:35 [PATCH manager 0/3] ui: prompt users for reload when web ui version changes Dominik Csapak
@ 2026-09-23 11:35 ` Dominik Csapak
  2026-09-23 11:35 ` [PATCH manager 2/3] api: provide GUI versions via index and /cluster/resources Dominik Csapak
  2026-09-23 11:35 ` [PATCH manager 3/3] ui: workspace: prompt user for reload when UI packages were updated Dominik Csapak
  2 siblings, 0 replies; 4+ messages in thread
From: Dominik Csapak @ 2026-09-23 11:35 UTC (permalink / raw)
  To: pve-devel

Getting the pwt version will be useful in other places later, so factor
it out into API2Tools.

While at it, change it to use 'PVE::File' and handle missing pwt file by
providing the default '' (to avoid a perl warning in that case).

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 PVE/API2Tools.pm        | 12 ++++++++++++
 PVE/Service/pveproxy.pm |  6 +++---
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/PVE/API2Tools.pm b/PVE/API2Tools.pm
index bca21aa5..63d50fd5 100644
--- a/PVE/API2Tools.pm
+++ b/PVE/API2Tools.pm
@@ -11,6 +11,7 @@ use URI;
 
 use PVE::Cluster;
 use PVE::DataCenterConfig; # so we can cfs-read datacenter.cfg
+use PVE::File;
 use PVE::Exception qw(raise_param_exc);
 use PVE::INotify;
 use PVE::RPCEnvironment;
@@ -272,4 +273,15 @@ sub get_resource_pool_guest_members {
     return $pool_members;
 }
 
+sub pwt_base_dir {
+    return '/usr/share/javascript/proxmox-widget-toolkit';
+}
+
+sub read_pwt_version {
+    my $base_dir = pwt_base_dir();
+    my $wtversionraw = PVE::File::file_read_first_line("$base_dir/proxmoxlib.js") // '';
+    my $wtversion = $wtversionraw =~ m|^// (.*)$| ? $1 : '';
+    return $wtversion;
+}
+
 1;
diff --git a/PVE/Service/pveproxy.pm b/PVE/Service/pveproxy.pm
index dfdd014c..9ff0770b 100755
--- a/PVE/Service/pveproxy.pm
+++ b/PVE/Service/pveproxy.pm
@@ -11,6 +11,7 @@ use URI::QueryParam;
 use URI;
 
 use PVE::API2;
+use PVE::API2Tools;
 use PVE::APIServer::AnyEvent;
 use PVE::APIServer::Formatter::HTML;
 use PVE::APIServer::Formatter::Standard;
@@ -56,7 +57,7 @@ my $basedirs = {
     novnc => '/usr/share/novnc-pve',
     yew_mobile => '/usr/share/pve-yew-mobile-gui',
     i18n_yew => '/usr/share/pve-yew-mobile-i18n',
-    widgettoolkit => '/usr/share/javascript/proxmox-widget-toolkit',
+    widgettoolkit => PVE::API2Tools::pwt_base_dir(),
     xtermjs => '/usr/share/pve-xtermjs',
 };
 
@@ -254,8 +255,7 @@ sub get_index {
 
     my $version = PVE::pvecfg::version();
 
-    my $wtversionraw = PVE::Tools::file_read_firstline("$basedirs->{widgettoolkit}/proxmoxlib.js");
-    my $wtversion = $wtversionraw =~ m|^// (.*)$| ? $1 : '';
+    my $wtversion = PVE::API2Tools::read_pwt_version();
 
     # while we could use the actual pkg version (e.g., shipped as pkg-version file in each
     # respective package's /usr/share/<pkg> folder, this way it should also work when using make
-- 
2.47.3





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

* [PATCH manager 2/3] api: provide GUI versions via index and /cluster/resources
  2026-09-23 11:35 [PATCH manager 0/3] ui: prompt users for reload when web ui version changes Dominik Csapak
  2026-09-23 11:35 ` [PATCH manager 1/3] api: factor out read_pwt_version and pwt_base_dir Dominik Csapak
@ 2026-09-23 11:35 ` Dominik Csapak
  2026-09-23 11:35 ` [PATCH manager 3/3] ui: workspace: prompt user for reload when UI packages were updated Dominik Csapak
  2 siblings, 0 replies; 4+ messages in thread
From: Dominik Csapak @ 2026-09-23 11:35 UTC (permalink / raw)
  To: pve-devel

Index has these versions anyway, just expose them to the UI via the
usual `Proxmox` object.

In the /cluster/resources API call, we add that information to the node
that is handling the request (which is normally the same where the index
was loaded from).

Cache the pwt versions locally for 60 seconds, so we don't hit the file
read on every call.

With this information, the UI can detect an outdated UI version still
running.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 PVE/API2/Cluster.pm | 42 ++++++++++++++++++++++++++++++++++++++++++
 www/index.html.tpl  |  6 +++++-
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/PVE/API2/Cluster.pm b/PVE/API2/Cluster.pm
index 4e5efbfd..f66e0a6a 100644
--- a/PVE/API2/Cluster.pm
+++ b/PVE/API2/Cluster.pm
@@ -20,6 +20,7 @@ use PVE::RPCEnvironment;
 use PVE::SafeSyslog;
 use PVE::Storage;
 use PVE::Tools qw(extract_param);
+use PVE::pvecfg;
 
 use PVE::API2::ACMEAccount;
 use PVE::API2::ACMEPlugin;
@@ -259,6 +260,9 @@ my sub can_access_network {
     return 0;
 }
 
+# widget toolkit version, re-read at most once per minute to avoid reading the file on every call
+my $pwt_version_cache = {};
+
 __PACKAGE__->register_method({
     name => 'resources',
     path => 'resources',
@@ -503,6 +507,25 @@ __PACKAGE__->register_method({
                     default => 'x86_64',
                     optional => 1,
                 },
+                'versions' => {
+                    description => "Optional package versions (for type 'node').",
+                    type => 'object',
+                    optional => 1,
+                    properties => {
+                        'pve-manager' => {
+                            type => "string",
+                            optional => 1,
+                            description =>
+                                "The pve-manager version of this node. Only included for the node handling the request.",
+                        },
+                        'proxmox-widget-toolkit' => {
+                            type => "string",
+                            optional => 1,
+                            description =>
+                                "The proxmox-widget-toolkit version of this node. Only included for the node handling the request.",
+                        },
+                    },
+                },
             },
         },
     },
@@ -618,6 +641,8 @@ __PACKAGE__->register_method({
         my $static_node_info = PVE::Cluster::get_node_kv("static-info");
 
         if (!$param->{type} || $param->{type} eq 'node') {
+            my $nodename = PVE::INotify::nodename();
+
             foreach my $node (@$nodelist) {
                 my $can_audit = $rpcenv->check($authuser, "/nodes/$node", ['Sys.Audit'], 1);
                 my $entry =
@@ -634,6 +659,23 @@ __PACKAGE__->register_method({
                     $entry->{'hastate'} = $status;
                 }
 
+                if ($node eq $nodename) {
+                    my $now = time();
+                    if (
+                        !defined($pwt_version_cache->{version})
+                        || $pwt_version_cache->{time} + 60 < $now
+                    ) {
+                        $pwt_version_cache->{version} = PVE::API2Tools::read_pwt_version();
+                        $pwt_version_cache->{time} = $now;
+                    }
+                    my $pwt_version = $pwt_version_cache->{version};
+
+                    $entry->{versions} = { 'pve-manager' => PVE::pvecfg::version() };
+                    # an empty version means reading failed, omit it to avoid false positives
+                    $entry->{versions}->{'proxmox-widget-toolkit'} = $pwt_version
+                        if $pwt_version ne '';
+                }
+
                 push @$res, $entry;
             }
         }
diff --git a/www/index.html.tpl b/www/index.html.tpl
index c18e6411..8484710a 100644
--- a/www/index.html.tpl
+++ b/www/index.html.tpl
@@ -48,7 +48,11 @@
         NodeArch: '[% arch %]',
         UserName: '[% username %]',
         CSRFPreventionToken: '[% token %]',
-        ConsentText: '[% consenttext %]'
+        ConsentText: '[% consenttext %]',
+        GUIVersions: {
+            'pve-manager': '[% version %]',
+            'proxmox-widget-toolkit': '[% wtversion %]',
+        },
     };
     </script>
     <script type="text/javascript" src="/proxmoxlib.js?ver=[% wtversion %]"></script>
-- 
2.47.3





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

* [PATCH manager 3/3] ui: workspace: prompt user for reload when UI packages were updated
  2026-09-23 11:35 [PATCH manager 0/3] ui: prompt users for reload when web ui version changes Dominik Csapak
  2026-09-23 11:35 ` [PATCH manager 1/3] api: factor out read_pwt_version and pwt_base_dir Dominik Csapak
  2026-09-23 11:35 ` [PATCH manager 2/3] api: provide GUI versions via index and /cluster/resources Dominik Csapak
@ 2026-09-23 11:35 ` Dominik Csapak
  2 siblings, 0 replies; 4+ messages in thread
From: Dominik Csapak @ 2026-09-23 11:35 UTC (permalink / raw)
  To: pve-devel

When the UI packages (pve-manager, proxmox-widget-toolkit) are updated,
an already running Web UI instance still uses the potentially older
versions.

Detect that by comparing the version from the site load to the ones
reported from /cluster/resources (which is polled regularly) and prompt
the user to reload the UI.

The message box offers a 'Later' option so that ongoing work can be
finished before reloading. In that case the notice is shown in the top
bar until the user reloads.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 www/manager6/Workspace.js | 66 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/www/manager6/Workspace.js b/www/manager6/Workspace.js
index 189d3373..392d9783 100644
--- a/www/manager6/Workspace.js
+++ b/www/manager6/Workspace.js
@@ -193,6 +193,55 @@ Ext.define('PVE.StdWorkspace', {
         }
     },
 
+    // compare the versions the backend reports with the ones this page was loaded with
+    checkGUIVersions: function () {
+        let me = this;
+
+        if (me.guiUpdateDetected) {
+            return;
+        }
+
+        let node = PVE.data.ResourceStore.getNodeById(Proxmox.NodeName);
+        let versions = node?.data?.versions;
+        if (!versions) {
+            return; // e.g., older backend
+        }
+
+        let changed = Object.entries(Proxmox.GUIVersions ?? {}).some(
+            ([pkg, loaded]) => versions[pkg] !== undefined && versions[pkg] !== loaded,
+        );
+        if (!changed) {
+            return;
+        }
+
+        me.guiUpdateDetected = true;
+        let msgBox = Ext.create('Ext.window.MessageBox', {
+            closeAction: 'destroy',
+        });
+        msgBox.show({
+            title: gettext('New Version Available'),
+            message: gettext(
+                'A new version of the web interface is available. Reload the page to use it.',
+            ),
+            icon: Ext.Msg.INFO,
+            closable: false,
+            buttons: Ext.Msg.YESNO,
+            buttonText: {
+                yes: gettext('Reload UI'),
+                no: gettext('Later'),
+            },
+            fn: function (btn) {
+                if (btn === 'yes') {
+                    window.location.reload();
+                } else if (btn === 'no') {
+                    me.down('#uiUpdateHint').setVisible(true);
+                    me.down('#uiUpdateBtn').setVisible(true);
+                    msgBox.close();
+                }
+            },
+        });
+    },
+
     updateUserInfo: function () {
         let me = this;
         let ui = me.query('#userinfo')[0];
@@ -352,6 +401,21 @@ Ext.define('PVE.StdWorkspace', {
                                 'line-height': '20px',
                             },
                         },
+                        {
+                            itemId: 'uiUpdateHint',
+                            html: gettext('A new version of the web interface is available.'),
+                            hidden: true,
+                        },
+                        {
+                            xtype: 'button',
+                            itemId: 'uiUpdateBtn',
+                            baseCls: 'x-btn',
+                            iconCls: 'fa fa-refresh',
+                            text: gettext('Reload UI'),
+                            margin: '0 5',
+                            hidden: true,
+                            handler: () => window.location.reload(),
+                        },
                         {
                             flex: 2,
                         },
@@ -546,6 +610,8 @@ Ext.define('PVE.StdWorkspace', {
 
         me.updateUserInfo();
 
+        me.mon(PVE.data.ResourceStore, 'load', me.checkGUIVersions, me);
+
         // on resize, center all modal windows
         Ext.on('resize', function () {
             let modalWindows = Ext.ComponentQuery.query('window[modal]');
-- 
2.47.3





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

end of thread, other threads:[~2026-09-23 11:38 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-23 11:35 [PATCH manager 0/3] ui: prompt users for reload when web ui version changes Dominik Csapak
2026-09-23 11:35 ` [PATCH manager 1/3] api: factor out read_pwt_version and pwt_base_dir Dominik Csapak
2026-09-23 11:35 ` [PATCH manager 2/3] api: provide GUI versions via index and /cluster/resources Dominik Csapak
2026-09-23 11:35 ` [PATCH manager 3/3] ui: workspace: prompt user for reload when UI packages were updated Dominik Csapak

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal