[pve-devel] [PATCH pve-manager 10/11] sdn: add fabric edit/delete forms
Gabriel Goller
g.goller at proxmox.com
Fri Feb 14 14:39:50 CET 2025
Add the add/edit/delete modals for the FabricsView. This allows us to
create, edit, and delete fabrics, nodes, and interfaces.
Co-authored-by: Stefan Hanreich <s.hanreich at proxmox.com>
Signed-off-by: Gabriel Goller <g.goller at proxmox.com>
---
www/manager6/sdn/fabrics/Common.js | 222 ++++++++++++++++++
.../sdn/fabrics/openfabric/FabricEdit.js | 67 ++++++
.../sdn/fabrics/openfabric/InterfaceEdit.js | 92 ++++++++
.../sdn/fabrics/openfabric/NodeEdit.js | 187 +++++++++++++++
www/manager6/sdn/fabrics/ospf/FabricEdit.js | 60 +++++
.../sdn/fabrics/ospf/InterfaceEdit.js | 46 ++++
www/manager6/sdn/fabrics/ospf/NodeEdit.js | 191 +++++++++++++++
7 files changed, 865 insertions(+)
create mode 100644 www/manager6/sdn/fabrics/Common.js
create mode 100644 www/manager6/sdn/fabrics/openfabric/FabricEdit.js
create mode 100644 www/manager6/sdn/fabrics/openfabric/InterfaceEdit.js
create mode 100644 www/manager6/sdn/fabrics/openfabric/NodeEdit.js
create mode 100644 www/manager6/sdn/fabrics/ospf/FabricEdit.js
create mode 100644 www/manager6/sdn/fabrics/ospf/InterfaceEdit.js
create mode 100644 www/manager6/sdn/fabrics/ospf/NodeEdit.js
diff --git a/www/manager6/sdn/fabrics/Common.js b/www/manager6/sdn/fabrics/Common.js
new file mode 100644
index 000000000000..72ec093fc928
--- /dev/null
+++ b/www/manager6/sdn/fabrics/Common.js
@@ -0,0 +1,222 @@
+Ext.define('PVE.sdn.Fabric.InterfacePanel', {
+ extend: 'Ext.grid.Panel',
+ mixins: ['Ext.form.field.Field'],
+
+ network_interfaces: undefined,
+
+ selectionChange: function(_grid, _selection) {
+ let me = this;
+ me.value = me.getSelection().map((rec) => {
+ delete rec.data.cidr;
+ delete rec.data.cidr6;
+ delete rec.data.selected;
+ return PVE.Parser.printPropertyString(rec.data);
+ });
+ me.checkChange();
+ },
+
+ getValue: function() {
+ let me = this;
+ return me.value ?? [];
+ },
+
+ setValue: function(value) {
+ let me = this;
+
+ value ??= [];
+
+ me.updateSelectedInterfaces(value);
+
+ return me.mixins.field.setValue.call(me, value);
+ },
+
+ addInterfaces: function(fabric_interfaces) {
+ let me = this;
+ if (me.network_interfaces) {
+ let node_interfaces = me.network_interfaces
+ //.filter((elem) => elem.type === 'eth')
+ .map((elem) => {
+ const obj = {
+ name: elem.iface,
+ cidr: elem.cidr,
+ cidr6: elem.cidr6,
+ };
+ return obj;
+ });
+
+ if (fabric_interfaces) {
+ node_interfaces = node_interfaces.map(i => {
+ let elem = fabric_interfaces.find(j => j.name === i.name);
+ return Object.assign(i, elem);
+ });
+ let store = me.getStore();
+ store.setData(node_interfaces);
+ } else {
+ let store = me.getStore();
+ store.setData(node_interfaces);
+ }
+ } else if (fabric_interfaces) {
+ // We could not get the available interfaces of the node, so we display the configured ones only.
+ let interfaces = fabric_interfaces.map((elem) => {
+ const obj = {
+ name: elem.name,
+ cidr: 'unknown',
+ cidr6: 'unknown',
+ ...elem,
+ };
+ return obj;
+ });
+
+ let store = me.getStore();
+ store.setData(interfaces);
+ } else {
+ console.warn("no fabric_interfaces and cluster_interfaces available!");
+ }
+ },
+
+ updateSelectedInterfaces: function(values) {
+ let me = this;
+ if (values) {
+ let recs = [];
+ let store = me.getStore();
+
+ for (const i of values) {
+ let rec = store.getById(i.name);
+ if (rec) {
+ recs.push(rec);
+ }
+ }
+ me.suspendEvent('change');
+ me.setSelection();
+ me.setSelection(recs);
+ me.resumeEvent('change');
+ } else {
+ me.suspendEvent('change');
+ me.setSelection();
+ me.resumeEvent('change');
+ }
+ },
+
+ setNetworkInterfaces: function(network_interfaces) {
+ this.network_interfaces = network_interfaces;
+ },
+
+ getSubmitData: function() {
+ let records = this.getSelection().map((record) => {
+ // we don't need the cidr, cidr6, and selected parameters
+ delete record.data.cidr;
+ delete record.data.cidr6;
+ delete record.data.selected;
+ return Proxmox.Utils.printPropertyString(record.data);
+ });
+ return {
+ 'interfaces': records,
+ };
+ },
+
+ controller: {
+ onValueChange: function(field, value) {
+ let me = this;
+ let record = field.getWidgetRecord();
+ let column = field.getWidgetColumn();
+ if (record) {
+ record.set(column.dataIndex, value);
+ record.commit();
+
+ me.getView().checkChange();
+ me.getView().selectionChange();
+ }
+ },
+
+ control: {
+ 'field': {
+ change: 'onValueChange',
+ },
+ },
+ },
+
+ selModel: {
+ type: 'checkboxmodel',
+ mode: 'SIMPLE',
+ },
+
+ listeners: {
+ selectionchange: function() {
+ this.selectionChange(...arguments);
+ },
+ },
+
+ commonColumns: [
+ {
+ text: gettext('Name'),
+ dataIndex: 'name',
+ flex: 2,
+ },
+ {
+ text: gettext('IPv4'),
+ dataIndex: 'cidr',
+ flex: 2,
+ },
+ {
+ text: gettext('IPv6'),
+ dataIndex: 'cidr6',
+ flex: 2,
+ },
+ ],
+
+ additionalColumns: [],
+
+ initComponent: function() {
+ let me = this;
+
+ Ext.apply(me, {
+ store: Ext.create("Ext.data.Store", {
+ model: "Pve.sdn.Interface",
+ sorters: {
+ property: 'name',
+ direction: 'ASC',
+ },
+ }),
+ columns: me.commonColumns.concat(me.additionalColumns),
+ });
+
+ me.callParent();
+
+ Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
+ me.initField();
+ },
+});
+
+
+Ext.define('Pve.sdn.Fabric', {
+ extend: 'Ext.data.Model',
+ idProperty: 'name',
+ fields: [
+ 'name',
+ 'type',
+ ],
+});
+
+Ext.define('Pve.sdn.Node', {
+ extend: 'Ext.data.Model',
+ idProperty: 'name',
+ fields: [
+ 'name',
+ 'fabric',
+ 'type',
+ ],
+});
+
+Ext.define('Pve.sdn.Interface', {
+ extend: 'Ext.data.Model',
+ idProperty: 'name',
+ fields: [
+ 'name',
+ 'cidr',
+ 'cidr6',
+ 'passive',
+ 'hello_interval',
+ 'hello_multiplier',
+ 'csnp_interval',
+ ],
+});
diff --git a/www/manager6/sdn/fabrics/openfabric/FabricEdit.js b/www/manager6/sdn/fabrics/openfabric/FabricEdit.js
new file mode 100644
index 000000000000..0431a00e7302
--- /dev/null
+++ b/www/manager6/sdn/fabrics/openfabric/FabricEdit.js
@@ -0,0 +1,67 @@
+Ext.define('PVE.sdn.Fabric.OpenFabric.Fabric.Edit', {
+ extend: 'Proxmox.window.Edit',
+ xtype: 'pveSDNOpenFabricRouteEdit',
+
+ subject: gettext('Add OpenFabric'),
+
+ url: '/cluster/sdn/fabrics/openfabric',
+ type: 'openfabric',
+
+ isCreate: undefined,
+
+ viewModel: {
+ data: {
+ isCreate: true,
+ },
+ },
+
+ items: [
+ {
+ xtype: 'textfield',
+ name: 'type',
+ value: 'openfabric',
+ allowBlank: false,
+ hidden: true,
+ },
+ {
+ xtype: 'textfield',
+ fieldLabel: gettext('Name'),
+ labelWidth: 120,
+ name: 'name',
+ allowBlank: false,
+ bind: {
+ disabled: '{!isCreate}',
+ },
+ },
+ {
+ xtype: 'numberfield',
+ fieldLabel: gettext('Hello Interval'),
+ labelWidth: 120,
+ name: 'hello_interval',
+ allowBlank: true,
+ },
+ ],
+
+ submitUrl: function(url, values) {
+ let me = this;
+ return `${me.url}`;
+ },
+
+ initComponent: function() {
+ let me = this;
+
+ let view = me.getViewModel();
+ view.set('isCreate', me.isCreate);
+
+ me.method = me.isCreate ? 'POST' : 'PUT';
+ me.callParent();
+
+ if (!me.isCreate) {
+ me.load({
+ success: function(response, opts) {
+ me.setValues(response.result.data.fabric);
+ },
+ });
+ }
+ },
+});
diff --git a/www/manager6/sdn/fabrics/openfabric/InterfaceEdit.js b/www/manager6/sdn/fabrics/openfabric/InterfaceEdit.js
new file mode 100644
index 000000000000..ef33c16b784f
--- /dev/null
+++ b/www/manager6/sdn/fabrics/openfabric/InterfaceEdit.js
@@ -0,0 +1,92 @@
+Ext.define('PVE.sdn.Fabric.OpenFabric.Interface.Edit', {
+ extend: 'Proxmox.window.Edit',
+ xtype: 'pveSDNOpenFabricInterfaceEdit',
+
+ initComponent: function() {
+ let me = this;
+
+ Ext.apply(me, {
+ items: [{
+ xtype: 'inputpanel',
+ items: [
+ {
+ xtype: 'textfield',
+ fieldLabel: gettext('Interface'),
+ name: 'name',
+ disabled: true,
+ },
+ {
+ xtype: 'proxmoxcheckbox',
+ fieldLabel: gettext('Passive'),
+ name: 'passive',
+ uncheckedValue: 0,
+ },
+ {
+ xtype: 'numberfield',
+ fieldLabel: gettext('Hello Interval'),
+ name: 'hello_interval',
+ allowBlank: true,
+ },
+ {
+ xtype: 'numberfield',
+ fieldLabel: gettext('Hello Multiplier'),
+ name: 'hello_multiplier',
+ allowBlank: true,
+ },
+ {
+ xtype: 'numberfield',
+ fieldLabel: gettext('CSNP Interval'),
+ name: 'csnp_interval',
+ allowBlank: true,
+ },
+ ],
+ }],
+ });
+
+ me.callParent();
+ },
+});
+
+Ext.define('PVE.sdn.Fabric.OpenFabric.InterfacePanel', {
+ extend: 'PVE.sdn.Fabric.InterfacePanel',
+
+ additionalColumns: [
+ {
+ text: gettext('Passive'),
+ xtype: 'widgetcolumn',
+ dataIndex: 'passive',
+ flex: 1,
+ widget: {
+ xtype: 'checkbox',
+ },
+ },
+ {
+ text: gettext('Hello Interval'),
+ xtype: 'widgetcolumn',
+ dataIndex: 'hello_interval',
+ flex: 1,
+ widget: {
+ xtype: 'numberfield',
+ },
+ },
+ {
+ text: gettext('Hello Multiplier'),
+ xtype: 'widgetcolumn',
+ dataIndex: 'hello_multiplier',
+ flex: 1,
+ widget: {
+ xtype: 'numberfield',
+ },
+ },
+ {
+ text: gettext('CSNP Interval'),
+ xtype: 'widgetcolumn',
+ dataIndex: 'csnp_interval',
+ flex: 1,
+ widget: {
+ xtype: 'numberfield',
+ },
+ },
+ ],
+});
+
diff --git a/www/manager6/sdn/fabrics/openfabric/NodeEdit.js b/www/manager6/sdn/fabrics/openfabric/NodeEdit.js
new file mode 100644
index 000000000000..ce61f0c15b49
--- /dev/null
+++ b/www/manager6/sdn/fabrics/openfabric/NodeEdit.js
@@ -0,0 +1,187 @@
+Ext.define('PVE.sdn.Fabric.OpenFabric.Node.InputPanel', {
+ extend: 'Proxmox.panel.InputPanel',
+
+ viewModel: {},
+
+ isCreate: undefined,
+ loadClusterInterfaces: undefined,
+
+ interface_selector: undefined,
+ node_not_accessible_warning: undefined,
+
+ onSetValues: function(values) {
+ let me = this;
+ me.interface_selector.setNetworkInterfaces(values.network_interfaces);
+ if (values.node) {
+ // this means we are in edit mode and we have a config
+ me.interface_selector.addInterfaces(values.node.interface);
+ me.interface_selector.updateSelectedInterfaces(values.node.interface);
+ return { node: values.node.node, net: values.node.net, interfaces: values.node.interface };
+ } else {
+ // this means we are in create mode, so don't select any interfaces
+ me.interface_selector.addInterfaces(null);
+ me.interface_selector.updateSelectedInterfaces(null);
+ return {};
+ }
+ },
+
+ initComponent: function() {
+ let me = this;
+ me.items = [
+ {
+ xtype: 'pveNodeSelector',
+ reference: 'nodeselector',
+ fieldLabel: gettext('Node'),
+ labelWidth: 120,
+ name: 'node',
+ allowBlank: false,
+ disabled: !me.isCreate,
+ onlineValidator: me.isCreate,
+ autoSelect: me.isCreate,
+ listeners: {
+ change: function(f, value) {
+ if (me.isCreate) {
+ me.loadClusterInterfaces(value, (result) => {
+ me.setValues({ network_interfaces: result });
+ });
+ }
+ },
+ },
+ listConfig: {
+ columns: [
+ {
+ header: gettext('Node'),
+ dataIndex: 'node',
+ sortable: true,
+ hideable: false,
+ flex: 1,
+ },
+ ],
+ },
+
+ },
+ me.node_not_accessible_warning,
+ {
+ xtype: 'textfield',
+ fieldLabel: gettext('Net'),
+ labelWidth: 120,
+ name: 'net',
+ allowBlank: false,
+ },
+ me.interface_selector,
+ ];
+ me.callParent();
+ },
+});
+
+Ext.define('PVE.sdn.Fabric.OpenFabric.Node.Edit', {
+ extend: 'Proxmox.window.Edit',
+ xtype: 'pveSDNFabricAddNode',
+
+ width: 800,
+
+ // dummyurl
+ url: '/cluster/sdn/fabrics/openfabric',
+
+ interface_selector: undefined,
+ isCreate: undefined,
+
+ controller: {
+ xclass: 'Ext.app.ViewController',
+ },
+
+ submitUrl: function(url, values) {
+ let me = this;
+ return `${me.url}/${me.extraRequestParams.fabric}/node/${values.node}`;
+ },
+
+ loadClusterInterfaces: function(node, onSuccess) {
+ Proxmox.Utils.API2Request({
+ url: `/api2/extjs/nodes/${node}/network`,
+ method: 'GET',
+ success: function(response, _opts) {
+ onSuccess(response.result.data);
+ },
+ // No failure callback because this api call can't fail, it
+ // just hangs the request :) (if the node doesn't exist it gets proxied)
+ });
+ },
+ loadFabricInterfaces: function(fabric, node, onSuccess, onFailure) {
+ Proxmox.Utils.API2Request({
+ url: `/cluster/sdn/fabrics/openfabric/${fabric}/node/${node}`,
+ method: 'GET',
+ success: function(response, _opts) {
+ onSuccess(response.result.data);
+ },
+ failure: onFailure,
+ });
+ },
+ loadAllAvailableNodes: function(onSuccess) {
+ Proxmox.Utils.API2Request({
+ url: `/cluster/config/nodes`,
+ method: 'GET',
+ success: function(response, _opts) {
+ onSuccess(response.result.data);
+ },
+ });
+ },
+
+ initComponent: function() {
+ let me = this;
+
+ me.interface_selector = Ext.create('PVE.sdn.Fabric.OpenFabric.InterfacePanel', {
+ name: 'interfaces',
+ });
+
+ me.node_not_accessible_warning = Ext.create('Proxmox.form.field.DisplayEdit', {
+ userCls: 'pmx-hint',
+ value: gettext('The node is not accessible.'),
+ hidden: true,
+ });
+
+ let ipanel = Ext.create('PVE.sdn.Fabric.OpenFabric.Node.InputPanel', {
+ interface_selector: me.interface_selector,
+ node_not_accessible_warning: me.node_not_accessible_warning,
+ isCreate: me.isCreate,
+ loadClusterInterfaces: me.loadClusterInterfaces,
+ });
+
+ Ext.apply(me, {
+ subject: gettext('Node'),
+ items: [ipanel],
+ });
+
+ me.callParent();
+
+ if (!me.isCreate) {
+ me.loadAllAvailableNodes((allNodes) => {
+ if (allNodes.some(i => i.name === me.node)) {
+ me.loadClusterInterfaces(me.node, (clusterResult) => {
+ me.loadFabricInterfaces(me.fabric, me.node, (fabricResult) => {
+ fabricResult.node.interface = fabricResult.node.interface
+ .map(i => PVE.Parser.parsePropertyString(i));
+ fabricResult.network_interfaces = clusterResult;
+ // this will also set them as selected
+ ipanel.setValues(fabricResult);
+ });
+ });
+ } else {
+ me.node_not_accessible_warning.setHidden(false);
+ // If the node is not currently in the cluster and not available (we can't get it's interfaces).
+ me.loadFabricInterfaces(me.fabric, me.node, (fabricResult) => {
+ fabricResult.node.interface = fabricResult.node.interface
+ .map(i => PVE.Parser.parsePropertyString(i));
+ ipanel.setValues(fabricResult);
+ });
+ }
+ });
+ }
+
+ if (me.isCreate) {
+ me.method = 'POST';
+ } else {
+ me.method = 'PUT';
+ }
+ },
+});
+
diff --git a/www/manager6/sdn/fabrics/ospf/FabricEdit.js b/www/manager6/sdn/fabrics/ospf/FabricEdit.js
new file mode 100644
index 000000000000..2ce88e443cdd
--- /dev/null
+++ b/www/manager6/sdn/fabrics/ospf/FabricEdit.js
@@ -0,0 +1,60 @@
+Ext.define('PVE.sdn.Fabric.Ospf.Fabric.Edit', {
+ extend: 'Proxmox.window.Edit',
+ xtype: 'pveSDNOpenFabricRouteEdit',
+
+ subject: gettext('Add OSPF'),
+
+ url: '/cluster/sdn/fabrics/ospf',
+ type: 'ospf',
+
+ isCreate: undefined,
+
+ viewModel: {
+ data: {
+ isCreate: true,
+ },
+ },
+
+ items: [
+ {
+ xtype: 'textfield',
+ name: 'type',
+ value: 'ospf',
+ allowBlank: false,
+ hidden: true,
+ },
+ {
+ xtype: 'textfield',
+ fieldLabel: gettext('Area'),
+ labelWidth: 120,
+ name: 'name',
+ allowBlank: false,
+ bind: {
+ disabled: '{!isCreate}',
+ },
+ },
+ ],
+
+ submitUrl: function(url, values) {
+ let me = this;
+ return `${me.url}`;
+ },
+
+ initComponent: function() {
+ let me = this;
+
+ let view = me.getViewModel();
+ view.set('isCreate', me.isCreate);
+
+ me.method = me.isCreate ? 'POST' : 'PUT';
+
+ me.callParent();
+ if (!me.isCreate) {
+ me.load({
+ success: function(response, opts) {
+ me.setValues(response.result.data.fabric);
+ },
+ });
+ }
+ },
+});
diff --git a/www/manager6/sdn/fabrics/ospf/InterfaceEdit.js b/www/manager6/sdn/fabrics/ospf/InterfaceEdit.js
new file mode 100644
index 000000000000..e7810b3f34c9
--- /dev/null
+++ b/www/manager6/sdn/fabrics/ospf/InterfaceEdit.js
@@ -0,0 +1,46 @@
+Ext.define('PVE.sdn.Fabric.Ospf.Interface.Edit', {
+ extend: 'Proxmox.window.Edit',
+ xtype: 'pveSDNOspfInterfaceEdit',
+
+ initComponent: function() {
+ let me = this;
+
+ Ext.apply(me, {
+ items: [{
+ xtype: 'inputpanel',
+ items: [
+ {
+ xtype: 'textfield',
+ fieldLabel: gettext('Interface'),
+ name: 'name',
+ disabled: true,
+ },
+ {
+ xtype: 'proxmoxcheckbox',
+ fieldLabel: gettext('Passive'),
+ name: 'passive',
+ uncheckedValue: 0,
+ },
+ ],
+ }],
+ });
+
+ me.callParent();
+ },
+});
+
+Ext.define('PVE.sdn.Fabric.Ospf.InterfacePanel', {
+ extend: 'PVE.sdn.Fabric.InterfacePanel',
+
+ additionalColumns: [
+ {
+ text: gettext('Passive'),
+ xtype: 'widgetcolumn',
+ dataIndex: 'passive',
+ flex: 1,
+ widget: {
+ xtype: 'checkbox',
+ },
+ },
+ ],
+});
diff --git a/www/manager6/sdn/fabrics/ospf/NodeEdit.js b/www/manager6/sdn/fabrics/ospf/NodeEdit.js
new file mode 100644
index 000000000000..41778e930bfb
--- /dev/null
+++ b/www/manager6/sdn/fabrics/ospf/NodeEdit.js
@@ -0,0 +1,191 @@
+Ext.define('PVE.sdn.Fabric.Ospf.Node.InputPanel', {
+ extend: 'Proxmox.panel.InputPanel',
+
+ viewModel: {},
+
+ isCreate: undefined,
+ loadClusterInterfaces: undefined,
+
+ interface_selector: undefined,
+ node_not_accessible_warning: undefined,
+
+ onSetValues: function(values) {
+ let me = this;
+ me.interface_selector.setNetworkInterfaces(values.network_interfaces);
+ if (values.node) {
+ // this means we are in edit mode and we have a config
+ me.interface_selector.addInterfaces(values.node.interface);
+ me.interface_selector.updateSelectedInterfaces(values.node.interface);
+ return {
+ node: values.node.node,
+ router_id: values.node.router_id,
+ interfaces: values.node.interface,
+ };
+ } else {
+ // this means we are in create mode, so don't select any interfaces
+ me.interface_selector.addInterfaces(null);
+ me.interface_selector.updateSelectedInterfaces(null);
+ return {};
+ }
+ },
+
+ initComponent: function() {
+ let me = this;
+ me.items = [
+ {
+ xtype: 'pveNodeSelector',
+ reference: 'nodeselector',
+ fieldLabel: gettext('Node'),
+ labelWidth: 120,
+ name: 'node',
+ allowBlank: false,
+ disabled: !me.isCreate,
+ onlineValidator: me.isCreate,
+ autoSelect: me.isCreate,
+ listeners: {
+ change: function(f, value) {
+ if (me.isCreate) {
+ me.loadClusterInterfaces(value, (result) => {
+ me.setValues({ network_interfaces: result });
+ });
+ }
+ },
+ },
+ listConfig: {
+ columns: [
+ {
+ header: gettext('Node'),
+ dataIndex: 'node',
+ sortable: true,
+ hideable: false,
+ flex: 1,
+ },
+ ],
+ },
+
+ },
+ me.node_not_accessible_warning,
+ {
+ xtype: 'textfield',
+ fieldLabel: gettext('Router-Id'),
+ labelWidth: 120,
+ name: 'router_id',
+ allowBlank: false,
+ },
+ me.interface_selector,
+ ];
+ me.callParent();
+ },
+});
+
+Ext.define('PVE.sdn.Fabric.Ospf.Node.Edit', {
+ extend: 'Proxmox.window.Edit',
+ xtype: 'pveSDNFabricAddNode',
+
+ width: 800,
+
+ // dummyurl
+ url: '/cluster/sdn/fabrics/ospf',
+
+ interface_selector: undefined,
+ isCreate: undefined,
+
+ controller: {
+ xclass: 'Ext.app.ViewController',
+ },
+
+ submitUrl: function(url, values) {
+ let me = this;
+ return `${me.url}/${me.extraRequestParams.fabric}/node/${values.node}`;
+ },
+
+ loadClusterInterfaces: function(node, onSuccess) {
+ Proxmox.Utils.API2Request({
+ url: `/api2/extjs/nodes/${node}/network`,
+ method: 'GET',
+ success: function(response, _opts) {
+ onSuccess(response.result.data);
+ },
+ // No failure callback because this api call can't fail, it
+ // just hangs the request :) (if the node doesn't exist it gets proxied)
+ });
+ },
+ loadFabricInterfaces: function(fabric, node, onSuccess, onFailure) {
+ Proxmox.Utils.API2Request({
+ url: `/cluster/sdn/fabrics/ospf/${fabric}/node/${node}`,
+ method: 'GET',
+ success: function(response, _opts) {
+ onSuccess(response.result.data);
+ },
+ failure: onFailure,
+ });
+ },
+ loadAllAvailableNodes: function(onSuccess) {
+ Proxmox.Utils.API2Request({
+ url: `/cluster/config/nodes`,
+ method: 'GET',
+ success: function(response, _opts) {
+ onSuccess(response.result.data);
+ },
+ });
+ },
+
+ initComponent: function() {
+ let me = this;
+
+ me.interface_selector = Ext.create('PVE.sdn.Fabric.Ospf.InterfacePanel', {
+ name: 'interfaces',
+ });
+
+ me.node_not_accessible_warning = Ext.create('Proxmox.form.field.DisplayEdit', {
+ userCls: 'pmx-hint',
+ value: gettext('The node is not accessible.'),
+ hidden: true,
+ });
+
+
+ let ipanel = Ext.create('PVE.sdn.Fabric.Ospf.Node.InputPanel', {
+ interface_selector: me.interface_selector,
+ node_not_accessible_warning: me.node_not_accessible_warning,
+ isCreate: me.isCreate,
+ loadClusterInterfaces: me.loadClusterInterfaces,
+ });
+
+ Ext.apply(me, {
+ subject: gettext('Node'),
+ items: [ipanel],
+ });
+
+ me.callParent();
+
+ if (!me.isCreate) {
+ me.loadAllAvailableNodes((allNodes) => {
+ if (allNodes.some(i => i.name === me.node)) {
+ me.loadClusterInterfaces(me.node, (clusterResult) => {
+ me.loadFabricInterfaces(me.fabric, me.node, (fabricResult) => {
+ fabricResult.node.interface = fabricResult.node.interface
+ .map(i => PVE.Parser.parsePropertyString(i));
+ fabricResult.network_interfaces = clusterResult;
+ // this will also set them as selected
+ ipanel.setValues(fabricResult);
+ });
+ });
+ } else {
+ me.node_not_accessible_warning.setHidden(false);
+ // If the node is not currently in the cluster and not available (we can't get it's interfaces).
+ me.loadFabricInterfaces(me.fabric, me.node, (fabricResult) => {
+ fabricResult.node.interface = fabricResult.node.interface
+ .map(i => PVE.Parser.parsePropertyString(i));
+ ipanel.setValues(fabricResult);
+ });
+ }
+ });
+ }
+
+ if (me.isCreate) {
+ me.method = 'POST';
+ } else {
+ me.method = 'PUT';
+ }
+ },
+});
--
2.39.5
More information about the pve-devel
mailing list