public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Hannes Laimer <h.laimer@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH pve-manager 2/2] ui: sdn: ipam: allow picking the nic instead of typing its MAC
Date: Wed, 19 Aug 2026 14:44:07 +0200	[thread overview]
Message-ID: <20260819124407.856577-3-h.laimer@proxmox.com> (raw)
In-Reply-To: <20260819124407.856577-1-h.laimer@proxmox.com>

Instead of hand-copying a MAC from the guest's hardware panel, take a
guest and one of its NICs on the assignments's VNet, and fill the MAC in
from there.

Setting a MAC without a guest stays possible, so this is purely a UX
improvement. We could also restrict this, so our IPAM only manages IPs
of guests in our SDN.

Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
 www/manager6/sdn/IpamEdit.js | 112 ++++++++++++++++++++++++++++++++++-
 1 file changed, 109 insertions(+), 3 deletions(-)

diff --git a/www/manager6/sdn/IpamEdit.js b/www/manager6/sdn/IpamEdit.js
index cdefe436..aeb21b2b 100644
--- a/www/manager6/sdn/IpamEdit.js
+++ b/www/manager6/sdn/IpamEdit.js
@@ -16,18 +16,48 @@ Ext.define('PVE.sdn.IpamEditInputPanel', {
 
     items: [
         {
-            xtype: 'pmxDisplayEditField',
             name: 'vmid',
-            fieldLabel: 'VMID',
+            fieldLabel: gettext('Guest'),
+            allowBlank: true,
+            notFoundIsValid: true,
+            emptyText: Proxmox.Utils.NoneText,
+            cbind: {
+                xtype: (get) => (get('isCreate') ? 'vmComboSelector' : 'displayfield'),
+            },
+            listeners: {
+                change: 'onGuestChange',
+            },
+        },
+        {
+            xtype: 'combobox',
+            reference: 'netid',
+            fieldLabel: gettext('Network Device'),
+            emptyText: gettext('Select a guest first'),
+            submitValue: false,
             allowBlank: false,
             editable: false,
+            disabled: true,
+            queryMode: 'local',
+            valueField: 'netid',
+            displayField: 'netid',
+            listConfig: {
+                itemTpl: '{netid} <i>{mac:htmlEncode}</i>',
+            },
+            store: {
+                fields: ['netid', 'mac'],
+                data: [],
+            },
             cbind: {
-                hidden: '{isCreate}',
+                hidden: '{!isCreate}',
+            },
+            listeners: {
+                select: 'onDeviceSelect',
             },
         },
         {
             xtype: 'pmxDisplayEditField',
             name: 'mac',
+            reference: 'mac',
             fieldLabel: 'MAC',
             allowBlank: false,
             cbind: {
@@ -58,11 +88,87 @@ Ext.define('PVE.sdn.IpamEdit', {
         return `${url}/${values.vnet}/ips`;
     },
 
+    controller: {
+        xclass: 'Ext.app.ViewController',
+
+        onGuestChange: function (f, vmid) {
+            if (!this.getView().isCreate) {
+                return;
+            }
+            this.setGuest(vmid ? f.getSelection() : undefined);
+        },
+
+        onDeviceSelect: function (f, record) {
+            this.lookup('mac').setValue(record?.data.mac ?? '');
+        },
+
+        setGuest: function (record) {
+            let me = this;
+            let view = me.getView();
+
+            let selector = me.lookup('netid');
+            let mac = me.lookup('mac');
+
+            selector.clearValue();
+            selector.getStore().removeAll();
+            selector.setDisabled(!record);
+
+            mac.setValue('');
+            mac.setEditable(!record);
+
+            if (!record) {
+                selector.setEmptyText(gettext('Select a guest first'));
+                return;
+            }
+
+            Proxmox.Utils.API2Request({
+                url: `/nodes/${record.data.node}/${record.data.type}/${record.data.vmid}/config`,
+                method: 'GET',
+                failure: (response) => Ext.Msg.alert(gettext('Error'), response.htmlStatus),
+                success: function ({ result }) {
+                    if (selector.destroyed) {
+                        return;
+                    }
+
+                    let vnet = view.extraRequestParams?.vnet;
+                    let nics = [];
+
+                    for (const [key, value] of Object.entries(result.data)) {
+                        if (!key.match(/^net\d+$/)) {
+                            continue;
+                        }
+
+                        let net =
+                            record.data.type === 'qemu'
+                                ? PVE.Parser.parseQemuNetwork(key, value)
+                                : PVE.Parser.parseLxcNetwork(value);
+
+                        let mac = net?.macaddr ?? net?.hwaddr;
+                        if (!mac || net.bridge !== vnet) {
+                            continue;
+                        }
+
+                        nics.push({ netid: key, mac });
+                    }
+
+                    selector.getStore().setData(nics);
+                    selector.setEmptyText(
+                        nics.length
+                            ? gettext('Select a network device')
+                            : Ext.String.format(gettext('No network device on {0}'), vnet),
+                    );
+                },
+            });
+        },
+    },
+
     initComponent: function () {
         var me = this;
 
         me.method = me.isCreate ? 'POST' : 'PUT';
 
+        me.defaultFocus = me.isCreate ? 'textfield[name=mac]' : 'textfield[name=ip]';
+
         let ipanel = Ext.create('PVE.sdn.IpamEditInputPanel', {
             isCreate: me.isCreate,
         });
-- 
2.47.3





      parent reply	other threads:[~2026-08-19 12:44 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-19 12:44 [PATCH manager/network 0/2] sdn: add guest/nic selectors to IPAM create window Hannes Laimer
2026-08-19 12:44 ` [PATCH pve-network 1/2] api: sdn: ipam: add optional vmid to POST endpoint Hannes Laimer
2026-08-19 12:44 ` Hannes Laimer [this message]

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=20260819124407.856577-3-h.laimer@proxmox.com \
    --to=h.laimer@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