Introduces a new UI element to set/edit/delete any number of fw_cfg
arguments in a table-like manner.

Signed-off-by: Leo Nunner <[email protected]>
---
 www/manager6/Makefile                |   1 +
 www/manager6/qemu/FirmwareCfgEdit.js | 224 +++++++++++++++++++++++++++
 www/manager6/qemu/Options.js         |   6 +
 3 files changed, 231 insertions(+)
 create mode 100644 www/manager6/qemu/FirmwareCfgEdit.js

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 05afeda4..bf3c8b20 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -217,6 +217,7 @@ JSSRC=                                                      
\
        qemu/Config.js                                  \
        qemu/CreateWizard.js                            \
        qemu/DisplayEdit.js                             \
+       qemu/FirmwareCfgEdit.js                         \
        qemu/HDEdit.js                                  \
        qemu/HDEfi.js                                   \
        qemu/HDTPM.js                                   \
diff --git a/www/manager6/qemu/FirmwareCfgEdit.js 
b/www/manager6/qemu/FirmwareCfgEdit.js
new file mode 100644
index 00000000..031042e3
--- /dev/null
+++ b/www/manager6/qemu/FirmwareCfgEdit.js
@@ -0,0 +1,224 @@
+Ext.define('pve-fw-cfg-option', {
+    extend: 'Ext.data.Model',
+    fields: [
+       { name: 'opt', type: 'string' },
+       { name: 'val', type: 'string' },
+    ],
+});
+
+Ext.define('PVE.qemu.FirmwareCfgPanel', {
+    extend: 'Ext.form.FieldContainer',
+    alias: 'widget.pveQemuFirmwareCfgPanel',
+
+    config: {}, // store loaded vm config
+    store: undefined,
+
+    inUpdate: false,
+    controller: {
+       xclass: 'Ext.app.ViewController',
+
+       init: function(view) {
+           let me = this;
+           let grid = me.lookup('grid');
+
+           view.store = Ext.create('Ext.data.Store', {
+               model: 'pve-fw-cfg-option',
+           });
+
+           grid.setStore(view.store);
+       },
+
+       addOption: function() {
+           let me = this;
+           me.lookup('grid').getStore().add({});
+       },
+
+       removeOption: function(field) {
+           let me = this;
+           let record = field.getWidgetRecord();
+           me.lookup('grid').getStore().remove(record);
+           me.setMarkerValue();
+       },
+
+       onUpdate: function(record, property, value) {
+           let me = this;
+
+           if (record === undefined) {
+               return;
+           }
+
+           record.set(property, value);
+           record.commit();
+           me.setMarkerValue();
+       },
+
+       onUpdateOption: function(field, value) {
+           let me = this;
+           let record = field.getWidgetRecord();
+
+           me.onUpdate(record, "opt", value);
+       },
+
+       onUpdateValue: function(field, value) {
+           let me = this;
+           let record = field.getWidgetRecord();
+
+           me.onUpdate(record, "val", value);
+       },
+
+       setMarkerValue() {
+           let me = this;
+           let view = me.getView();
+
+           view.inUpdate = true;
+           me.lookup('marker').setValue(view.calculateValue());
+           view.inUpdate = false;
+       },
+
+       control: {
+           "grid textfield[dest=opt]": {
+               change: "onUpdateOption",
+           },
+           "grid textfield[dest=val]": {
+               change: "onUpdateValue",
+           },
+       },
+    },
+
+    loadConfig: function(config) {
+       let me = this;
+       let marker = me.lookup('marker');
+       let list = PVE.Parser.parsePropertyString(config.fw_cfg);
+       let options = [];
+
+       me.config = config;
+       me.store.removeAll();
+
+       for (const [key, value] of Object.entries(list)) {
+           options.push({
+               opt: key,
+               val: value,
+           });
+       }
+
+       marker.originalValue = config.fw_cfg;
+       marker.value = config.fw_cfg;
+       me.store.setData(options);
+    },
+
+    calculateValue: function() {
+       let me = this;
+       let ret = [];
+       me.store.each((record) => {
+           ret.push(record.data.opt + "=" + record.data.val);
+       });
+       return ret.join(",");
+    },
+
+    items: [
+       {
+           xtype: 'grid',
+           reference: 'grid',
+           margin: '0 0 5 0',
+           height: 150,
+           defaults: {
+               sortable: false,
+               hideable: false,
+               draggable: false,
+           },
+           columns: [
+               {
+                   xtype: 'widgetcolumn',
+                   text: gettext('Option'),
+                   dataIndex: 'opt',
+                   flex: 1,
+                   isFormField: false,
+                   widget: {
+                       xtype: 'textfield',
+                       allowBlank: false,
+                       dest: 'opt',
+                       emptyText: 'opt/...',
+                   },
+               },
+               {
+                   xtype: 'widgetcolumn',
+                   text: gettext('Value'),
+                   dataIndex: 'val',
+                   flex: 1,
+                   isFormField: false,
+                   widget: {
+                       xtype: 'textfield',
+                       allowBlank: false,
+                       dest: 'val',
+                   },
+               },
+               {
+                   xtype: 'widgetcolumn',
+                   width: 40,
+                   widget: {
+                       xtype: 'button',
+                       iconCls: 'fa fa-trash-o',
+                       handler: 'removeOption',
+                   },
+               },
+           ],
+       },
+       {
+           // for dirty marking and 'reset' function
+           xtype: 'hiddenfield',
+           reference: 'marker',
+           name: 'fw_cfg',
+           setValue: function(value) {
+               let me = this;
+               let panel = me.up('pveQemuFirmwareCfgPanel');
+
+               // Reset
+               if (!panel.inUpdate) {
+                   panel.loadConfig(panel.config);
+               }
+
+               me.value = value;
+               me.checkDirty();
+           },
+           getValue: function() {
+               return this.value;
+           },
+           getSubmitValue: function() {
+               return this.value;
+           },
+       },
+       {
+           xtype: 'button',
+           text: gettext('Add'),
+           iconCls: 'fa fa-plus-circle',
+           handler: 'addOption',
+       },
+    ],
+});
+
+Ext.define('PVE.qemu.FirmwareCfgEdit', {
+    extend: 'Proxmox.window.Edit',
+
+    items: [{
+       xtype: 'pveQemuFirmwareCfgPanel',
+       itemId: 'inputpanel',
+    }],
+
+    subject: gettext('Firmware Configuration'),
+    onlineHelp: 'qm_fw_cfg',
+    width: 640,
+
+    getValues: function() {
+       let me = this;
+       let values = me.callParent();
+       return values.fw_cfg ? values : { 'delete': 'fw_cfg' };
+    },
+
+    initComponent: function() {
+       let me = this;
+       me.callParent();
+       me.load({
+           success: ({ result }) => 
me.down('#inputpanel').loadConfig(result.data),
+       });
+    },
+});
diff --git a/www/manager6/qemu/Options.js b/www/manager6/qemu/Options.js
index 7b112400..80407010 100644
--- a/www/manager6/qemu/Options.js
+++ b/www/manager6/qemu/Options.js
@@ -338,6 +338,12 @@ Ext.define('PVE.qemu.Options', {
                    },
                } : undefined,
            },
+           fw_cfg: {
+               header: gettext('QEMU Firmware Configuration'),
+               defaultValue: '',
+               renderer: val => val || Proxmox.Utils.noneText,
+               editor: caps.vms['VM.Config.Options'] ? 
'PVE.qemu.FirmwareCfgEdit' : undefined,
+           },
            hookscript: {
                header: gettext('Hookscript'),
            },
-- 
2.30.2



_______________________________________________
pve-devel mailing list
[email protected]
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to