general nitpick:

i would like to have more commits from this (e.g. the move of loadSSHKeyFrom to Utils, the dataCache check move, etc.)

further comments inline

On 02/21/2018 04:45 PM, Thomas Lamprecht wrote:
add setNodename method to FileSelector and a setUnprivileged to
MPEdit, this allows to make those properties bindable

Reset MPEdits quota checkbox when it gets disabled

Move the loadSSHKeyFromFile helper to the PVE.Utils singleton

And then, with all those changes transform the LXC Create wizard to
a declarative style, in one go. Maybe it's better to just look at the
end result than the diff...

Signed-off-by: Thomas Lamprecht <t.lampre...@proxmox.com>
---

I did not see easy intermediate steps that make sense from a git
history POV, so just sending ti as one change...

  www/manager6/Utils.js             |  19 ++
  www/manager6/form/FileSelector.js |   4 +
  www/manager6/lxc/CreateWizard.js  | 597 ++++++++++++++++++--------------------
  www/manager6/lxc/MPEdit.js        |  13 +-
  www/manager6/lxc/Network.js       |  11 +-
  5 files changed, 325 insertions(+), 319 deletions(-)

diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js
index 8f80c76a..87699e56 100644
--- a/www/manager6/Utils.js
+++ b/www/manager6/Utils.js
@@ -875,6 +875,25 @@ Ext.define('PVE.Utils', { utilities: {
delete values[fieldname];
        }
+    },
+
+    loadSSHKeyFromFile: function(file, callback) {
+       // ssh-keygen produces 740 bytes for an average 4096 bit rsa key, with
+       // a user@host comment, 1420 for 8192 bits; current max is 16kbit
+       // assume: 740*8 for max. 32kbit (5920 byte file)
+       // round upwards to nearest nice number => 8192 bytes, leaves lots of 
comment space
+       if (file.size > 8192) {
+           Ext.Msg.alert(gettext('Error'), gettext("Invalid file size: ") + 
file.size);
+           return;
+       }
+       /*global
+         FileReader
+       */
+       var reader = new FileReader();
+       reader.onload = function(evt) {
+           callback(evt.target.result);
+       };
+       reader.readAsText(file);
      }
  },
diff --git a/www/manager6/form/FileSelector.js b/www/manager6/form/FileSelector.js
index 9afbf821..3dc50720 100644
--- a/www/manager6/form/FileSelector.js
+++ b/www/manager6/form/FileSelector.js
@@ -47,6 +47,10 @@ Ext.define('PVE.form.FileSelector', {
        me.store.load();
      },
+ setNodename: function(nodename) {
+       this.setStorage(undefined, nodename);
+    },
+
      store: {
        model: 'pve-storage-content'
      },
diff --git a/www/manager6/lxc/CreateWizard.js b/www/manager6/lxc/CreateWizard.js
index 5b069317..9abe7887 100644
--- a/www/manager6/lxc/CreateWizard.js
+++ b/www/manager6/lxc/CreateWizard.js
@@ -1,342 +1,317 @@
-/*global
-  FileReader
-*/
-
+/*jslint confusion: true*/
  Ext.define('PVE.lxc.CreateWizard', {
      extend: 'PVE.window.Wizard',
+    mixins: ['Proxmox.Mixin.CBind'],
- loadSSHKeyFromFile: function(file) {
-       var me = this;
-       // ssh-keygen produces 740 bytes for an average 4096 bit rsa key, with
-       // a user@host comment, 1420 for 8192 bits; current max is 16kbit
-       // assume: 740*8 for max. 32kbit (5920 byte file)
-       // round upwards to nearest nice number => 8192 bytes, leaves lots of 
comment space
-       if (file.size > 8192) {
-           Ext.Msg.alert(gettext('Error'), gettext("Invalid file size: ") + 
file.size);
-           return;
+    viewModel: {
+       data: {
+           nodename: '',
+           storage: '',
+           unprivileged: false
        }
-       var reader = new FileReader();
-       reader.onload = function(evt) {
-           me.sshkeyfield.setValue(evt.target.result);
-       };
-       reader.readAsText(file);
      },
- initComponent: function() {
-       var me = this;
+    cbindData: {
+       nodename: undefined
+    },
+
+    subject: gettext('LXC Container'),
- var summarystore = Ext.create('Ext.data.Store', {
-           model: 'KeyValue',
-           sorters: [
+    items: [
+       {
+           xtype: 'inputpanel',
+           title: gettext('General'),
+           onlineHelp: 'pct_general',
+           column1: [
+               {
+                   xtype: 'pveNodeSelector',
+                   name: 'nodename',
+                   cbind: {
+                       selectCurNode: '{!nodename}',
+                       preferredValue: '{nodename}'
+                   },
+                   bind: {
+                       value: '{nodename}'
+                   },
+                   fieldLabel: gettext('Node'),
+                   allowBlank: false,
+                   onlineValidator: true
+               },
+               {
+                   xtype: 'pveGuestIDSelector',
+                   name: 'vmid', // backend only knows vmid
+                   guestType: 'lxc',
+                   value: '',
+                   loadNextFreeID: true,
+                   validateExists: false
+               },
+               {
+                   xtype: 'proxmoxtextfield',
+                   name: 'hostname',
+                   vtype: 'DnsName',
+                   value: '',
+                   fieldLabel: gettext('Hostname'),
+                   skipEmptyText: true,
+                   allowBlank: true
+               },
                {
-                   property : 'key',
-                   direction: 'ASC'
+                   xtype: 'proxmoxcheckbox',
+                   name: 'unprivileged',
+                   value: false,
+                   bind: {
+                       value: '{unprivileged}'
+                   },
+                   fieldLabel: gettext('Unprivileged container')
+               }
+           ],
+           column2: [
+               {
+                   xtype: 'pvePoolSelector',
+                   fieldLabel: gettext('Resource Pool'),
+                   name: 'pool',
+                   submitValue: false,
+                   value: '',
+                   allowBlank: true
+               },
+               {
+                   xtype: 'textfield',
+                   inputType: 'password',
+                   name: 'password',
+                   value: '',
+                   fieldLabel: gettext('Password'),
+                   allowBlank: false,
+                   minLength: 5,
+                   change: function(f, value) {
+                       if (!f.rendered) {
+                           return;
+                       }
+                       f.uo().down('field[name=confirmpw]').validate();

i believe this is a typo? i guess this should be: f.up().down(...
would it not be better if we would use a viewcontroller and have a reference to the things we want to check/change?

+                   }
+               },
+               {
+                   xtype: 'textfield',
+                   inputType: 'password',
+                   name: 'confirmpw',
+                   value: '',
+                   fieldLabel: gettext('Confirm password'),
+                   allowBlank: true,
+                   submitValue: false,
+                   validator: function(value) {
+                       var pw = 
this.up().down('field[name=password]').getValue();
+                       if (pw !== value) {
+                           return "Passwords do not match!";
+                       }
+                       return true;
+                   }

not necessary for now, but we have a custom vtype 'password' in the widget toolkit we could use instead

the syntax is like:

{
 xtype: 'textfield',
 vtype: 'password',
 initialPassField: '<name of passwordfield>',
}

which does the match check for us

+               },
+               {
+                   xtype: 'proxmoxtextfield',
+                   name: 'ssh-public-keys',
+                   value: '',
+                   fieldLabel: gettext('SSH public key'),
+                   allowBlank: true,
+                   validator: function(value) {
+                       var pwfield = this.up().down('field[name=password]');
+                       if (value.length) {
+                           var key = PVE.Parser.parseSSHKey(value);
+                           if (!key) {
+                               return "Failed to recognize ssh key";
+                           }
+                           pwfield.allowBlank = true;
+                       } else {
+                           pwfield.allowBlank = false;
+                       }
+                       pwfield.validate();
+                       return true;
+                   },
+                   afterRender: function() {
+                       if (!window.FileReader) {
+                           // No FileReader support in this browser
+                           return;
+                       }
+                       var cancel = function(ev) {
+                           ev = ev.event;
+                           if (ev.preventDefault) {
+                               ev.preventDefault();
+                           }
+                       };
+                       var field = this;
+                       field.inputEl.on('dragover', cancel);
+                       field.inputEl.on('dragenter', cancel);
+                       field.inputEl.on('drop', function(ev) {
+                           ev = ev.event;
+                           if (ev.preventDefault) {
+                               ev.preventDefault();
+                           }
+                           var files = ev.dataTransfer.files;
+                           PVE.Utils.loadSSHKeyFromFile(files[0], function(v) {
+                               field.setValue(v);
+                           });
+                       });
+                   }
+               },
+               {
+                   xtype: 'filebutton',
+                   name: 'file',
+                   hidden: !window.FileReader,
+                   text: gettext('Load SSH Key File'),
+                   listeners: {
+                       change: function(btn, e, value) {
+                           e = e.event;
+                           var field = 
this.up().down('proxmoxtextfield[name=ssh-public-keys]');
+                           PVE.Utils.loadSSHKeyFromFile(e.target.files[0], 
function(v) {
+                               field.setValue(v);
+                           });
+                           btn.reset();
+                       }
+                   }
                }
            ]
-       });
-
-       var tmplsel = Ext.create('PVE.form.FileSelector', {
-           name: 'ostemplate',
-           storageContent: 'vztmpl',
-           fieldLabel: gettext('Template'),
-           allowBlank: false
-       });
-
-       var tmplstoragesel = Ext.create('PVE.form.StorageSelector', {
-           name: 'tmplstorage',
-           fieldLabel: gettext('Storage'),
-           storageContent: 'vztmpl',
-           autoSelect: true,
-           allowBlank: false,
-           listeners: {
-               change: function(f, value) {
-                   tmplsel.setStorage(value);
+       },
+       {
+           xtype: 'inputpanel',
+           title: gettext('Template'),
+           onlineHelp: 'pct_container_images',
+           column1: [
+               {
+                   xtype: 'pveStorageSelector',
+                   name: 'tmplstorage',
+                   fieldLabel: gettext('Storage'),
+                   storageContent: 'vztmpl',
+                   autoSelect: true,
+                   allowBlank: false,
+                   bind: {
+                       value: '{storage}',
+                       nodename: '{nodename}'
+                   }
+               },
+               {
+                   xtype: 'pveFileSelector',
+                   name: 'ostemplate',
+                   storageContent: 'vztmpl',
+                   fieldLabel: gettext('Template'),
+                   bind: {
+                       storage: '{storage}',
+                       nodename: '{nodename}'
+                   },
+                   allowBlank: false
                }
-           }
-       });
-
-       var rootfspanel = Ext.create('PVE.lxc.MountPointInputPanel', {
+           ]
+       },
+       {
+           xtype: 'pveLxcMountPointInputPanel',
            title: gettext('Root Disk'),
            insideWizard: true,
            isCreate: true,
            unused: false,
-           unprivileged: false,
+           bind: {
+               nodename: '{nodename}',
+               unprivileged: '{unprivileged}'
+           },
            confid: 'rootfs'
-       });
-
-       var networkpanel = Ext.create('PVE.lxc.NetworkInputPanel', {
+       },
+       {
+           xtype: 'pveLxcCPUInputPanel',
+           title: gettext('CPU'),
+           insideWizard: true
+       },
+       {
+           xtype: 'pveLxcMemoryInputPanel',
+           title: gettext('Memory'),
+           insideWizard: true
+       },
+       {
+           xtype: 'pveLxcNetworkInputPanel',
            title: gettext('Network'),
            insideWizard: true,
-           dataCache: {},
+           bind: {
+               nodename: '{nodename}'
+           },
            isCreate: true
-       });
-
-       var passwordfield = Ext.createWidget('textfield', {
-           inputType: 'password',
-           name: 'password',
-           value: '',
-           fieldLabel: gettext('Password'),
-           allowBlank: false,
-           minLength: 5,
-           change: function(f, value) {
-               if (!me.rendered) {
-                   return;
-               }
-               me.down('field[name=confirmpw]').validate();
-           }
-       });
-
-       /*jslint confusion: true */
-       /* the validator function can return either a string or a boolean */
-       me.sshkeyfield = Ext.createWidget('proxmoxtextfield', {
-           name: 'ssh-public-keys',
-           value: '',
-           fieldLabel: gettext('SSH public key'),
-           allowBlank: true,
-           validator: function(value) {
-               if (value.length) {
-                   var key = PVE.Parser.parseSSHKey(value);
-                   if (!key) {
-                       return "Failed to recognize ssh key";
-                   }
-                   me.down('field[name=password]').allowBlank = true;
-               } else {
-                   me.down('field[name=password]').allowBlank = false;
-               }
-               me.down('field[name=password]').validate();
-               return true;
-           },
-           afterRender: function() {
-               if (!window.FileReader) {
-                   // No FileReader support in this browser
-                   return;
-               }
-               var cancel = function(ev) {
-                   ev = ev.event;
-                   if (ev.preventDefault) {
-                       ev.preventDefault();
-                   }
-               };
-               me.sshkeyfield.inputEl.on('dragover', cancel);
-               me.sshkeyfield.inputEl.on('dragenter', cancel);
-               me.sshkeyfield.inputEl.on('drop', function(ev) {
-                   ev = ev.event;
-                   if (ev.preventDefault) {
-                       ev.preventDefault();
-                   }
-                   var files = ev.dataTransfer.files;
-                   me.loadSSHKeyFromFile(files[0]);
-               });
-           }
-       });
-
-       var column2 = [
-           {
-               xtype: 'pvePoolSelector',
-               fieldLabel: gettext('Resource Pool'),
-               name: 'pool',
-               value: '',
-               allowBlank: true
-           },
-           passwordfield,
-           {
-               xtype: 'textfield',
-               inputType: 'password',
-               name: 'confirmpw',
-               value: '',
-               fieldLabel: gettext('Confirm password'),
-               allowBlank: true,
-               validator: function(value) {
-                   var pw = me.down('field[name=password]').getValue();
-                   if (pw !== value) {
-                       return "Passwords do not match!";
-                   }
-                   return true;
-               }
-           },
-           me.sshkeyfield
-       ];
-       /*jslint confusion: false */
-
-       if (window.FileReader) {
-           column2.push({
-               xtype: 'filebutton',
-               name: 'file',
-               text: gettext('Load SSH Key File'),
-               listeners: {
-                   change: function(btn, e, value) {
-                       e = e.event;
-                       me.loadSSHKeyFromFile(e.target.files[0]);
-                       btn.reset();
-                   }
-               }
-           });
-       }
-
-       Ext.applyIf(me, {
-           subject: gettext('LXC Container'),
+       },
+       {
+           xtype: 'pveLxcDNSInputPanel',
+           title: gettext('DNS'),
+           insideWizard: true
+       },
+       {
+           title: gettext('Confirm'),
+           layout: 'fit',
            items: [
                {
-                   xtype: 'inputpanel',
-                   title: gettext('General'),
-                   onlineHelp: 'pct_general',
-                   column1: [
-                       {
-                           xtype: 'pveNodeSelector',
-                           name: 'nodename',
-                           selectCurNode: !me.nodename,
-                           preferredValue: me.nodename,
-                           fieldLabel: gettext('Node'),
-                           allowBlank: false,
-                           onlineValidator: true,
-                           listeners: {
-                               change: function(f, value) {
-                                   tmplstoragesel.setNodename(value);
-                                   tmplsel.setStorage(undefined, value);
-                                   networkpanel.setNodename(value);
-                                   rootfspanel.setNodename(value);
-                               }
-                           }
-                       },
-                       {
-                           xtype: 'pveGuestIDSelector',
-                           name: 'vmid', // backend only knows vmid
-                           guestType: 'lxc',
-                           value: '',
-                           loadNextFreeID: true,
-                           validateExists: false
-                       },
-                       {
-                           xtype: 'proxmoxtextfield',
-                           name: 'hostname',
-                           vtype: 'DnsName',
-                           value: '',
-                           fieldLabel: gettext('Hostname'),
-                           skipEmptyText: true,
-                           allowBlank: true
-                       },
-                       {
-                           xtype: 'proxmoxcheckbox',
-                           name: 'unprivileged',
-                           value: '',
-                           listeners: {
-                               change: function(f, value) {
-                                   if (value) {
-                                       
rootfspanel.down('field[name=quota]').setValue(false);
-                                   }
-                                   rootfspanel.unprivileged = value;
-                                   var hdsel = rootfspanel.down('#hdstorage');
-                                   hdsel.fireEvent('change', hdsel, 
hdsel.getValue());
-                               }
-                           },
-                           fieldLabel: gettext('Unprivileged container')
-                       }
-                   ],
-                   column2: column2,
-                   onGetValues: function(values) {
-                       delete values.confirmpw;
-                       if (!values.pool) {
-                           delete values.pool;
-                       }
-                       return values;
-                   }
-               },
-               {
-                   xtype: 'inputpanel',
-                   title: gettext('Template'),
-                   onlineHelp: 'pct_container_images',
-                   column1: [ tmplstoragesel, tmplsel]
-               },
-               rootfspanel,
-               {
-                   xtype: 'pveLxcCPUInputPanel',
-                   title: gettext('CPU'),
-                   insideWizard: true
-               },
-               {
-                   xtype: 'pveLxcMemoryInputPanel',
-                   title: gettext('Memory'),
-                   insideWizard: true
-               },
-               networkpanel,
-               {
-                   xtype: 'pveLxcDNSInputPanel',
-                   title: gettext('DNS'),
-                   insideWizard: true
-               },
-               {
-                   title: gettext('Confirm'),
-                   layout: 'fit',
-                   items: [
-                       {
-                           xtype: 'grid',
-                           store: summarystore,
-                           columns: [
-                               {header: 'Key', width: 150, dataIndex: 'key'},
-                               {header: 'Value', flex: 1, dataIndex: 'value'}
-                           ]
-                       }
-                   ],
-                   listeners: {
-                       show: function(panel) {
-                           var form = me.down('form').getForm();
-                           var kv = me.getValues();
-                           var data = [];
-                           Ext.Object.each(kv, function(key, value) {
-                               if (key === 'delete' || key === 'tmplstorage') 
{ // ignore
-                                   return;
-                               }
-                               if (key === 'password') { // don't show pw
-                                   return;
-                               }
-                               var html = 
Ext.htmlEncode(Ext.JSON.encode(value));
-                               data.push({ key: key, value: value });
-                           });
-                           summarystore.suspendEvents();
-                           summarystore.removeAll();
-                           summarystore.add(data);
-                           summarystore.sort();
-                           summarystore.resumeEvents();
-                           summarystore.fireEvent('refresh');
-                       }
+                   xtype: 'grid',
+                   store: {
+                       model: 'KeyValue',
+                       sorters: [{
+                               property : 'key',
+                               direction: 'ASC'
+                       }]
                    },
-                   onSubmit: function() {
-                       var kv = me.getValues();
-                       delete kv['delete'];
+                   columns: [
+                       {header: 'Key', width: 150, dataIndex: 'key'},
+                       {header: 'Value', flex: 1, dataIndex: 'value'}
+                   ]
+               }
+           ],
+           listeners: {
+               show: function(panel) {
+                   var wizard = this.up('window');
+                   var kv = wizard.getValues();
+                   var data = [];
+                   Ext.Object.each(kv, function(key, value) {
+                       if (key === 'delete' || key === 'tmplstorage') { // 
ignore
+                           return;
+                       }
+                       if (key === 'password') { // don't show pw
+                           return;
+                       }
+                       var html = Ext.htmlEncode(Ext.JSON.encode(value));
+                       data.push({ key: key, value: value });
+                   });
- var nodename = kv.nodename;
-                       delete kv.nodename;
-                       delete kv.tmplstorage;
+                   var summarystore = panel.down('grid').getStore();
+                   summarystore.suspendEvents();
+                   summarystore.removeAll();
+                   summarystore.add(data);
+                   summarystore.sort();
+                   summarystore.resumeEvents();
+                   summarystore.fireEvent('refresh');
+               }
+           },
+           onSubmit: function() {
+               var wizard = this.up('window');
+               var kv = wizard.getValues();
+               delete kv['delete'];
- if (!kv.password.length && kv['ssh-public-keys']) {
-                           delete kv.password;
-                       }
+               var nodename = kv.nodename;
+               delete kv.nodename;
+               delete kv.tmplstorage;
+
+               if (!kv.password.length && kv['ssh-public-keys']) {
+                   delete kv.password;
+               }
- Proxmox.Utils.API2Request({
-                           url: '/nodes/' + nodename + '/lxc',
-                           waitMsgTarget: me,
-                           method: 'POST',
-                           params: kv,
-                           success: function(response, opts){
-                               var upid = response.result.data;
+               Proxmox.Utils.API2Request({
+                   url: '/nodes/' + nodename + '/lxc',
+                   waitMsgTarget: wizard,
+                   method: 'POST',
+                   params: kv,
+                   success: function(response, opts){
+                       var upid = response.result.data;
- var win = Ext.create('Proxmox.window.TaskViewer', {
-                                   upid: upid
-                               });
-                               win.show();
-                               me.close();
-                           },
-                           failure: function(response, opts) {
-                               Ext.Msg.alert(gettext('Error'), 
response.htmlStatus);
-                           }
+                       var win = Ext.create('Proxmox.window.TaskViewer', {
+                           upid: upid
                        });
+                       win.show();
+                       wizard.close();
+                   },
+                   failure: function(response, opts) {
+                       Ext.Msg.alert(gettext('Error'), response.htmlStatus);
                    }
-               }
-           ]
-       });
-
-       me.callParent();
-    }
+               });
+           }
+       }
+    ]
  });
diff --git a/www/manager6/lxc/MPEdit.js b/www/manager6/lxc/MPEdit.js
index 827869e8..3f84ed5f 100644
--- a/www/manager6/lxc/MPEdit.js
+++ b/www/manager6/lxc/MPEdit.js
@@ -12,6 +12,10 @@ Ext.define('PVE.lxc.MountPointInputPanel', {
vmconfig: {}, // used to select unused disks + setUnprivileged: function(unprivileged) {
+       this.unprivileged = unprivileged;
+    },
+
      onGetValues: function(values) {
        var me = this;
@@ -77,7 +81,6 @@ Ext.define('PVE.lxc.MountPointInputPanel', { if (mp.type === 'bind') {
            me.quota.setDisabled(true);
-           me.quota.setValue(false);
            me.acl.setDisabled(true);
            me.acl.setValue('Default');
            me.down('#hdstorage').setDisabled(true);
@@ -222,7 +225,12 @@ Ext.define('PVE.lxc.MountPointInputPanel', {
            name: 'quota',
            defaultValue: 0,
            disabled: me.unprivileged,
-           fieldLabel: gettext('Enable quota')
+           fieldLabel: gettext('Enable quota'),
+           listeners: {
+               disable: function() {
+                   this.reset();
+               }
+           }
        });
me.column2 = [
@@ -276,7 +284,6 @@ Ext.define('PVE.lxc.MountPointInputPanel', {
                }
                if (rec.data.type === 'zfs' || rec.data.type === 'zfspool') {
                    me.quota.setDisabled(true);
-                   me.quota.setValue(false);
                } else {
                    me.quota.setDisabled(me.unprivileged);
                }
diff --git a/www/manager6/lxc/Network.js b/www/manager6/lxc/Network.js
index 1b574239..22d30055 100644
--- a/www/manager6/lxc/Network.js
+++ b/www/manager6/lxc/Network.js
@@ -49,17 +49,18 @@ Ext.define('PVE.lxc.NetworkInputPanel', {
      initComponent : function() {
        var me = this;
- if (!me.dataCache) {
-           throw "no dataCache specified";
-       }
-       
        var cdata = {};
if (me.insideWizard) {
            me.ifname = 'net0';
            cdata.name = 'eth0';
+           me.dataCache = {};
        }
-       
+
+       if (!me.dataCache) {
+           throw "no dataCache specified";
+       }
+
        if (!me.isCreate) {
            if (!me.ifname) {
                throw "no interface name specified";



_______________________________________________
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to