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
next prev parent 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