public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Jakob Klocker <j.klocker@proxmox.com>
To: pve-devel@lists.proxmox.com
Cc: Jakob Klocker <j.klocker@proxmox.com>
Subject: [PATCH pve-manager 7/9] www: storage: show plugin state/external/url in StatusView
Date: Fri, 31 Jul 2026 17:36:15 +0200	[thread overview]
Message-ID: <20260731153617.358265-8-j.klocker@proxmox.com> (raw)
In-Reply-To: <20260731153617.358265-1-j.klocker@proxmox.com>

Display additional storage information: `Plugin State`, `External` and
`Plugin URL`. The `Plugin URL` row is hidden when no URL is set, and
third-party plugin URLs are prefixed to distinguish them from official
documentation links. The `Plugin State` row shows whether the plugin is
up to date, outdated (with how many more API versions it will remain
supported), or failed to load.

Signed-off-by: Jakob Klocker <j.klocker@proxmox.com>
---
 www/manager6/Utils.js              | 68 ++++++++++++++++++++++++++++++
 www/manager6/storage/StatusView.js | 38 ++++++++++++++++-
 2 files changed, 105 insertions(+), 1 deletion(-)

diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js
index 040b5ae0..2f098ff0 100644
--- a/www/manager6/Utils.js
+++ b/www/manager6/Utils.js
@@ -1072,6 +1072,32 @@ Ext.define('PVE.Utils', {
                 .join(', ');
         },
 
+        format_plugin_state: function (value) {
+            if (!value) {
+                return '';
+            }
+            switch (value.state) {
+                case 'load-error':
+                    return gettext('Failed to load');
+                case 'outdated': {
+                    let ver = value['api-version'];
+                    let min = value['api-min'];
+                    let max = value['api-max'];
+                    let headroom = ver - min;
+                    return Ext.String.format(
+                        gettext(
+                            'Outdated (API {0}, current {1}) - supported for {2} more API version(s)',
+                        ),
+                        ver,
+                        max,
+                        headroom,
+                    );
+                }
+                default:
+                    return gettext('Up to date');
+            }
+        },
+
         render_storage_content: function (value, metaData, record) {
             let data = record.data;
             let result;
@@ -1367,6 +1393,48 @@ Ext.define('PVE.Utils', {
             return Ext.htmlEncode(Proxmox.Utils.format_task_description(type, id));
         },
 
+        render_plugin_url: function (value, type) {
+            if (value === undefined || value === null || value === '') {
+                return '';
+            }
+            let isLink = /^https?:\/\//i.test(value);
+            if (!isLink) {
+                return Ext.htmlEncode(value);
+            }
+
+            let isOfficial = false;
+
+            try {
+                isOfficial = new URL(value).hostname === 'pve.proxmox.com';
+            } catch {
+                isOfficial = false;
+            }
+
+            let encoded = Ext.htmlEncode(value);
+
+            if (isOfficial) {
+                let name = type ? PVE.Utils.format_storage_type(type) : '';
+                let label = name
+                    ? Ext.String.format(gettext('{0} Documentation'), name)
+                    : gettext('Documentation');
+                return (
+                    '<a href="' +
+                    encoded +
+                    '" target="_blank" rel="noopener noreferrer">' +
+                    Ext.htmlEncode(label) +
+                    '</a>'
+                );
+            }
+
+            let link =
+                '<a href="' +
+                encoded +
+                '" target="_blank" rel="noopener noreferrer">' +
+                encoded +
+                '</a>';
+            return gettext('(External) ') + link;
+        },
+
         render_optional_url: function (value) {
             if (value && value.match(/^https?:\/\//)) {
                 return '<a target="_blank" href="' + value + '">' + value + '</a>';
diff --git a/www/manager6/storage/StatusView.js b/www/manager6/storage/StatusView.js
index 0525fbb5..ba5e6b07 100644
--- a/www/manager6/storage/StatusView.js
+++ b/www/manager6/storage/StatusView.js
@@ -2,7 +2,7 @@ Ext.define('PVE.storage.StatusView', {
     extend: 'Proxmox.panel.StatusView',
     alias: 'widget.pveStorageStatusView',
 
-    height: 230,
+    height: 320,
     title: gettext('Status'),
 
     layout: {
@@ -47,6 +47,42 @@ Ext.define('PVE.storage.StatusView', {
             textField: 'type',
             renderer: PVE.Utils.format_storage_type,
         },
+        {
+            itemId: 'plugin-external',
+            title: gettext('External'),
+            printBar: false,
+            textField: 'plugin',
+            renderer: (value) => Proxmox.Utils.format_boolean(value?.external),
+        },
+        {
+            itemId: 'plugin-status',
+            title: gettext('Plugin State'),
+            printBar: false,
+            textField: 'plugin',
+            renderer: (value) => PVE.Utils.format_plugin_state(value),
+        },
+        {
+            itemId: 'plugin-url',
+            title: gettext('Plugin URL'),
+            printBar: false,
+            textField: 'plugin',
+            hidden: true,
+            renderer: function (value) {
+                let url = value?.url;
+                let has = url !== undefined && url !== null && url !== '';
+                this.setHidden(!has);
+                if (!has) {
+                    return '';
+                }
+                let view = this.up('pveStorageStatusView');
+                let type;
+                if (view && view.rstore) {
+                    let rec = view.rstore.getById('type');
+                    type = rec ? rec.data.value : undefined;
+                }
+                return PVE.Utils.render_plugin_url(url, type);
+            },
+        },
         {
             xtype: 'box',
             height: 10,
-- 
2.47.3




  parent reply	other threads:[~2026-07-31 15:37 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-31 15:36 [PATCH manager/storage 0/9] storage: plugins: display failed and outdated storage plugins in the GUI Jakob Klocker
2026-07-31 15:36 ` [PATCH pve-storage 1/9] storage: drop unused variable in storage_info Jakob Klocker
2026-07-31 15:36 ` [PATCH pve-storage 2/9] storage: add `plugin-url` to built-in plugins Jakob Klocker
2026-07-31 15:36 ` [PATCH pve-storage 3/9] storage: add `unknown` flag to parse_config Jakob Klocker
2026-07-31 15:36 ` [PATCH pve-storage 4/9] storage: plugins: cache and classify custom storage plugins Jakob Klocker
2026-07-31 15:36 ` [PATCH pve-storage 5/9] storage: expose plugin metadata in storage status Jakob Klocker
2026-07-31 15:36 ` [PATCH pve-manager 6/9] cluster: backend: include storages with unloadable plugins Jakob Klocker
2026-07-31 15:36 ` Jakob Klocker [this message]
2026-07-31 15:36 ` [PATCH pve-manager 8/9] www: storage: distinguish failed/outdated storage plugins in resource tree Jakob Klocker
2026-07-31 15:36 ` [PATCH pve-manager 9/9] www: storage: display custom summary for failed plugins Jakob Klocker

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260731153617.358265-8-j.klocker@proxmox.com \
    --to=j.klocker@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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