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 ACB491FF0A7 for ; Wed, 16 Sep 2026 11:07:45 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 3DDF72158F; Wed, 16 Sep 2026 11:07:35 +0200 (CEST) From: Jonas Theisen To: pve-devel@lists.proxmox.com Subject: [PATCH manager 1/5] ui: integrate new VM.Reboot permission Date: Wed, 16 Sep 2026 11:06:55 +0200 Message-ID: <20260916090715.72307-2-j.theisen@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260916090715.72307-1-j.theisen@proxmox.com> References: <20260916090715.72307-1-j.theisen@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1789549651012 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.277 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust 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: LKW6JDFY5PJMCHZEDHCNNGB4V4PVM6Z4 X-Message-ID-Hash: LKW6JDFY5PJMCHZEDHCNNGB4V4PVM6Z4 X-MailFrom: j.theisen@proxmox.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: To allow users with this restriced VM PowerMgmt permission to still intuitively use the interface this commit rearranges and introduces a few new UI elements. If the user only has the VM.Reboot permission: * The default Shutdown Button is replaced by a Reboot button to not hide the first available functino to the user behind a dropdown menu. * The Start button is hidden as long as the user does not have the VM.PowerMgmt permission. * The new Reboot button is updated similar to the Shutdown and Start button if the guest state changes. For regular users with VM.PowerMgmt permission this should not change anything. Signed-off-by: Jonas Theisen --- www/manager6/qemu/Config.js | 51 +++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/www/manager6/qemu/Config.js b/www/manager6/qemu/Config.js index 842d35de..b22b52fe 100644 --- a/www/manager6/qemu/Config.js +++ b/www/manager6/qemu/Config.js @@ -57,7 +57,7 @@ Ext.define('PVE.qemu.Config', { var startBtn = Ext.create('Ext.Button', { text: gettext('Start'), disabled: !caps.vms['VM.PowerMgmt'] || running, - hidden: template, + hidden: !caps.vms['VM.PowerMgmt'] || template, handler: function () { vm_command('start'); }, @@ -153,7 +153,7 @@ Ext.define('PVE.qemu.Config', { var shutdownBtn = Ext.create('PVE.button.Split', { text: gettext('Shutdown'), disabled: !caps.vms['VM.PowerMgmt'] || !running, - hidden: template, + hidden: !caps.vms['VM.PowerMgmt'] || template, confirmMsg: PVE.Utils.formatGuestTaskConfirmation('qmshutdown', vmid, vm.name), handler: function () { vm_command('shutdown'); @@ -228,6 +228,35 @@ Ext.define('PVE.qemu.Config', { iconCls: 'fa fa-power-off', }); + var rebootBtn = Ext.create('PVE.button.Split', { + text: gettext('Reboot'), + disabled: !running || !!caps.vms['VM.PowerMgmt'] || !caps.vms['VM.Reboot'], + hidden: !!caps.vms['VM.PowerMgmt'] || !caps.vms['VM.Reboot'], + tooltip: Ext.String.format( + gettext('Shutdown, apply pending changes and reboot {0}'), + 'VM', + ), + confirmMsg: PVE.Utils.formatGuestTaskConfirmation('qmreboot', vmid, vm.name), + handler: function () { + vm_command('reboot'); + }, + iconCls: 'fa fa-refresh', + menu: { + items: [ + { + text: gettext('Reset'), + disabled: !(caps.vms['VM.PowerMgmt'] || caps.vms['VM.Reboot']), + tooltip: Ext.String.format(gettext('Reset {0} immediately'), 'VM'), + confirmMsg: PVE.Utils.formatGuestTaskConfirmation('qmreset', vmid, vm.name), + handler: function () { + vm_command('reset'); + }, + iconCls: 'fa fa-bolt', + }, + ], + }, + }); + var consoleBtn = Ext.create('PVE.button.ConsoleButton', { disabled: !caps.vms['VM.Console'], hidden: template, @@ -287,6 +316,7 @@ Ext.define('PVE.qemu.Config', { resumeBtn, startBtn, shutdownBtn, + rebootBtn, migrateBtn, consoleBtn, moreBtn, @@ -486,12 +516,14 @@ Ext.define('PVE.qemu.Config', { var resume = ['prelaunch', 'paused', 'suspended'].indexOf(qmpstatus) !== -1; - if (resume || lock === 'suspended') { - startBtn.setVisible(false); - resumeBtn.setVisible(true); - } else { - startBtn.setVisible(true); - resumeBtn.setVisible(false); + if (caps.vms['VM.PowerMgmt']) { + if (resume || lock === 'suspended') { + startBtn.setVisible(false); + resumeBtn.setVisible(true); + } else { + startBtn.setVisible(true); + resumeBtn.setVisible(false); + } } consoleBtn.setEnableSpice(spice); @@ -504,6 +536,9 @@ Ext.define('PVE.qemu.Config', { startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || template || guest_running); shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running'); + + rebootBtn.setDisabled(!caps.vms['VM.Reboot'] || status !== 'running'); + me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped'); consoleBtn.setDisabled(template); -- 2.47.3