lxc/MPEdit: rework for advanced options

this is a complete rework of the inputpanel (long overdue)
it uses a viewModel and viewcontroller to avoid the
multiple is zfs/root/bind checks and concentrate them
in one place

also some features get optimized (e.g. the noreplication checkbox)

adds a setNodename to the DiskStorageSelector so that we can bind
the nodename there

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2018-04-05 16:03:56 +02:00 committed by Dietmar Maurer
parent 86daeceb9d
commit b44ca5bac6
2 changed files with 228 additions and 224 deletions

View File

@ -76,6 +76,15 @@ Ext.define('PVE.form.DiskStorageSelector', {
hdsizesel.setVisible(!select && !me.hideSize);
},
setNodename: function(nodename) {
var me = this;
var hdstorage = me.getComponent('hdstorage');
var hdfilesel = me.getComponent('hdimage');
hdstorage.setNodename(nodename);
hdfilesel.setNodename(nodename);
},
initComponent: function() {
var me = this;

View File

@ -1,6 +1,11 @@
/*jslint confusion: true*/
/* hidden: boolean and string
* bind: function and object
* disabled: boolean and string
*/
Ext.define('PVE.lxc.MountPointInputPanel', {
extend: 'Proxmox.panel.InputPanel',
alias: 'widget.pveLxcMountPointInputPanel',
xtype: 'pveLxcMountPointInputPanel',
insideWizard: false,
@ -13,284 +18,274 @@ Ext.define('PVE.lxc.MountPointInputPanel', {
vmconfig: {}, // used to select unused disks
setUnprivileged: function(unprivileged) {
this.unprivileged = unprivileged;
this.quota.setDisabled(unprivileged);
var me = this;
var vm = me.getViewModel();
me.unprivileged = unprivileged;
vm.set('unpriv', unprivileged);
},
onGetValues: function(values) {
var me = this;
var confid = me.confid || values.mpsel;
values.file = me.down('field[name=file]').getValue();
if (me.unused) {
me.mpdata.file = me.vmconfig[values.unusedId];
confid = values.mpsel;
} else if (me.isCreate) {
me.mpdata.file = values.hdstorage + ':' + values.disksize;
values.file = values.hdstorage + ':' + values.disksize;
}
if (confid !== 'rootfs') {
me.mpdata.mp = values.mp;
}
if (values.ro) {
me.mpdata.ro = 1;
} else {
delete me.mpdata.ro;
}
if (values.quota) {
me.mpdata.quota = 1;
} else {
delete me.mpdata.quota;
}
if (values.acl === 'Default') {
delete me.mpdata.acl;
} else {
me.mpdata.acl = values.acl;
}
if (values.backup) {
me.mpdata.backup = 1;
} else {
delete me.mpdata.backup;
}
if (values.noreplicate) {
me.mpdata.replicate = '0';
}
delete me.mpdata.noreplicate;
// delete unnecessary fields
delete values.mpsel;
delete values.hdstorage;
delete values.disksize;
delete values.diskformat;
var res = {};
res[confid] = PVE.Parser.printLxcMountPoint(me.mpdata);
res[confid] = PVE.Parser.printLxcMountPoint(values);
return res;
},
setMountPoint: function(mp) {
var me = this;
// the fields name is 'hdstorage',
// but the api expects/has 'storage'
mp.hdstorage = mp.storage;
delete mp.hdstorage;
me.mpdata = mp;
if (!Ext.isDefined(me.mpdata.acl)) {
me.mpdata.acl = 'Default';
}
if (mp.type === 'bind') {
me.quota.setDisabled(true);
me.acl.setDisabled(true);
me.acl.setValue('Default');
me.down('#hdstorage').setDisabled(true);
if (me.confid !== 'rootfs') {
me.backup.setDisabled(true);
}
}
if (mp.replicate) { // check box reverses the config option
mp.noreplicate = !PVE.Parser.parseBoolean(mp.replicate, 1);
delete mp.replicate;
}
var vm = this.getViewModel();
vm.set('mptype', mp.type);
me.setValues(mp);
},
setVMConfig: function(vmconfig) {
var me = this;
var vm = me.getViewModel();
me.vmconfig = vmconfig;
vm.set('unpriv', vmconfig.unprivileged);
vm.notify();
if (me.mpsel) {
var i;
for (i = 0; i != 8; ++i) {
var name = "mp" + i.toString();
if (!Ext.isDefined(vmconfig[name])) {
me.mpsel.setValue(name);
break;
}
PVE.Utils.forEachMP(function(bus, i) {
var name = "mp" + i.toString();
if (!Ext.isDefined(vmconfig[name])) {
me.down('field[name=mpsel]').setValue(name);
return false;
}
}
if (me.unusedDisks) {
var disklist = [];
Ext.Object.each(vmconfig, function(key, value) {
if (key.match(/^unused\d+$/)) {
disklist.push([key, value]);
}
});
me.unusedDisks.store.loadData(disklist);
me.unusedDisks.setValue(me.confid);
}
});
},
setNodename: function(nodename) {
var me = this;
me.down('#hdstorage').setNodename(nodename);
me.down('#hdimage').setStorage(undefined, nodename);
var vm = me.getViewModel();
vm.set('node', nodename);
vm.notify();
me.down('#diskstorage').setNodename(nodename);
},
initComponent : function() {
var me = this;
controller: {
xclass: 'Ext.app.ViewController',
var isroot = me.confid === 'rootfs';
me.mpdata = {};
me.column1 = [];
if (!me.confid || me.unused) {
var names = [];
var i;
for (i = 0; i != 8; ++i) {
var name = 'mp' + i.toString();
names.push([name, name]);
}
me.mpsel = Ext.create('Proxmox.form.KVComboBox', {
name: 'mpsel',
fieldLabel: gettext('Mount Point'),
matchFieldWidth: false,
allowBlank: false,
comboItems: names,
validator: function(value) {
if (!me.rendered) {
control: {
'field[name=mpsel]': {
change: function(field, value) {
field.validate();
}
},
'#hdstorage': {
change: function(field, newValue) {
var me = this;
if (!newValue) {
return;
}
if (Ext.isDefined(me.vmconfig[value])) {
return "Mount point is already in use.";
}
/*jslint confusion: true*/
/* returns a string above */
return true;
},
listeners: {
change: function(field, value) {
field.validate();
}
}
});
me.column1.push(me.mpsel);
}
me.column1.push({
var rec = field.store.getById(newValue);
if (!rec) {
return;
}
var vm = me.getViewModel();
vm.set('type', rec.data.type);
vm.notify();
}
}
},
init: function(view) {
var me = this;
var vm = this.getViewModel();
vm.set('confid', view.confid);
vm.set('unused', view.unused);
vm.set('node', view.nodename);
vm.set('unpriv', view.unprivileged);
vm.set('hideStorSelector', view.unused || !view.isCreate);
vm.notify();
}
},
viewModel: {
data: {
unpriv: false,
unused: false,
showStorageSelector: false,
mptype: '',
type: '',
confid: '',
node: ''
},
formulas: {
quota: function(get) {
return !(get('type') === 'zfs' ||
get('type') === 'zfspool' ||
get('unpriv') ||
get('isBind'));
},
hasMP: function(get) {
return !!get('confid') && !get('unused');
},
isRoot: function(get) {
return get('confid') === 'rootfs';
},
isBind: function(get) {
return get('mptype') === 'bind';
},
isBindOrRoot: function(get) {
return get('isBind') || get('isRoot');
}
}
},
column1: [
{
xtype: 'proxmoxKVComboBox',
name: 'mpsel',
fieldLabel: gettext('Mount Point'),
matchFieldWidth: false,
hidden: true,
allowBlank: false,
bind: {
hidden: '{hasMP}',
disabled: '{hasMP}'
},
comboItems: (function(){
var mps = [];
PVE.Utils.forEachMP(function(bus,i) {
var name = 'mp' + i.toString();
mps.push([name,name]);
});
return mps;
}()),
validator: function(value) {
var me = this.up('inputpanel');
if (!me.rendered) {
return;
}
if (Ext.isDefined(me.vmconfig[value])) {
return "Mount point is already in use.";
}
/*jslint confusion: true*/
/* returns a string above */
return true;
}
},
{
xtype: 'pveDiskStorageSelector',
nodename: me.nodename,
itemId: 'diskstorage',
storageContent: 'rootdir',
hidden: true,
autoSelect: true,
selectformat: false,
defaultSize: 8,
hidden: me.unused || !me.isCreate
});
if (me.unused) {
me.unusedDisks = Ext.create('Proxmox.form.KVComboBox', {
name: 'unusedId',
fieldLabel: gettext('Disk image'),
matchFieldWidth: false,
listConfig: {
width: 350
},
data: [],
allowBlank: false,
listeners: {
change: function(f, value) {
// make sure our buttons are enabled/disabled when switching
// between images on different storages:
var disk = me.vmconfig[value];
var storage = disk.split(':')[0];
me.down('#hdstorage').setValue(storage);
}
}
});
me.column1.push(me.unusedDisks);
} else if (!me.isCreate) {
me.column1.push({
xtype: 'textfield',
disabled: true,
submitValue: false,
fieldLabel: gettext('Disk image'),
name: 'file'
});
bind: {
hidden: '{hideStorSelector}',
disabled: '{hideStorSelector}',
nodename: '{node}'
}
},
{
xtype: 'textfield',
disabled: true,
submitValue: false,
fieldLabel: gettext('Disk image'),
name: 'file',
bind: {
hidden: '{!hideStorSelector}'
}
}
],
me.acl = Ext.createWidget('proxmoxKVComboBox', {
name: 'acl',
fieldLabel: 'ACLs',
comboItems: [['Default', 'Default'], ['1', 'On'], ['0', 'Off']],
value: 'Default',
allowBlank: true
});
column2: [
{
xtype: 'textfield',
name: 'mp',
value: '',
emptyText: gettext('/some/path'),
allowBlank: false,
fieldLabel: gettext('Path'),
bind: {
hidden: '{isRoot}',
disabled: '{isRoot}'
}
},
{
xtype: 'proxmoxcheckbox',
name: 'backup',
fieldLabel: gettext('Backup'),
bind: {
hidden: '{isRoot}',
disabled: '{isBindOrRoot}'
}
}
],
me.quota = Ext.createWidget('proxmoxcheckbox', {
advancedColumn1: [
{
xtype: 'proxmoxcheckbox',
name: 'quota',
defaultValue: 0,
disabled: me.unprivileged,
bind: {
disabled: '{!quota}'
},
fieldLabel: gettext('Enable quota'),
listeners: {
disable: function() {
this.reset();
}
}
});
me.column2 = [
me.acl,
me.quota
];
if (!isroot) {
me.column2.splice(1, 0, {
xtype: 'proxmoxcheckbox',
name: 'ro',
defaultValue: 0,
fieldLabel: gettext('Read-only'),
hidden: me.insideWizard
});
me.backup = Ext.createWidget('proxmoxcheckbox',{
xtype: 'proxmoxcheckbox',
name: 'backup',
fieldLabel: gettext('Backup')
});
if (me.mpdata.type !== 'bind') {
me.column2.push(me.backup);
}
me.column2.push({
xtype: 'proxmoxcheckbox',
name: 'noreplicate',
fieldLabel: gettext('Skip replication')
});
me.column2.push({
xtype: 'textfield',
name: 'mp',
value: '',
emptyText: gettext('/some/path'),
allowBlank: false,
hidden: isroot,
fieldLabel: gettext('Path')
});
},
{
xtype: 'proxmoxcheckbox',
name: 'ro',
defaultValue: 0,
bind: {
hidden: '{isRoot}',
disabled: '{isRoot}'
},
fieldLabel: gettext('Read-only')
}
],
me.callParent();
if (me.unused || me.isCreate) {
me.mon(me.down('#hdstorage'), 'change', function(field, newValue) {
if (!newValue) {
return;
}
var rec = field.store.getById(newValue);
if (!rec) {
return;
}
if (rec.data.type === 'zfs' || rec.data.type === 'zfspool') {
me.quota.setDisabled(true);
} else {
me.quota.setDisabled(me.unprivileged);
}
});
advancedColumn2: [
{
xtype: 'proxmoxKVComboBox',
name: 'acl',
fieldLabel: 'ACLs',
deleteEmpty: false,
comboItems: [
['__default__', Proxmox.Utils.defaultText],
['1', Proxmox.Utils.enabledText],
['0', Proxmox.Utils.disabledText]
],
value: '__default__',
bind: {
disabled: '{isBind}'
},
allowBlank: true
},
{
xtype: 'proxmoxcheckbox',
inputValue: '0', // reverses the logic
name: 'replicate',
fieldLabel: gettext('Skip replication')
}
}
]
});
Ext.define('PVE.lxc.MountPointEdit', {