Ext.define('PVE.lxc.MountPointInputPanel', {
- extend: 'PVE.panel.InputPanel',
- alias: 'widget.pveLxcMountPointInputPanel',
-
- insideWizard: false,
+ extend: 'Proxmox.panel.InputPanel',
+ xtype: 'pveLxcMountPointInputPanel',
onlineHelp: 'pct_container_storage',
- unused: false, // add unused disk imaged
+ insideWizard: false,
+ unused: false, // add unused disk imaged
unprivileged: false,
vmconfig: {}, // used to select unused disks
+ setUnprivileged: function(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;
+ var confid = me.confid || "mp"+values.mpid;
+ me.mp.file = me.down('field[name=file]').getValue();
if (me.unused) {
- me.mpdata.file = me.vmconfig[values.unusedId];
- confid = values.mpsel;
+ confid = "mp"+values.mpid;
} else if (me.isCreate) {
- me.mpdata.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';
+ me.mp.file = values.hdstorage + ':' + values.disksize;
}
- delete me.mpdata.noreplicate;
- var res = {};
- res[confid] = PVE.Parser.printLxcMountPoint(me.mpdata);
+ // delete unnecessary fields
+ delete values.mpid;
+ delete values.hdstorage;
+ delete values.disksize;
+ delete values.diskformat;
+
+ let setMPOpt = (k, src, v) => PVE.Utils.propertyStringSet(me.mp, src, k, v);
+
+ setMPOpt('mp', values.mp);
+ let mountOpts = (values.mountoptions || []).join(';');
+ setMPOpt('mountoptions', values.mountoptions, mountOpts);
+ setMPOpt('mp', values.mp);
+ setMPOpt('backup', values.backup);
+ setMPOpt('quota', values.quota);
+ setMPOpt('ro', values.ro);
+ setMPOpt('acl', values.acl);
+ setMPOpt('replicate', values.replicate);
+
+ let res = {};
+ res[confid] = PVE.Parser.printLxcMountPoint(me.mp);
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.quota.setValue(false);
- me.acl.setDisabled(true);
- me.acl.setValue('Default');
- me.down('#hdstorage').setDisabled(true);
- if (me.confid !== 'rootfs') {
- me.backup.setDisabled(true);
- }
+ let me = this;
+ let vm = me.getViewModel();
+ vm.set('mptype', mp.type);
+ if (mp.mountoptions) {
+ mp.mountoptions = mp.mountoptions.split(';');
}
-
- if (mp.replicate) { // check box reverses the config option
- mp.noreplicate = !PVE.Parser.parseBoolean(mp.replicate, 1);
- delete mp.replicate;
- }
-
+ me.mp = mp;
+ me.filterMountOptions();
me.setValues(mp);
},
- setVMConfig: function(vmconfig) {
- var me = this;
+ filterMountOptions: function() {
+ let me = this;
+ if (me.confid === 'rootfs') {
+ let field = me.down('field[name=mountoptions]');
+ let exclude = ['nodev', 'noexec'];
+ let filtered = field.comboItems.filter(v => !exclude.includes(v[0]));
+ field.setComboItems(filtered);
+ }
+ },
+ updateVMConfig: function(vmconfig) {
+ let me = this;
+ let vm = me.getViewModel();
me.vmconfig = vmconfig;
+ vm.set('unpriv', vmconfig.unprivileged);
+ me.down('field[name=mpid]').validate();
+ },
- 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;
- }
+ setVMConfig: function(vmconfig) {
+ let me = this;
+
+ me.updateVMConfig(vmconfig);
+ PVE.Utils.forEachMP((bus, i) => {
+ let name = "mp" + i.toString();
+ if (!Ext.isDefined(vmconfig[name])) {
+ me.down('field[name=mpid]').setValue(i);
+ 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);
- }
+ return undefined;
+ });
},
setNodename: function(nodename) {
- var me = this;
- me.down('#hdstorage').setNodename(nodename);
- me.down('#hdimage').setStorage(undefined, nodename);
+ let me = this;
+ let vm = me.getViewModel();
+ vm.set('node', nodename);
+ me.down('#diskstorage').setNodename(nodename);
},
- initComponent : function() {
- var me = this;
-
- var isroot = me.confid === 'rootfs';
+ controller: {
+ xclass: 'Ext.app.ViewController',
- 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('PVE.form.KVComboBox', {
- name: 'mpsel',
- fieldLabel: gettext('Mount Point'),
- matchFieldWidth: false,
- allowBlank: false,
- comboItems: names,
- validator: function(value) {
- if (!me.rendered) {
- return;
- }
- if (Ext.isDefined(me.vmconfig[value])) {
- return "Mount point is already in use.";
+ control: {
+ 'field[name=mpid]': {
+ change: function(field, value) {
+ let me = this;
+ let view = this.getView();
+ if (view.confid !== 'rootfs') {
+ view.fireEvent('diskidchange', view, `mp${value}`);
}
- /*jslint confusion: true*/
- /* returns a string above */
- return true;
+ field.validate();
},
- listeners: {
- change: function(field, value) {
- field.validate();
+ },
+ '#hdstorage': {
+ change: function(field, newValue) {
+ let me = this;
+ if (!newValue) {
+ return;
}
- }
- });
- me.column1.push(me.mpsel);
- }
-
- me.column1.push({
- xtype: 'pveDiskStorageSelector',
- nodename: me.nodename,
- storageContent: 'rootdir',
- autoSelect: true,
- hidden: me.unused || !me.isCreate
- });
- if (me.unused) {
- me.unusedDisks = Ext.create('PVE.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);
+ let rec = field.store.getById(newValue);
+ if (!rec) {
+ return;
}
+ me.getViewModel().set('type', rec.data.type);
+ },
+ },
+ },
+ init: function(view) {
+ let me = this;
+ let vm = this.getViewModel();
+ view.mp = {};
+ 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);
+
+ if (view.isCreate) { // can be array if created from unused disk
+ vm.set('isIncludedInBackup', true);
+ if (view.insideWizard) {
+ view.filterMountOptions();
}
- });
- me.column1.push(me.unusedDisks);
- } else if (!me.isCreate) {
- me.column1.push({
- xtype: 'textfield',
- disabled: true,
- submitValue: false,
- fieldLabel: gettext('Disk image'),
- name: 'file'
- });
- }
-
- me.acl = Ext.createWidget('pveKVComboBox', {
- name: 'acl',
- fieldLabel: gettext('ACLs'),
- comboItems: [['Default', 'Default'], ['1', 'On'], ['0', 'Off']],
- value: 'Default',
- allowBlank: true
- });
-
- me.quota = Ext.createWidget('pvecheckbox', {
- name: 'quota',
- defaultValue: 0,
- disabled: me.unprivileged,
- fieldLabel: gettext('Enable quota')
- });
-
- me.column2 = [
- me.acl,
- me.quota
- ];
-
- if (!isroot) {
- me.column2.splice(1, 0, {
- xtype: 'pvecheckbox',
- name: 'ro',
- defaultValue: 0,
- fieldLabel: gettext('Read-only'),
- hidden: me.insideWizard
- });
-
- me.backup = Ext.createWidget('pvecheckbox',{
- xtype: 'pvecheckbox',
- name: 'backup',
- fieldLabel: gettext('Backup')
- });
- if (me.mpdata.type !== 'bind') {
- me.column2.push(me.backup);
}
- me.column2.push({
- xtype: 'pvecheckbox',
- 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')
- });
- }
+ if (view.selectFree) {
+ view.setVMConfig(view.vmconfig);
+ }
+ },
+ },
- me.callParent();
+ 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');
+ },
+ },
+ },
- 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;
+ column1: [
+ {
+ xtype: 'proxmoxintegerfield',
+ name: 'mpid',
+ fieldLabel: gettext('Mount Point ID'),
+ minValue: 0,
+ maxValue: PVE.Utils.mp_counts.mp - 1,
+ hidden: true,
+ allowBlank: false,
+ disabled: true,
+ bind: {
+ hidden: '{hasMP}',
+ disabled: '{hasMP}',
+ },
+ validator: function(value) {
+ let view = this.up('inputpanel');
+ if (!view.rendered) {
+ return undefined;
}
- if (rec.data.type === 'zfs' || rec.data.type === 'zfspool') {
- me.quota.setDisabled(true);
- me.quota.setValue(false);
- } else {
- me.quota.setDisabled(me.unprivileged);
+ if (Ext.isDefined(view.vmconfig["mp"+value])) {
+ return "Mount point is already in use.";
}
- });
- }
- }
+ return true;
+ },
+ },
+ {
+ xtype: 'pveDiskStorageSelector',
+ itemId: 'diskstorage',
+ storageContent: 'rootdir',
+ hidden: true,
+ autoSelect: true,
+ selectformat: false,
+ defaultSize: 8,
+ bind: {
+ hidden: '{hideStorSelector}',
+ disabled: '{hideStorSelector}',
+ nodename: '{node}',
+ },
+ },
+ {
+ xtype: 'textfield',
+ disabled: true,
+ submitValue: false,
+ fieldLabel: gettext('Disk image'),
+ name: 'file',
+ bind: {
+ hidden: '{!hideStorSelector}',
+ },
+ },
+ ],
+
+ column2: [
+ {
+ xtype: 'textfield',
+ name: 'mp',
+ value: '',
+ emptyText: gettext('/some/path'),
+ allowBlank: false,
+ disabled: true,
+ fieldLabel: gettext('Path'),
+ bind: {
+ hidden: '{isRoot}',
+ disabled: '{isRoot}',
+ },
+ },
+ {
+ xtype: 'proxmoxcheckbox',
+ name: 'backup',
+ fieldLabel: gettext('Backup'),
+ autoEl: {
+ tag: 'div',
+ 'data-qtip': gettext('Include volume in backup job'),
+ },
+ bind: {
+ hidden: '{isRoot}',
+ disabled: '{isBindOrRoot}',
+ value: '{isIncludedInBackup}',
+ },
+ },
+ ],
+
+ advancedColumn1: [
+ {
+ xtype: 'proxmoxcheckbox',
+ name: 'quota',
+ defaultValue: 0,
+ bind: {
+ disabled: '{!quota}',
+ },
+ fieldLabel: gettext('Enable quota'),
+ listeners: {
+ disable: function() {
+ this.reset();
+ },
+ },
+ },
+ {
+ xtype: 'proxmoxcheckbox',
+ name: 'ro',
+ defaultValue: 0,
+ bind: {
+ hidden: '{isRoot}',
+ disabled: '{isRoot}',
+ },
+ fieldLabel: gettext('Read-only'),
+ },
+ {
+ xtype: 'proxmoxKVComboBox',
+ name: 'mountoptions',
+ fieldLabel: gettext('Mount options'),
+ deleteEmpty: false,
+ comboItems: [
+ ['lazytime', 'lazytime'],
+ ['noatime', 'noatime'],
+ ['nodev', 'nodev'],
+ ['noexec', 'noexec'],
+ ['nosuid', 'nosuid'],
+ ],
+ multiSelect: true,
+ value: [],
+ allowBlank: true,
+ },
+ ],
+
+ 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', {
- extend: 'PVE.window.Edit',
+ extend: 'Proxmox.window.Edit',
unprivileged: false,
- initComponent : function() {
- var me = this;
+ initComponent: function() {
+ let me = this;
- var nodename = me.pveSelNode.data.node;
+ let nodename = me.pveSelNode.data.node;
if (!nodename) {
throw "no node name specified";
}
- var unused = me.confid && me.confid.match(/^unused\d+$/);
+ let unused = me.confid && me.confid.match(/^unused\d+$/);
me.isCreate = me.confid ? unused : true;
- var ipanel = Ext.create('PVE.lxc.MountPointInputPanel', {
+ let ipanel = Ext.create('PVE.lxc.MountPointInputPanel', {
confid: me.confid,
nodename: nodename,
unused: unused,
unprivileged: me.unprivileged,
- isCreate: me.isCreate
+ isCreate: me.isCreate,
});
- var subject;
+ let subject;
if (unused) {
subject = gettext('Unused Disk');
} else if (me.isCreate) {
Ext.apply(me, {
subject: subject,
- items: ipanel
+ defaultFocus: me.confid !== 'rootfs' ? 'textfield[name=mp]' : 'tool',
+ items: ipanel,
});
me.callParent();
me.load({
success: function(response, options) {
ipanel.setVMConfig(response.result.data);
- if (me.confid) {
- /*jslint confusion: true*/
- /*data is defined as array above*/
- var value = response.result.data[me.confid];
- /*jslint confusion: false*/
- var mp = PVE.Parser.parseLxcMountPoint(value);
+ if (me.confid) {
+ let value = response.result.data[me.confid];
+ let mp = PVE.Parser.parseLxcMountPoint(value);
if (!mp) {
Ext.Msg.alert(gettext('Error'), 'Unable to parse mount point options');
me.close();
return;
}
-
ipanel.setMountPoint(mp);
me.isValid(); // trigger validation
}
- }
+ },
});
- }
+ },
});