From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 34CF91FF0B7 for ; Fri, 16 Oct 2026 12:07:34 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 58EA62144E; Fri, 16 Oct 2026 12:07:33 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dualfroz.com; s=dkim; t=1792145239; h=from:subject:date:message-id:to:mime-version: content-transfer-encoding; bh=3w1IatSKwYXxKkAepkbhiv0sB17jzzvgFv7sy8r0zig=; b=ofmMwYGNNKtz360wmsN+kl2LEimJqdO1B8WdgMuNx/+WQb/IZBfwYv8xtDxd+5/tVmzEyu ANz5uIYh93BeZzkOCyeZ1QU+0R/mVZSSgum710ZX5f8Y8VTkfee5w4xxYY7kPn0Q6h5CEG zo5NLX3KKX5Qr2F//bReKoi+/bViv85IkeEUUWDp+jlyqN9VJF4K9JNGz6oGltk5paRb6e Kf1ir9++Et/F8t+yDOaeJ0nhIP4SqHE1JJnI9enQljBzI8L1Vygf3d3+62piQkzozJRNoB Pv1IFavnys8kOcnyp0ZJ2bEVPzjhYKSN6hXDCdpAAM/FYQMR8y6OrPmYkb9xFQ== From: Michal Fox To: pve-devel@lists.proxmox.com Subject: [PATCH manager] fix #5871: ui: resize disk: show current and new size Date: Fri, 16 Oct 2026 10:07:13 +0000 Message-ID: <20261016100713.7-1-me@dualfroz.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Last-TLS-Session-Version: TLSv1.3 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.129 Adjusted score from AWL reputation of From: address DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature DKIM_VALID_AU -0.1 Message has a valid DKIM or DK signature from author's domain DKIM_VALID_EF -0.1 Message has a valid DKIM or DK signature from envelope-from domain DMARC_PASS -0.1 DMARC pass policy SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: 5FD6CHYSYWD3ENQNYM7EVK2FWEU6QVEG X-Message-ID-Hash: 5FD6CHYSYWD3ENQNYM7EVK2FWEU6QVEG X-MailFrom: me@dualfroz.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: The resize dialogs of VMs and containers only ask for the size increment, so users have to look up the current size of the disk in the config to know which size the disk will have afterwards. Load the config of the guest in the dialogs and show the current size of the disk, and the size it will have with the entered increment, which gets updated while typing. As the dialogs load the size themselves, callers do not need to change. The size of the config is in the 'disk-size' format, where the units are binary, while Proxmox.Utils.parse_size_unit() takes 'G' as GB, so add a small parser for it, like parse_size() of PVE::JSONSchema. Signed-off-by: Michal Fox --- Tested in the browser with both dialogs and mocked API calls, for disks with the sizes '32G', '528K', '16896', '1.5T' and '10GiB', a passed through disk without size, and a container's rootfs and mount point: the current size is shown ('Unknown' without size), the new size follows the increment and is empty for an invalid one, and the resize request is the same as before, for example '+2.5G'. The fixed height of the VM dialog is dropped, as it cut off the new rows. This does not touch the callers, so it should not conflict with the series splitting out the disks into their own grid, which opens the dialog the same way. The shown sizes are based on the size in the config, like in the hardware view, while the API adds the increment to the actual size of the volume. These only differ if the config is out of date. www/manager6/Utils.js | 10 +++++++++ www/manager6/lxc/MPResize.js | 41 ++++++++++++++++++++++++++++++++++ www/manager6/qemu/HDResize.js | 42 ++++++++++++++++++++++++++++++++++- 3 files changed, 92 insertions(+), 1 deletion(-) diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js index 8b99371d..a9260ec6 100644 --- a/www/manager6/Utils.js +++ b/www/manager6/Utils.js @@ -1148,6 +1148,16 @@ Ext.define('PVE.Utils', { return `${per.toFixed(1)}% of ${maxcpu} ${cpu_label}`; }, + // parses a size in the 'disk-size' format of the API, like '32G', into bytes + parse_disk_size: function (value) { + let match = /^(\d+(?:\.\d+)?)(?:([KMGT])(?:iB)?)?$/.exec(value); + if (!match) { + return undefined; + } + let exponent = ['', 'K', 'M', 'G', 'T'].indexOf(match[2] ?? ''); + return parseFloat(match[1]) * 1024 ** exponent; + }, + render_bandwidth: function (value) { if (!Ext.isNumeric(value)) { return ''; diff --git a/www/manager6/lxc/MPResize.js b/www/manager6/lxc/MPResize.js index 658123a1..ec56adb1 100644 --- a/www/manager6/lxc/MPResize.js +++ b/www/manager6/lxc/MPResize.js @@ -24,6 +24,17 @@ Ext.define('PVE.window.MPResize', { }); }, + updateNewSize: function () { + let me = this; + let newSize = ''; + if (me.currentSize !== undefined && me.hdsizesel.isValid()) { + newSize = Proxmox.Utils.format_size( + me.currentSize + me.hdsizesel.getValue() * 1024 ** 3, + ); + } + me.down('#newSize').setValue(newSize); + }, + initComponent: function () { var me = this; @@ -44,6 +55,11 @@ Ext.define('PVE.window.MPResize', { vtype: 'StorageId', allowBlank: false, }, + { + xtype: 'displayfield', + itemId: 'currentSize', + fieldLabel: gettext('Current Size'), + }, ]; me.hdsizesel = Ext.createWidget('numberfield', { @@ -54,9 +70,17 @@ Ext.define('PVE.window.MPResize', { value: '0', fieldLabel: `${gettext('Size Increment')} (${gettext('GiB')})`, allowBlank: false, + listeners: { + change: () => me.updateNewSize(), + }, }); items.push(me.hdsizesel); + items.push({ + xtype: 'displayfield', + itemId: 'newSize', + fieldLabel: gettext('New Size'), + }); me.formPanel = Ext.create('Ext.form.Panel', { bodyPadding: 10, @@ -92,5 +116,22 @@ Ext.define('PVE.window.MPResize', { }); me.callParent(); + + Proxmox.Utils.API2Request({ + url: `/nodes/${me.nodename}/lxc/${me.vmid}/config`, + method: 'GET', + waitMsgTarget: me, + failure: (response) => Ext.Msg.alert(gettext('Error'), response.htmlStatus), + success: function (response) { + let size = PVE.Parser.parseLxcMountPoint(response.result.data[me.disk])?.size; + me.currentSize = size ? PVE.Utils.parse_disk_size(size) : undefined; + me.down('#currentSize').setValue( + me.currentSize !== undefined + ? Proxmox.Utils.format_size(me.currentSize) + : Proxmox.Utils.unknownText, + ); + me.updateNewSize(); + }, + }); }, }); diff --git a/www/manager6/qemu/HDResize.js b/www/manager6/qemu/HDResize.js index 574bfb5a..4c2ac581 100644 --- a/www/manager6/qemu/HDResize.js +++ b/www/manager6/qemu/HDResize.js @@ -25,6 +25,17 @@ Ext.define('PVE.window.HDResize', { }); }, + updateNewSize: function () { + let me = this; + let newSize = ''; + if (me.currentSize !== undefined && me.hdsizesel.isValid()) { + newSize = Proxmox.Utils.format_size( + me.currentSize + me.hdsizesel.getValue() * 1024 ** 3, + ); + } + me.down('#newSize').setValue(newSize); + }, + initComponent: function () { var me = this; @@ -45,6 +56,11 @@ Ext.define('PVE.window.HDResize', { vtype: 'StorageId', allowBlank: false, }, + { + xtype: 'displayfield', + itemId: 'currentSize', + fieldLabel: gettext('Current Size'), + }, ]; me.hdsizesel = Ext.createWidget('numberfield', { @@ -55,9 +71,17 @@ Ext.define('PVE.window.HDResize', { value: '0', fieldLabel: `${gettext('Size Increment')} (${gettext('GiB')})`, allowBlank: false, + listeners: { + change: () => me.updateNewSize(), + }, }); items.push(me.hdsizesel); + items.push({ + xtype: 'displayfield', + itemId: 'newSize', + fieldLabel: gettext('New Size'), + }); me.formPanel = Ext.create('Ext.form.Panel', { bodyPadding: 10, @@ -87,7 +111,6 @@ Ext.define('PVE.window.HDResize', { Ext.apply(me, { modal: true, width: 250, - height: 150, border: false, layout: 'fit', buttons: [submitBtn], @@ -95,5 +118,22 @@ Ext.define('PVE.window.HDResize', { }); me.callParent(); + + Proxmox.Utils.API2Request({ + url: `/nodes/${me.nodename}/qemu/${me.vmid}/config`, + method: 'GET', + waitMsgTarget: me, + failure: (response) => Ext.Msg.alert(gettext('Error'), response.htmlStatus), + success: function (response) { + let size = PVE.Parser.parseQemuDrive(me.disk, response.result.data[me.disk])?.size; + me.currentSize = size ? PVE.Utils.parse_disk_size(size) : undefined; + me.down('#currentSize').setValue( + me.currentSize !== undefined + ? Proxmox.Utils.format_size(me.currentSize) + : Proxmox.Utils.unknownText, + ); + me.updateNewSize(); + }, + }); }, }); -- 2.43.0