[pve-devel] [PATCH manager 5/6] ui: add ACMEPluginEdit window
Dominik Csapak
d.csapak at proxmox.com
Tue May 5 14:38:17 CEST 2020
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.csapak at 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
More information about the pve-devel
mailing list