this is a rather complex edit window, because we dynamically create form fields according to the schema we get from the api
to do this properly we have to handle a few things: * we have to properly set the values on edit * we have to properly track the original values * we have to merge and split with/from the generic 'data' field (so that if a plugin has some extra fields that we did not include in the schema the user can still enter them) Signed-off-by: Dominik Csapak <d.csa...@proxmox.com> --- www/manager6/Makefile | 1 + www/manager6/Parser.js | 17 ++- www/manager6/dc/ACMEPluginEdit.js | 190 ++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 www/manager6/dc/ACMEPluginEdit.js diff --git a/www/manager6/Makefile b/www/manager6/Makefile index 62253ede..fb4c51bb 100644 --- a/www/manager6/Makefile +++ b/www/manager6/Makefile @@ -217,6 +217,7 @@ JSSRC= \ ha/GroupEdit.js \ ha/Groups.js \ ha/Fencing.js \ + dc/ACMEPluginEdit.js \ dc/Summary.js \ grid/Replication.js \ dc/Health.js \ diff --git a/www/manager6/Parser.js b/www/manager6/Parser.js index 43cc4f5f..4cecb3e1 100644 --- a/www/manager6/Parser.js +++ b/www/manager6/Parser.js @@ -696,5 +696,20 @@ Ext.define('PVE.Parser', { statics: { }; } return null; - } + }, + + parseACMEPluginData: function(data) { + let res = {}; + let extradata = []; + data.split('\n').forEach((line) => { + // capture everything after the first = as value + let [key, value] = line.split(/=(.+)/); + if (value !== undefined) { + res[key] = value; + } else { + extradata.push(line); + } + }); + return [res, extradata]; + }, }}); diff --git a/www/manager6/dc/ACMEPluginEdit.js b/www/manager6/dc/ACMEPluginEdit.js new file mode 100644 index 00000000..fd07017c --- /dev/null +++ b/www/manager6/dc/ACMEPluginEdit.js @@ -0,0 +1,190 @@ +Ext.define('PVE.dc.ACMEPluginEditor', { + extend: 'Proxmox.window.Edit', + xtype: 'pveACMEPluginEditor', + mixins: ['Proxmox.Mixin.CBind'], + + isAdd: true, + isCreate: false, + + width: 400, + url: '/cluster/acme/plugins/', + + subject: gettext('Plugin'), + items: [ + { + xtype: 'inputpanel', + // we dynamically create fields from the given schema + // things we have to do here: + // * save which fields we created to remove them again + // * split the data from the generic 'data' field into the boxes + // * on deletion collect those values again + // * save the original values of the data field + createdFields: {}, + createdInitially: false, + originalValues: {}, + createSchemaFields: function(schema) { + let me = this; + // we know where to add because we define it right below + let container = me.down('container'); + let datafield = me.down('field[name=data]'); + if (!me.createdInitially) { + [me.originalValues] = PVE.Parser.parseACMEPluginData(datafield.getValue()); + } + + // collect values from custom fields and add it to 'data'', + // then remove the custom fields + let data = []; + for (const [name, field] of Object.entries(me.createdFields)) { + let value = field.getValue(); + if (value !== undefined && value !== null && value !== '') { + data.push(`${name}=${value}`); + } + container.remove(field); + } + let datavalue = datafield.getValue(); + if (datavalue !== undefined && datavalue !== null && datavalue !== '') { + data.push(datavalue); + } + datafield.setValue(data.join('\n')); + + me.createdFields = {}; + + // create custom fields according to schema + for (const [name, definition] of Object.entries(schema)) { + let xtype; + switch (definition.type) { + case 'string': + xtype = 'proxmoxtextfield'; + break; + case 'integer': + xtype = 'proxmoxintegerfield'; + break; + case 'number': + xtype = 'numberfield'; + break; + default: + console.warn(`unknown type '${definition.type}'`); + xtype = 'proxmoxtextfield'; + break; + } + + let field = Ext.create({ + xtype, + name: `custom_${name}`, + fieldLabel: name, + width: '100%', + labelWidth: 120, + autoEl: definition.description ? { + tag: 'div', + 'data-qtip': definition.description, + } : undefined, + }); + + me.createdFields[name] = field; + container.add(field); + } + + // parse data from field and set it to the custom ones + let extradata = []; + [data, extradata] = PVE.Parser.parseACMEPluginData(datafield.getValue()); + for (const [key, value] of Object.entries(data)) { + if (me.createdFields[key]) { + me.createdFields[key].setValue(value); + me.createdFields[key].originalValue = me.originalValues[key]; + } else { + extradata.push(`${key}=${value}`); + } + } + datafield.setValue(extradata.join('\n')); + if (!me.createdInitially) { + datafield.resetOriginalValue(); + me.createdInitially = true; // save that we initally set that + } + }, + onGetValues: function(values) { + let me = this; + let win = me.up('pveACMEPluginEditor'); + if (win.isCreate) { + values.id = values.plugin; + values.type = 'dns'; // the only one for now + } + delete values.plugin; + + PVE.Utils.delete_if_default(values, 'validation-delay', '30', win.isCreate); + + let data = ''; + for (const [name, field] of Object.entries(me.createdFields)) { + let value = field.getValue(); + if (value !== null && value !== undefined && value !== '') { + data += `${name}=${value}\n`; + } + delete values[`custom_${name}`]; + } + values.data = Ext.util.Base64.encode(data + values.data); + return values; + }, + items: [ + { + xtype: 'pmxDisplayEditField', + cbind: { + editable: (get) => get('isCreate'), + submitValue: (get) => get('isCreate'), + }, + editConfig: { + flex: 1, + xtype: 'proxmoxtextfield', + allowBlank: false, + }, + name: 'plugin', + labelWidth: 120, + fieldLabel: gettext('Plugin'), + }, + { + xtype: 'proxmoxintegerfield', + name: 'validation-delay', + labelWidth: 120, + fieldLabel: gettext('Validation Delay'), + emptyText: 30, + cbind: { + deleteEmpty: '{!isCreate}', + }, + minValue: 0, + maxValue: 172800, + }, + { + xtype: 'pveACMEApiSelector', + name: 'api', + labelWidth: 120, + listeners: { + change: function(selector) { + let schema = selector.getSchema(); + selector.up('inputpanel').createSchemaFields(schema); + }, + }, + }, + { + fieldLabel: gettext('API Data'), + labelWidth: 120, + xtype: 'textarea', + name: 'data', + }, + ], + }, + ], + + initComponent: function() { + var me = this; + + me.callParent(); + + if (!me.isCreate) { + me.load({ + success: function(response, opts) { + me.setValues(response.result.data); + }, + }); + } else { + me.method = 'POST'; + } + }, +}); -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel