pve-manager/www/manager6/tree/DhcpTree.js
Stefan Hanreich 2989f3a9b8 sdn: ipam: fix editing custom mappings
Currently custom mappings cannot be edited, due to them having no VMID
value. The VMID parameter was always sent by the frontend to the
update call - even if it was empty - leading to validation failure on
the backend. Fix this by only sending the vmid parameter when it is
actually set.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
2024-07-22 18:37:32 +02:00

281 lines
5.4 KiB
JavaScript

Ext.define('PVE.sdn.DhcpTree', {
extend: 'Ext.tree.Panel',
xtype: 'pveDhcpTree',
layout: 'fit',
rootVisible: false,
animate: false,
store: {
sorters: ['ip', 'name'],
},
controller: {
xclass: 'Ext.app.ViewController',
reload: function() {
let me = this;
Proxmox.Utils.API2Request({
url: `/cluster/sdn/ipams/pve/status`,
method: 'GET',
success: function(response, opts) {
let root = {
name: '__root',
expanded: true,
children: [],
};
let zones = {};
let vnets = {};
let subnets = {};
response.result.data.forEach((element) => {
element.leaf = true;
if (!(element.zone in zones)) {
let zone = {
name: element.zone,
type: 'zone',
iconCls: 'fa fa-th',
expanded: true,
children: [],
};
zones[element.zone] = zone;
root.children.push(zone);
}
if (!(element.vnet in vnets)) {
let vnet = {
name: element.vnet,
zone: element.zone,
type: 'vnet',
iconCls: 'fa fa-network-wired x-fa-treepanel',
expanded: true,
children: [],
};
vnets[element.vnet] = vnet;
zones[element.zone].children.push(vnet);
}
if (!(element.subnet in subnets)) {
let subnet = {
name: element.subnet,
zone: element.zone,
vnet: element.vnet,
type: 'subnet',
iconCls: 'x-tree-icon-none',
expanded: true,
children: [],
};
subnets[element.subnet] = subnet;
vnets[element.vnet].children.push(subnet);
}
element.type = 'mapping';
element.iconCls = 'x-tree-icon-none';
subnets[element.subnet].children.push(element);
});
me.getView().setRootNode(root);
},
});
},
init: function(view) {
let me = this;
me.reload();
},
onDelete: function(table, rI, cI, item, e, { data }) {
let me = this;
let view = me.getView();
Ext.Msg.show({
title: gettext('Confirm'),
icon: Ext.Msg.WARNING,
message: Ext.String.format(gettext('Are you sure you want to remove DHCP mapping {0}'), `${data.mac} / ${data.ip}`),
buttons: Ext.Msg.YESNO,
defaultFocus: 'no',
callback: function(btn) {
if (btn !== 'yes') {
return;
}
let params = {
zone: data.zone,
mac: data.mac,
ip: data.ip,
};
let encodedParams = Ext.Object.toQueryString(params);
let url = `/cluster/sdn/vnets/${data.vnet}/ips?${encodedParams}`;
Proxmox.Utils.API2Request({
url,
method: 'DELETE',
waitMsgTarget: view,
failure: function(response, opts) {
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
},
callback: me.reload.bind(me),
});
},
});
},
editAction: function(_grid, _rI, _cI, _item, _e, rec) {
this.edit(rec);
},
editDblClick: function() {
let me = this;
let view = me.getView();
let selection = view.getSelection();
if (!selection || selection.length < 1) {
return;
}
me.edit(selection[0]);
},
edit: function(rec) {
let me = this;
if (rec.data.type === 'mapping' && !rec.data.gateway) {
me.openEditWindow(rec.data);
}
},
openEditWindow: function(data) {
let me = this;
let extraRequestParams = {
mac: data.mac,
zone: data.zone,
vnet: data.vnet,
};
if (data.vmid) {
extraRequestParams.vmid = data.vmid;
}
Ext.create('PVE.sdn.IpamEdit', {
autoShow: true,
mapping: data,
extraRequestParams,
listeners: {
destroy: () => me.reload(),
},
});
},
},
listeners: {
itemdblclick: 'editDblClick',
},
tbar: [
{
xtype: 'proxmoxButton',
text: gettext('Reload'),
handler: 'reload',
},
],
columns: [
{
xtype: 'treecolumn',
text: gettext('Name / VMID'),
dataIndex: 'name',
width: 200,
renderer: function(value, meta, record) {
if (record.get('gateway')) {
return gettext('Gateway');
}
return record.get('name') ?? record.get('vmid') ?? ' ';
},
},
{
text: gettext('IP Address'),
dataIndex: 'ip',
width: 200,
},
{
text: 'MAC',
dataIndex: 'mac',
width: 200,
},
{
text: gettext('Gateway'),
dataIndex: 'gateway',
width: 200,
},
{
header: gettext('Actions'),
xtype: 'actioncolumn',
dataIndex: 'text',
width: 150,
items: [
{
handler: function(table, rI, cI, item, e, { data }) {
let me = this;
Ext.create('PVE.sdn.IpamEdit', {
autoShow: true,
mapping: {},
isCreate: true,
extraRequestParams: {
vnet: data.name,
zone: data.zone,
},
listeners: {
destroy: () => {
me.up('pveDhcpTree').controller.reload();
},
},
});
},
getTip: (v, m, rec) => gettext('Add'),
getClass: (v, m, { data }) => {
if (data.type === 'vnet') {
return 'fa fa-plus-square';
}
return 'pmx-hidden';
},
},
{
handler: 'editAction',
getTip: (v, m, rec) => gettext('Edit'),
getClass: (v, m, { data }) => {
if (data.type === 'mapping' && !data.gateway) {
return 'fa fa-pencil fa-fw';
}
return 'pmx-hidden';
},
},
{
handler: 'onDelete',
getTip: (v, m, rec) => gettext('Delete'),
getClass: (v, m, { data }) => {
if (data.type === 'mapping' && !data.gateway) {
return 'fa critical fa-trash-o';
}
return 'pmx-hidden';
},
},
],
},
],
});