});
},
- addHost: function() {
+ add: function(_grid, _rI, _cI, _item, _e, rec) {
let me = this;
- me.edit(false);
+ if (rec.data.type !== 'entry') {
+ return;
+ }
+
+ me.openMapEditWindow(rec.data.name);
},
- edit: function(includeNodename = true) {
+ editDblClick: function() {
let me = this;
let view = me.getView();
let selection = view.getSelection();
- if (!selection || !selection.length) {
+ if (!selection || selection.length < 1) {
return;
}
- let rec = selection[0];
- if (!view.canConfigure || (rec.data.type === 'entry' && includeNodename)) {
+
+ me.edit(selection[0]);
+ },
+
+ editAction: function(_grid, _rI, _cI, _item, _e, rec) {
+ this.edit(rec);
+ },
+
+ edit: function(rec) {
+ let me = this;
+ if (rec.data.type === 'map') {
return;
}
+ me.openMapEditWindow(rec.data.name, rec.data.node, rec.data.type === 'entry');
+ },
+
+ openMapEditWindow: function(name, nodename, entryOnly) {
+ let me = this;
+ let view = me.getView();
+
Ext.create(view.editWindowClass, {
- url: `${view.baseUrl}/${rec.data.name}`,
+ url: `${view.baseUrl}/${name}`,
autoShow: true,
autoLoad: true,
- nodename: includeNodename ? rec.data.node : undefined,
- name: rec.data.name,
+ entryOnly,
+ nodename,
+ name,
listeners: {
destroy: () => me.load(),
},
});
},
- remove: function() {
+ remove: function(_grid, _rI, _cI, _item, _e, rec) {
let me = this;
+ let msg, id;
let view = me.getView();
- let selection = view.getSelection();
- if (!selection || !selection.length) {
- return;
+ let confirmMsg;
+ switch (rec.data.type) {
+ case 'entry':
+ msg = gettext("Are you sure you want to remove '{0}'");
+ confirmMsg = Ext.String.format(msg, rec.data.name);
+ break;
+ case 'node':
+ msg = gettext("Are you sure you want to remove '{0}' entries for '{1}'");
+ confirmMsg = Ext.String.format(msg, rec.data.node, rec.data.name);
+ break;
+ case 'map':
+ msg = gettext("Are you sure you want to remove '{0}' on '{1}' for '{2}'");
+ id = rec.data[view.entryIdProperty];
+ confirmMsg = Ext.String.format(msg, id, rec.data.node, rec.data.name);
+ break;
+ default:
+ throw "invalid type";
}
+ Ext.Msg.confirm(gettext('Confirm'), confirmMsg, function(btn) {
+ if (btn === 'yes') {
+ me.executeRemove(rec.data);
+ }
+ });
+ },
+
+ executeRemove: function(data) {
+ let me = this;
+ let view = me.getView();
- let data = selection[0].data;
let url = `${view.baseUrl}/${data.name}`;
let method = 'PUT';
let params = {
return `<i class="fa ${iconCls}"></i> ${status}`;
},
+ getAddClass: function(v, mD, rec) {
+ let cls = 'fa fa-plus-circle';
+ if (rec.data.type !== 'entry' || rec.data.children?.length >= PVE.data.ResourceStore.getNodes().length) {
+ cls += ' pmx-action-hidden';
+ }
+ return cls;
+ },
+
+ isAddDisabled: function(v, r, c, i, rec) {
+ return rec.data.type !== 'entry' || rec.data.children?.length >= PVE.data.ResourceStore.getNodes().length;
+ },
+
init: function(view) {
let me = this;
tbar: [
{
- text: gettext('Add mapping'),
+ text: gettext('Add'),
handler: 'addMapping',
cbind: {
disabled: '{!canConfigure}',
},
},
- {
- xtype: 'proxmoxButton',
- text: gettext('New Host mapping'),
- disabled: true,
- parentXType: 'treepanel',
- enableFn: function(_rec) {
- return this.up('treepanel').canConfigure;
- },
- handler: 'addHost',
- },
- {
- xtype: 'proxmoxButton',
- text: gettext('Edit'),
- disabled: true,
- parentXType: 'treepanel',
- enableFn: function(rec) {
- return rec && rec.data.type !== 'entry' && this.up('treepanel').canConfigure;
- },
- handler: 'edit',
- },
- {
- xtype: 'proxmoxButton',
- parentXType: 'treepanel',
- handler: 'remove',
- disabled: true,
- text: gettext('Remove'),
- enableFn: function(rec) {
- return rec && this.up('treepanel').canConfigure;
- },
- confirmMsg: function(rec) {
- let msg, id;
- let view = this.up('treepanel');
- switch (rec.data.type) {
- case 'entry':
- msg = gettext("Are you sure you want to remove '{0}'");
- return Ext.String.format(msg, rec.data.name);
- case 'node':
- msg = gettext("Are you sure you want to remove '{0}' entries for '{1}'");
- return Ext.String.format(msg, rec.data.node, rec.data.name);
- case 'map':
- msg = gettext("Are you sure you want to remove '{0}' on '{1}' for '{2}'");
- id = rec.data[view.entryIdProperty];
- return Ext.String.format(msg, id, rec.data.node, rec.data.name);
- default:
- throw "invalid type";
- }
- },
- },
],
listeners: {
- itemdblclick: 'edit',
+ itemdblclick: 'editDblClick',
+ },
+
+ initComponent: function() {
+ let me = this;
+
+ let columns = [...me.columns];
+ columns.splice(1, 0, {
+ xtype: 'actioncolumn',
+ text: gettext('Actions'),
+ width: 80,
+ items: [
+ {
+ getTip: (v, m, { data }) =>
+ Ext.String.format(gettext("Add new host mapping for '{0}'"), data.name),
+ getClass: 'getAddClass',
+ isActionDisabled: 'isAddDisabled',
+ handler: 'add',
+ },
+ {
+ iconCls: 'fa fa-pencil',
+ getTip: (v, m, { data }) => data.type === 'entry'
+ ? Ext.String.format(gettext("Edit Mapping '{0}'"), data.name)
+ : Ext.String.format(gettext("Edit Mapping '{0}' for '{1}'"), data.name, data.node),
+ getClass: (v, m, { data }) => data.type !== 'map' ? 'fa fa-pencil' : 'pmx-hidden',
+ isActionDisabled: (v, r, c, i, rec) => rec.data.type === 'map',
+ handler: 'editAction',
+ },
+ {
+ iconCls: 'fa fa-trash-o',
+ getTip: (v, m, { data }) => data.type === 'entry'
+ ? Ext.String.format(gettext("Remove '{0}'"), data.name)
+ : data.type === 'node'
+ ? Ext.String.format(gettext("Remove mapping for '{0}'"), data.node)
+ : Ext.String.format(gettext("Remove mapping '{0}'"), data.path),
+ handler: 'remove',
+ },
+ ],
+ });
+ me.columns = columns;
+
+ me.callParent();
},
});
cbindData: function(initialConfig) {
let me = this;
- me.isCreate = !me.name || !me.nodename;
+ me.isCreate = (!me.name || !me.nodename) && !me.entryOnly;
me.method = me.name ? 'PUT' : 'POST';
+ me.hideMapping = !!me.entryOnly;
+ me.hideComment = me.name && !me.entryOnly;
+ me.hideNodeSelector = me.nodename || me.entryOnly;
+ me.hideNode = !me.nodename || !me.hideNodeSelector;
return {
name: me.name,
nodename: me.nodename,
allowBlank: false,
},
{
- xtype: 'pmxDisplayEditField',
+ xtype: 'displayfield',
fieldLabel: gettext('Mapping on Node'),
labelWidth: 120,
name: 'node',
- editConfig: {
- xtype: 'pveNodeSelector',
- reference: 'nodeselector',
- },
cbind: {
- editable: '{!nodename}',
value: '{nodename}',
+ disabled: '{hideNode}',
+ hidden: '{hideNode}',
+ },
+ allowBlank: false,
+ },
+ {
+ xtype: 'pveNodeSelector',
+ reference: 'nodeselector',
+ fieldLabel: gettext('Mapping on Node'),
+ labelWidth: 120,
+ name: 'node',
+ cbind: {
+ disabled: '{hideNodeSelector}',
+ hidden: '{hideNodeSelector}',
},
allowBlank: false,
},
],
column2: [
- {
- // as spacer
- xtype: 'displayfield',
- },
{
xtype: 'proxmoxcheckbox',
- fieldLabel: gettext('Mediated Devices'),
- labelWidth: 120,
+ fieldLabel: gettext('Use with Mediated Devices'),
+ labelWidth: 200,
reference: 'mdev',
name: 'mdev',
cbind: {
deleteEmpty: '{!isCreate}',
+ disabled: '{hideComment}',
},
},
],
name: 'map',
cbind: {
nodename: '{nodename}',
+ disabled: '{hideMapping}',
+ hidden: '{hideMapping}',
},
allowBlank: false,
onLoadCallBack: 'checkIommu',
name: 'description',
cbind: {
deleteEmpty: '{!isCreate}',
+ disabled: '{hideComment}',
+ hidden: '{hideComment}',
},
},
],
let me = this;
me.isCreate = !me.name;
me.method = me.isCreate ? 'POST' : 'PUT';
+ me.hideMapping = !!me.entryOnly;
+ me.hideComment = me.name && !me.entryOnly;
+ me.hideNodeSelector = me.nodename || me.entryOnly;
+ me.hideNode = !me.nodename || !me.hideNodeSelector;
return {
name: me.name,
nodename: me.nodename,
if (me.originalMap) {
map = PVE.Parser.filterPropertyStringList(me.originalMap, (e) => e.node !== values.node);
}
- map.push(PVE.Parser.printPropertyString(values));
+ if (values.id) {
+ map.push(PVE.Parser.printPropertyString(values));
+ }
- values = {
- map,
- description,
- };
+ values = { map };
+ if (description) {
+ values.description = description;
+ }
if (view.isCreate) {
values.id = name;
allowBlank: false,
},
{
- xtype: 'pmxDisplayEditField',
- fieldLabel: gettext('Node'),
+ xtype: 'displayfield',
+ fieldLabel: gettext('Mapping on Node'),
+ labelWidth: 120,
name: 'node',
- editConfig: {
- xtype: 'pveNodeSelector',
- reference: 'nodeselector',
- },
cbind: {
- editable: '{!nodename}',
value: '{nodename}',
+ disabled: '{hideNode}',
+ hidden: '{hideNode}',
+ },
+ allowBlank: false,
+ },
+ {
+ xtype: 'pveNodeSelector',
+ reference: 'nodeselector',
+ fieldLabel: gettext('Mapping on Node'),
+ labelWidth: 120,
+ name: 'node',
+ cbind: {
+ disabled: '{hideNodeSelector}',
+ hidden: '{hideNodeSelector}',
},
allowBlank: false,
},
xtype: 'fieldcontainer',
defaultType: 'radiofield',
layout: 'fit',
+ cbind: {
+ disabled: '{hideMapping}',
+ hidden: '{hideMapping}',
+ },
items: [
{
name: 'usb',
name: 'id',
cbind: {
nodename: '{nodename}',
+ disabled: '{hideMapping}',
},
editable: true,
allowBlank: false,
fieldLabel: gettext('Comment'),
submitValue: true,
name: 'description',
+ cbind: {
+ disabled: '{hideComment}',
+ hidden: '{hideComment}',
+ },
},
],
},