From: Leo Nunner <l.nunner@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH manager] fix #4068: expose fw_cfg through the GUI
Date: Wed, 1 Mar 2023 10:12:29 +0100 [thread overview]
Message-ID: <20230301091229.53505-5-l.nunner@proxmox.com> (raw)
In-Reply-To: <20230301091229.53505-1-l.nunner@proxmox.com>
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 <l.nunner@proxmox.com>
---
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
prev parent reply other threads:[~2023-03-01 9:12 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-01 9:12 [pve-devel] [PATCH qemu-server docs manager] Implement support for fw_cfg Leo Nunner
2023-03-01 9:12 ` [pve-devel] [PATCH qemu-server 1/2] fix #4068: implement " Leo Nunner
2023-03-15 14:05 ` Wolfgang Bumiller
2023-03-24 9:43 ` Leo Nunner
2023-03-01 9:12 ` [pve-devel] [PATCH qemu-server 2/2] test: add cfg2cmd tests " Leo Nunner
2023-03-01 9:12 ` [pve-devel] [PATCH docs] fix #4068: document fw_cfg parameter Leo Nunner
2023-03-01 9:12 ` Leo Nunner [this message]
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=20230301091229.53505-5-l.nunner@proxmox.com \
--to=l.nunner@proxmox.com \
--cc=pve-devel@lists.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.