[pve-devel] [PATCH manager] ui: declarative LXC Create

Dominik Csapak d.csapak at proxmox.com
Thu Feb 22 13:48:44 CET 2018


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.lamprecht at 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 at 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 at 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";
> 





More information about the pve-devel mailing list