public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: "Lukas Sichert" <l.sichert@proxmox.com>
To: "Stefan Hanreich" <s.hanreich@proxmox.com>,
	<pve-devel@lists.proxmox.com>
Subject: Re: [PATCH pve-manager v8 20/25] ui: sdn: prefix list: adapt to changed api structure
Date: Mon, 11 May 2026 18:11:50 +0200	[thread overview]
Message-ID: <DIFZ9TQGOAO2.1X0UKD75NI2WZ@proxmox.com> (raw)
In-Reply-To: <20260511133650.310040-21-s.hanreich@proxmox.com>

On 2026-05-11 15:36, Stefan Hanreich <s.hanreich@proxmox.com> wrote:

> From: Dominik Csapak <d.csapak@proxmox.com>
>
> instead of having to parse out the prefix list entries from the overall
> prefix list GET api call, the entries are now queried below:
>
> /sdn/cluster/prefix-list/{id}/entries
>
> so the entries grid can be simplified to use it's own store + url.
> This makes it possible to move the stores out of the viewmodel and into
> the respective grid views.
>
> Also use proxmoxStdRemoveButtons here to simplify the removal code.
>
> Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
> [SH: fixed wrong url in edit window, made sequence number optional and
> added empty text]
> Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
> ---
>  www/manager6/sdn/PrefixListPanel.js | 279 ++++++++++------------------
>  1 file changed, 96 insertions(+), 183 deletions(-)
>
> diff --git a/www/manager6/sdn/PrefixListPanel.js b/www/manager6/sdn/PrefixListPanel.js
> index cdb860f4f..0e5cc11b8 100644
> --- a/www/manager6/sdn/PrefixListPanel.js
> +++ b/www/manager6/sdn/PrefixListPanel.js
> @@ -1,16 +1,11 @@
>  Ext.define('PVE.sdn.PrefixList', {
>      extend: 'Ext.data.Model',
> -    fields: ['id', 'entries', 'pending'],
> -
> -    getId: function () {
> -        let me = this;
> -        return me.data.pending?.[me.idProperty] ?? me.data[me.idProperty];
> -    },
> +    fields: ['id', 'state'],
>  });
>  
>  Ext.define('PVE.sdn.PrefixListEntry', {
>      extend: 'Ext.data.Model',
> -    fields: ['id', 'action', 'prefix', 'le', 'ge', 'pending'],
> +    fields: ['id', 'action', 'seq', 'prefix', 'le', 'ge', 'pending'],
>  });
>  
>  Ext.define('PVE.sdn.EditPrefixListWindow', {
> @@ -45,10 +40,11 @@ Ext.define('PVE.sdn.EditPrefixListWindow', {
>  
>  Ext.define('PVE.sdn.EditPrefixListEntryWindow', {
>      extend: 'Proxmox.window.Edit',
> +    mixins: ['Proxmox.Mixin.CBind'],
>  
>      subject: gettext('Prefix List Entry'),
>  
> -    url: '/cluster/sdn/prefix-lists',
> +    baseUrl: '/cluster/sdn/prefix-lists',
>  
>      config: {
>          entry: null,
> @@ -57,6 +53,15 @@ Ext.define('PVE.sdn.EditPrefixListEntryWindow', {
>      isCreate: false,
>  
>      items: [
> +        {
> +            xtype: 'proxmoxintegerfield',
> +            name: 'seq',
> +            fieldLabel: gettext('Sequence Nr.'),
> +            emptyText: gettext('autogenerated'),
> +            cbind: {
> +                deleteEmpty: '{!isCreate}',
> +            }
> +        },
>          {
>              xtype: 'proxmoxKVComboBox',
>              fieldLabel: gettext('Action'),
> @@ -88,6 +93,17 @@ Ext.define('PVE.sdn.EditPrefixListEntryWindow', {
>      initComponent: function () {
>          let me = this;
>          me.method = me.isCreate ? 'POST' : 'PUT';
> +
> +        if (!me.prefixList) {
> +            throw new 'no prefixList given'();
> +        }
> +
> +        if (me.entry) {
> +            me.url = `${me.baseUrl}/${me.prefixList}/entries/${me.entry.seq}`;
> +        } else {
> +            me.url = `${me.baseUrl}/${me.prefixList}/entries`;
> +        }
> +
>          me.callParent();
>  
>          me.setValues(me.getEntry());
> @@ -108,19 +124,28 @@ Ext.define('PVE.sdn.PrefixListView', {
>          },
>          {
>              text: gettext('Remove'),
> -            xtype: 'button',
> -            handler: 'removePrefixList',
> -            bind: {
> -                disabled: '{!prefixListGrid.selection}',
> -            },
> +            xtype: 'proxmoxStdRemoveButton',
> +            baseurl: '/cluster/sdn/prefix-lists/',
> +            dangerous: true,
> +            callback: 'reloadPrefixList',
>          },
> +        '->',
>          {
>              text: gettext('Reload'),
>              xtype: 'button',
> -            handler: 'reload',
> +            handler: 'reloadPrefixList',
>          },
>      ],
>  
> +    store: {
> +        autoLoad: true,
> +        model: 'PVE.sdn.PrefixList',
> +        proxy: {
> +            type: 'proxmox',
> +            url: '/api2/json/cluster/sdn/prefix-lists?pending=1',
> +        },
> +    },
> +
>      columns: [
>          {
>              text: gettext('Name'),
> @@ -139,6 +164,12 @@ Ext.define('PVE.sdn.PrefixListView', {
>              },
>          },
>      ],
> +
> +    initComponent: function () {
> +        let me = this;
> +        me.callParent();
> +        Proxmox.Utils.monStoreErrors(me, me.getStore());
> +    },
>  });
>  
>  Ext.define('PVE.sdn.PrefixListEntriesView', {
> @@ -151,30 +182,22 @@ Ext.define('PVE.sdn.PrefixListEntriesView', {
>          prefixList: null,
>      },
>  
> -    viewConfig: {
> -        plugins: [
> -            {
> -                ptype: 'gridviewdragdrop',
> -            },
> -        ],
> -    },
> -
>      listeners: {
> -        drop: 'saveEntries',
>          itemdblclick: 'editPrefixListEntry',
>      },
>  
> +    store: {
> +        model: 'PVE.sdn.PrefixListEntry',
> +        proxy: {
> +            type: 'proxmox',
> +        },
> +    },
> +
>      columns: [
>          {
> -            width: 40,
> -            resizable: false,
> -            sortable: false,
> -            hideable: false,
> -            menuDisabled: true,
> -            renderer: function (value, metaData, record, rowIdx, colIdx) {
> -                metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
> -                return "<i class='pve-grid-fa fa fa-fw fa-reorder cursor-move'></i>";
> -            },
> +            text: gettext('Sequence Nr.'),
> +            dataIndex: 'seq',
> +            flex: 1,
>          },
>          {
>              text: gettext('Action'),
> @@ -209,21 +232,32 @@ Ext.define('PVE.sdn.PrefixListEntriesView', {
>          },
>          {
>              text: gettext('Edit'),
> -            xtype: 'button',
> +            xtype: 'proxmoxButton',
> +            disabled: true,
>              handler: 'editPrefixListEntry',
> -            bind: {
> -                disabled: '{!prefixListEntriesGrid.selection}',
> -            },
>          },
>          {
>              text: gettext('Remove'),
> -            xtype: 'button',
> -            handler: 'removePrefixListEntry',
> -            bind: {
> -                disabled: '{!prefixListEntriesGrid.selection}',
> +            xtype: 'proxmoxStdRemoveButton',
> +            customConfirmationMessage: gettext(
> +                'Are you sure you want to remove entry with sequence {0}',
> +            ),
> +            getRecordName: (rec) => rec.data.seq,
> +            getUrl: function (rec) {
> +                let grid = this.up('grid');
> +                let prefixList = grid.prefixList;
> +                let id = prefixList.getId();
> +                let seq = rec.data.seq;
> +                return `/cluster/sdn/prefix-lists/${id}/entries/${seq}`;

I am a bit confused here. I cannot find a Api Handler for '/entries' in
the pve-network PrefixLists.pm File. Also if I want to look at the
prefix-list entries in the Gui I get 'Method 'GET
/cluster/sdn/prefix-lists/<prefix-list>/entries' not implemented (501)'.
Is this somehow handled in a more obscure way or is it a bug that
happened during rewriting the API interface?

>              },
>          },
>      ],
> +
> +    initComponent: function () {
> +        let me = this;
> +        me.callParent();
> +        Proxmox.Utils.monStoreErrors(me, me.getStore());
> +    },
>  });
>  
>  Ext.define('PVE.sdn.PrefixListPanel', {
> @@ -233,30 +267,6 @@ Ext.define('PVE.sdn.PrefixListPanel', {
>      emptyText: gettext('No prefix list configured'),
>  
>      viewModel: {
> -        stores: {
> -            prefixLists: {
> -                autoLoad: true,
> -                model: 'PVE.sdn.PrefixList',
> -                proxy: {
> -                    type: 'proxmox',
> -                    url: '/api2/json/cluster/sdn/prefix-lists?pending=1',
> -                },
> -            },
> -            prefixListEntries: {
> -                model: 'PVE.sdn.PrefixListEntry',
> -                proxy: {
> -                    type: 'proxmox',
> -                    reader: {
> -                        transform: {
> -                            fn: function (response) {
> -                                let entries = response.data.entries ?? [];
> -                                return entries.map(PVE.Parser.parsePropertyString);
> -                            },
> -                        },
> -                    },
> -                },
> -            },
> -        },
>          formulas: {
>              entryGridEmptyText: function (get) {
>                  let selection = get('prefixListGrid.selection');
> @@ -269,64 +279,24 @@ Ext.define('PVE.sdn.PrefixListPanel', {
>      },
>  
>      controller: {
> -        reload: function () {
> +        reloadPrefixList: function () {
>              let me = this;
> -
> -            let prefixList = me.getViewModel().get('prefixListGrid.selection');
> -
> -            me.getViewModel()
> -                .getStore('prefixLists')
> -                .load((records, _operation, success) => {
> -                    if (!success || !prefixList) {
> -                        return;
> -                    }
> -
> -                    let newPrefixList = records.find((record) => {
> -                        return record.getId() === prefixList.getId();
> -                    });
> -
> -                    me.lookupReference('prefixListGrid').setSelection(newPrefixList);
> -                });
> +            me.lookup('prefixListGrid').getStore().load();
> +            // reset entries grid
> +            let entriesGrid = me.lookup('prefixListEntriesGrid');
> +            entriesGrid.getStore().setData([]);
> +            Proxmox.Utils.setErrorMask(entriesGrid, false);
>          },
> -        saveEntries: function () {
> +        reloadPrefixEntries: function () {
>              let me = this;
> -
> -            let prefixList = me.getViewModel().get('prefixListGrid.selection');
> -
> -            let entries = me
> -                .getViewModel()
> -                .getStore('prefixListEntries')
> -                .getData()
> -                .items.map((item) => {
> -                    let data = item.data;
> -                    delete data.id;
> -
> -                    return PVE.Parser.printPropertyString(data);
> -                });
> -
> -            let params = {};
> -
> -            if (entries.length > 0) {
> -                params.entries = entries;
> -            } else {
> -                params = { delete: ['entries'] };
> -            }
> -
> -            Proxmox.Async.api2({
> -                url: `/api2/extjs/cluster/sdn/prefix-lists/${prefixList.getId()}`,
> -                params,
> -                method: 'PUT',
> -            })
> -                .catch(Proxmox.Utils.alertResponseFailure)
> -                .finally(() => {
> -                    me.reload(prefixList);
> -                });
> +            me.lookup('prefixListEntriesGrid').getStore().load();
>          },
>          selectPrefixList: function (gridPanel, record, index, options) {
>              let me = this;
>  
> -            let url = `/api2/extjs/cluster/sdn/prefix-lists/${record.getId()}`;
> -            let entryStore = me.getViewModel().getStore('prefixListEntries');
> +            let prefixEntriesGrid = me.lookup('prefixListEntriesGrid');
> +            let entryStore = prefixEntriesGrid.getStore();
> +            let url = `/api2/json/cluster/sdn/prefix-lists/${record.getId()}/entries`;
>  
>              entryStore.getProxy().setUrl(url);
>              entryStore.load();
> @@ -338,56 +308,28 @@ Ext.define('PVE.sdn.PrefixListPanel', {
>                  autoShow: true,
>                  isCreate: true,
>                  listeners: {
> -                    close: () => me.reload(),
> +                    close: () => me.reloadPrefixList(),
>                  },
>              });
>          },
> -        removePrefixList: function () {
> +        addPrefixListEntry: function () {
>              let me = this;
>              let prefixList = me.getViewModel().get('prefixListGrid.selection');
>  
> -            Ext.Msg.show({
> -                title: gettext('Confirm'),
> -                icon: Ext.Msg.WARNING,
> -                message: Ext.String.format(gettext('Remove prefix list "{0}"?'), prefixList.getId()),
> -                buttons: Ext.Msg.YESNO,
> -                defaultFocus: 'no',
> -                callback: function (btn) {
> -                    if (btn !== 'yes') {
> -                        return;
> -                    }
> -
> -                    Proxmox.Async.api2({
> -                        url: `/api2/extjs/cluster/sdn/prefix-lists/${prefixList.getId()}`,
> -                        method: 'DELETE',
> -                    })
> -                        .catch(Proxmox.Utils.alertResponseFailure)
> -                        .finally(() => {
> -                            me.reload(prefixList);
> -                        });
> -                },
> -            });
> -        },
> -        addPrefixListEntry: function () {
> -            let panel = this;
> -
>              Ext.create('PVE.sdn.EditPrefixListEntryWindow', {
>                  autoShow: true,
>                  isCreate: true,
> -                submit: function () {
> -                    let me = this;
> -
> -                    panel.getViewModel().getStore('prefixListEntries').add(me.getValues());
> -                    panel.saveEntries();
> -
> -                    me.close();
> +                prefixList: prefixList.getId(),
> +                listeners: {
> +                    close: () => me.reloadPrefixEntries(),
>                  },
>              });
>          },
>          editPrefixListEntry: function () {
> -            let panel = this;
> +            let me = this;
>  
> -            let entry = panel.getViewModel().get('prefixListEntriesGrid.selection');
> +            let entry = me.getViewModel().get('prefixListEntriesGrid.selection');
> +            let prefixList = me.getViewModel().get('prefixListGrid.selection');
>  
>              if (!entry) {
>                  console.warn('no prefix list entry selected!');
> @@ -397,35 +339,10 @@ Ext.define('PVE.sdn.PrefixListPanel', {
>              Ext.create('PVE.sdn.EditPrefixListEntryWindow', {
>                  autoShow: true,
>                  isCreate: false,
> +                prefixList: prefixList.getId(),
>                  entry: entry.data,
> -                submit: function () {
> -                    let me = this;
> -                    entry.set(me.getValues());
> -
> -                    panel.saveEntries();
> -
> -                    me.close();
> -                },
> -            });
> -        },
> -        removePrefixListEntry: function () {
> -            let me = this;
> -
> -            let entry = me.getViewModel().get('prefixListEntriesGrid.selection');
> -
> -            Ext.Msg.show({
> -                title: gettext('Confirm'),
> -                icon: Ext.Msg.WARNING,
> -                message: gettext('Remove prefix list entry?'),
> -                buttons: Ext.Msg.YESNO,
> -                defaultFocus: 'no',
> -                callback: function (btn) {
> -                    if (btn !== 'yes') {
> -                        return;
> -                    }
> -
> -                    me.getViewModel().getStore('prefixListEntries').remove(entry);
> -                    me.saveEntries();
> +                listeners: {
> +                    close: () => me.reloadPrefixEntries(),
>                  },
>              });
>          },
> @@ -441,9 +358,6 @@ Ext.define('PVE.sdn.PrefixListPanel', {
>              border: false,
>              split: true,
>              reference: 'prefixListGrid',
> -            bind: {
> -                store: '{prefixLists}',
> -            },
>              listeners: {
>                  select: 'selectPrefixList',
>              },
> @@ -454,7 +368,6 @@ Ext.define('PVE.sdn.PrefixListPanel', {
>              border: false,
>              bind: {
>                  prefixList: '{prefixListGrid.selection}',
> -                store: '{prefixListEntries}',
>                  emptyText: '{entryGridEmptyText}',
>              },
>              reference: 'prefixListEntriesGrid',
> -- 
> 2.47.3





  reply	other threads:[~2026-05-11 16:12 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-11 13:36 [PATCH manager/network/proxmox{-ve-rs,-perl-rs} v8 00/25] Add support for route maps / prefix lists to SDN Stefan Hanreich
2026-05-11 13:36 ` [PATCH proxmox-ve-rs v8 01/25] sdn: prefix lists: refactor section config and api format Stefan Hanreich
2026-05-11 13:36 ` [PATCH proxmox-ve-rs v8 02/25] prefix lists: implement validation for prefix lists Stefan Hanreich
2026-05-11 13:36 ` [PATCH proxmox-perl-rs v8 03/25] sdn: prefix lists: refactor existing API endpoint Stefan Hanreich
2026-05-11 13:36 ` [PATCH proxmox-perl-rs v8 04/25] sdn: prefix lists: add crud methods for prefix list entries Stefan Hanreich
2026-05-11 13:36 ` [PATCH proxmox-perl-rs v8 05/25] sdn: prefix lists: validate prefix lists Stefan Hanreich
2026-05-11 13:36 ` [PATCH proxmox-perl-rs v8 06/25] sdn: route maps: add route map list method Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-network v8 07/25] tests: fix prefix list tests by including seq property Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-network v8 08/25] api: refactor route map api structure Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-network v8 09/25] api: refactor prefix list " Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 10/25] ui: sdn: add route map selector Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 11/25] ui: sdn: add prefix list selector Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 12/25] ui: sdn: add panel for managing prefix lists Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 13/25] ui: sdn: add panel for managing route map entries Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 14/25] ui: sdn: bgp controller: allow configuring route maps Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 15/25] ui: sdn: evpn " Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 16/25] ui: sdn: openfabric: add route filter Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 17/25] ui: sdn: ospf: add route filter setting Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 18/25] ui: sdn: prefix list: add missing subjects Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 19/25] sdn: do not fail rendering record data if pending property is missing Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 20/25] ui: sdn: prefix list: adapt to changed api structure Stefan Hanreich
2026-05-11 16:11   ` Lukas Sichert [this message]
2026-05-11 16:24     ` Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 21/25] ui: sdn: route maps: adapt to new route map " Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 22/25] ui: sdn: prefix lists: route maps: use integerfields for numbers Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 23/25] ui: sdn: prefix list panel: reload data on deleting prefix list entry Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 24/25] ui: prefix list panel: delete empty le and get properties Stefan Hanreich
2026-05-11 13:36 ` [PATCH pve-manager v8 25/25] ui: prefix list entry panel: make prefix required Stefan Hanreich
2026-05-12  1:51 ` applied: [PATCH manager/network/proxmox{-ve-rs,-perl-rs} v8 00/25] Add support for route maps / prefix lists to SDN Thomas Lamprecht
2026-05-12  8:22   ` Stefan Hanreich

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=DIFZ9TQGOAO2.1X0UKD75NI2WZ@proxmox.com \
    --to=l.sichert@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    --cc=s.hanreich@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