From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 5CFF21FF13F for ; Thu, 26 Mar 2026 16:40:25 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id DF6261970A; Thu, 26 Mar 2026 16:40:47 +0100 (CET) From: Maximiliano Sandoval To: Arthur Bied-Charreton Subject: Re: [PATCH pve-manager 5/8] ui: Add CPU flag editor for custom models In-Reply-To: <20260312084021.124465-6-a.bied-charreton@proxmox.com> (Arthur Bied-Charreton's message of "Thu, 12 Mar 2026 09:40:18 +0100") References: <20260312084021.124465-1-a.bied-charreton@proxmox.com> <20260312084021.124465-6-a.bied-charreton@proxmox.com> User-Agent: mu4e 1.12.9; emacs 30.1 Date: Thu, 26 Mar 2026 16:40:12 +0100 Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1774539564181 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.126 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment 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: LNGJNMFCUQUY3EHL7YVYCLUBFV2FSFA6 X-Message-ID-Hash: LNGJNMFCUQUY3EHL7YVYCLUBFV2FSFA6 X-MailFrom: m.sandoval@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 CC: pve-devel@lists.proxmox.com X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Arthur Bied-Charreton writes: > Add CPU flag editor to the CPUTypeEdit component, using the VMCPUFlagSele= ctor > also used in the VM creation flow. By default, only show the CPU flags th= at > are currently meant to be shown in the VM creation window, see [0]. When = in > CPUTypeEdit, show all available flags. > > For each flag in VMCPUFlagSelector, also display which node(s) it is avai= lable > on to limit misconfigurations. > > Original patch: > https://lore.proxmox.com/pve-devel/20211028114150.3245864-10-s.reiter@pro= xmox.com > > [0] https://git.proxmox.com/?p=3Dqemu-server.git;a=3Dblob;f=3Dsrc/PVE/Qem= uServer/CPUConfig.pm;h=3D32ec495422791422f20caa928d6b632b3de4fcd9;hb=3Drefs= /heads/master#l349 > > Originally-by: Stefan Reiter > Signed-off-by: Arthur Bied-Charreton > --- > www/manager6/dc/CPUTypeEdit.js | 11 ++- > www/manager6/form/CPUModelSelector.js | 1 + > www/manager6/form/VMCPUFlagSelector.js | 121 ++++++++++++++++++++++--- > 3 files changed, 117 insertions(+), 16 deletions(-) > > diff --git a/www/manager6/dc/CPUTypeEdit.js b/www/manager6/dc/CPUTypeEdit= .js > index 8cf508b4..d6e06601 100644 > --- a/www/manager6/dc/CPUTypeEdit.js > +++ b/www/manager6/dc/CPUTypeEdit.js > @@ -84,7 +84,16 @@ Ext.define('PVE.dc.CPUTypeEdit', { > name: 'phys-bits', > }, > ], > - > + columnB: [ > + { > + xtype: 'vmcpuflagselector', > + fieldLabel: gettext('Extra CPU flags'), > + name: 'flags', > + restrictToVMFlags: false, > + height: 380, > + hideHeaders: false, > + }, > + ], > }, > ], > }); > diff --git a/www/manager6/form/CPUModelSelector.js b/www/manager6/form/CP= UModelSelector.js > index 2154ff46..683fa469 100644 > --- a/www/manager6/form/CPUModelSelector.js > +++ b/www/manager6/form/CPUModelSelector.js > @@ -17,6 +17,7 @@ Ext.define('PVE.form.CPUModelSelector', { > anyMatch: true, > forceSelection: true, > autoSelect: false, > + triggerAction: 'query', >=20=20 > deleteEmpty: true, > config: { > diff --git a/www/manager6/form/VMCPUFlagSelector.js b/www/manager6/form/V= MCPUFlagSelector.js > index 74b1a2c4..06c9d9f1 100644 > --- a/www/manager6/form/VMCPUFlagSelector.js > +++ b/www/manager6/form/VMCPUFlagSelector.js > @@ -1,3 +1,19 @@ > +const VM_CPU_FLAGS_SUBSET =3D { > + aes: true, > + 'amd-no-ssb': true, > + 'amd-ssbd': true, > + 'hv-evmcs': true, > + 'hv-tlbflush': true, > + ibpb: true, > + 'md-clear': true, > + 'nested-virt': true, > + pcid: true, > + pdpe1gb: true, > + 'spec-ctrl': true, > + ssbd: true, > + 'virt-ssbd': true, > +}; > + > Ext.define('PVE.form.VMCPUFlagSelector', { > extend: 'Ext.grid.Panel', > alias: 'widget.vmcpuflagselector', > @@ -6,6 +22,10 @@ Ext.define('PVE.form.VMCPUFlagSelector', { > field: 'Ext.form.field.Field', > }, >=20=20 > + config: { > + restrictToVMFlags: true, > + }, > + > disableSelection: true, > columnLines: false, > selectable: false, > @@ -17,27 +37,18 @@ Ext.define('PVE.form.VMCPUFlagSelector', { > unknownFlags: [], >=20=20 > store: { > - type: 'store', > - fields: ['name', { name: 'state', defaultValue: '=3D' }, 'descri= ption'], > - autoLoad: true, > + fields: ['name', { name: 'state', defaultValue: '=3D' }, 'descri= ption', 'supported-on'], > + autoLoad: false, > proxy: { > type: 'proxmox', > url: '/api2/json/nodes/localhost/capabilities/qemu/cpu-flags= ', > + extraParams: { accel: 'kvm' }, > }, > listeners: { > update: function () { > this.commitChanges(); > }, > - refresh: function (store, eOpts) { > - let me =3D this; > - let view =3D me.view; > - > - if (store.adjustedForValue !=3D=3D view.value) { > - view.adjustStoreForValue(); > - } > - }, > }, > - adjustedForValue: undefined, > }, >=20=20 > getValue: function () { > @@ -86,14 +97,18 @@ Ext.define('PVE.form.VMCPUFlagSelector', { > let rec =3D store.findRecord('name', flagName, 0, false, tru= e, true); > if (rec !=3D=3D null) { > rec.set('state', sign); > + rec.commit(); > } else { > me.unknownFlags.push(flag); > } > }); >=20=20 > - store.adjustedForValue =3D value; > + me.getView().refresh(); > + }, > + isDirty: function () { > + let me =3D this; > + return me.originalValue !=3D=3D me.getValue(); > }, > - > setValue: function (value) { > let me =3D this; >=20=20 > @@ -109,6 +124,7 @@ Ext.define('PVE.form.VMCPUFlagSelector', { > }, > columns: [ > { > + text: gettext('State'), > dataIndex: 'state', > renderer: function (v) { > switch (v) { > @@ -125,6 +141,7 @@ Ext.define('PVE.form.VMCPUFlagSelector', { > width: 65, > }, > { > + text: gettext('Set'), This would benefit from a TRANSLATORS comment. Is this a noun (set as in set theory)? is it a verb (to set)? From the point of view of translators there is not enough context to decide. > xtype: 'widgetcolumn', > dataIndex: 'state', > width: 95, > @@ -171,22 +188,96 @@ Ext.define('PVE.form.VMCPUFlagSelector', { > }, > }, > { > + text: gettext('Flag'), > dataIndex: 'name', > width: 100, > }, > { > + text: gettext('Description'), > dataIndex: 'description', > + sortable: false, > + cellWrap: true, > + flex: 3, > + }, > + { > + text: gettext('Supported On'), > + dataIndex: 'supported-on', > cellWrap: true, > flex: 1, > + renderer: (v) =3D> (Array.isArray(v) ? v.join(', ') : ''), > }, > ], >=20=20 > initComponent: function () { > let me =3D this; >=20=20 > + me.unknownFlags =3D []; > me.value =3D me.originalValue =3D ''; > - me.store.view =3D me; > + > + me.dockedItems =3D [ > + { > + xtype: 'toolbar', > + dock: 'top', > + items: [ > + { > + xtype: 'tbtext', > + text: gettext('Acceleration:'), > + autoEl: { > + tag: 'span', > + 'data-qtip': gettext( > + 'A custom CPU model using acceleration-s= pecific flags should only be assigned to VMs configured with the matching a= cceleration type, i.e., `kvm: off` for TCG, or `kvm: on` for KVM.', I would recommend to use quotes `"`, single-quotes `'` in user-facing strings. Backticks are a markup/markdown concept. See [1]. off-topic: In principle one should use =E2=80=9C=E2=80=9D rather than "", b= ut I don't think there is precedent for this the codebase. [1] https://en.wikipedia.org/wiki/Quotation_mark#In_English > + ), > + }, > + }, > + { > + xtype: 'radiogroup', > + layout: 'hbox', > + validateOnChange: false, > + items: [ > + { > + boxLabel: 'KVM', > + inputValue: 'kvm', > + name: 'accel', > + checked: true, > + isFormField: false, > + }, > + { > + boxLabel: 'TCG', > + inputValue: 'tcg', > + name: 'accel', > + margin: '0 0 0 10', > + isFormField: false, > + }, > + ], > + listeners: { > + change: function (_, value) { > + let view =3D this.up('grid'); > + let proxy =3D view.getStore().getProxy(); > + let accel =3D value.accel; > + if (accel) { > + proxy.setExtraParam('accel', accel); > + } else { > + delete proxy.extraParams.accel; > + } > + view.getStore().load(); > + }, > + }, > + }, > + ], > + }, > + ]; >=20=20 > me.callParent(arguments); > + > + me.getStore().on('load', function (store, _, success) { > + if (success) { > + if (me.restrictToVMFlags) { > + store.filterBy((rec) =3D> VM_CPU_FLAGS_SUBSET[rec.ge= t('name')] =3D=3D=3D true); > + } > + me.adjustStoreForValue(); > + me.checkDirty(); > + } > + }); > + me.getStore().load(); > }, > }); --=20 Maximiliano