]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/lxc/MPEdit.js
ui: lxc: do not righ-align labels
[pve-manager.git] / www / manager6 / lxc / MPEdit.js
1 Ext.define('PVE.lxc.MountPointInputPanel', {
2 extend: 'Proxmox.panel.InputPanel',
3 xtype: 'pveLxcMountPointInputPanel',
4
5 onlineHelp: 'pct_container_storage',
6
7 insideWizard: false,
8
9 unused: false, // add unused disk imaged
10 unprivileged: false,
11
12 vmconfig: {}, // used to select unused disks
13
14 setUnprivileged: function(unprivileged) {
15 var me = this;
16 var vm = me.getViewModel();
17 me.unprivileged = unprivileged;
18 vm.set('unpriv', unprivileged);
19 },
20
21 onGetValues: function(values) {
22 var me = this;
23
24 var confid = me.confid || "mp"+values.mpid;
25 me.mp.file = me.down('field[name=file]').getValue();
26
27 if (me.unused) {
28 confid = "mp"+values.mpid;
29 } else if (me.isCreate) {
30 me.mp.file = values.hdstorage + ':' + values.disksize;
31 }
32
33 // delete unnecessary fields
34 delete values.mpid;
35 delete values.hdstorage;
36 delete values.disksize;
37 delete values.diskformat;
38
39 let setMPOpt = (k, src, v) => PVE.Utils.propertyStringSet(me.mp, src, k, v);
40
41 setMPOpt('mp', values.mp);
42 let mountOpts = (values.mountoptions || []).join(';');
43 setMPOpt('mountoptions', values.mountoptions, mountOpts);
44 setMPOpt('mp', values.mp);
45 setMPOpt('backup', values.backup);
46 setMPOpt('quota', values.quota);
47 setMPOpt('ro', values.ro);
48 setMPOpt('acl', values.acl);
49 setMPOpt('replicate', values.replicate);
50
51 let res = {};
52 res[confid] = PVE.Parser.printLxcMountPoint(me.mp);
53 return res;
54 },
55
56 setMountPoint: function(mp) {
57 let me = this;
58 let vm = me.getViewModel();
59 vm.set('mptype', mp.type);
60 if (mp.mountoptions) {
61 mp.mountoptions = mp.mountoptions.split(';');
62 }
63 me.mp = mp;
64 me.filterMountOptions();
65 me.setValues(mp);
66 },
67
68 filterMountOptions: function() {
69 let me = this;
70 if (me.confid === 'rootfs') {
71 let field = me.down('field[name=mountoptions]');
72 let exclude = ['nodev', 'noexec'];
73 let filtered = field.comboItems.filter(v => !exclude.includes(v[0]));
74 field.setComboItems(filtered);
75 }
76 },
77
78 updateVMConfig: function(vmconfig) {
79 let me = this;
80 let vm = me.getViewModel();
81 me.vmconfig = vmconfig;
82 vm.set('unpriv', vmconfig.unprivileged);
83 me.down('field[name=mpid]').validate();
84 },
85
86 setVMConfig: function(vmconfig) {
87 let me = this;
88
89 me.updateVMConfig(vmconfig);
90 PVE.Utils.forEachLxcMP((bus, i, name) => {
91 if (!Ext.isDefined(vmconfig[name])) {
92 me.down('field[name=mpid]').setValue(i);
93 return false;
94 }
95 return undefined;
96 });
97 },
98
99 setNodename: function(nodename) {
100 let me = this;
101 let vm = me.getViewModel();
102 vm.set('node', nodename);
103 me.down('#diskstorage').setNodename(nodename);
104 },
105
106 controller: {
107 xclass: 'Ext.app.ViewController',
108
109 control: {
110 'field[name=mpid]': {
111 change: function(field, value) {
112 let me = this;
113 let view = this.getView();
114 if (view.confid !== 'rootfs') {
115 view.fireEvent('diskidchange', view, `mp${value}`);
116 }
117 field.validate();
118 },
119 },
120 '#hdstorage': {
121 change: function(field, newValue) {
122 let me = this;
123 if (!newValue) {
124 return;
125 }
126
127 let rec = field.store.getById(newValue);
128 if (!rec) {
129 return;
130 }
131 me.getViewModel().set('type', rec.data.type);
132 },
133 },
134 },
135 init: function(view) {
136 let me = this;
137 let vm = this.getViewModel();
138 view.mp = {};
139 vm.set('confid', view.confid);
140 vm.set('unused', view.unused);
141 vm.set('node', view.nodename);
142 vm.set('unpriv', view.unprivileged);
143 vm.set('hideStorSelector', view.unused || !view.isCreate);
144
145 if (view.isCreate) { // can be array if created from unused disk
146 vm.set('isIncludedInBackup', true);
147 if (view.insideWizard) {
148 view.filterMountOptions();
149 }
150 }
151 if (view.selectFree) {
152 view.setVMConfig(view.vmconfig);
153 }
154 },
155 },
156
157 viewModel: {
158 data: {
159 unpriv: false,
160 unused: false,
161 showStorageSelector: false,
162 mptype: '',
163 type: '',
164 confid: '',
165 node: '',
166 },
167
168 formulas: {
169 quota: function(get) {
170 return !(get('type') === 'zfs' ||
171 get('type') === 'zfspool' ||
172 get('unpriv') ||
173 get('isBind'));
174 },
175 hasMP: function(get) {
176 return !!get('confid') && !get('unused');
177 },
178 isRoot: function(get) {
179 return get('confid') === 'rootfs';
180 },
181 isBind: function(get) {
182 return get('mptype') === 'bind';
183 },
184 isBindOrRoot: function(get) {
185 return get('isBind') || get('isRoot');
186 },
187 },
188 },
189
190 column1: [
191 {
192 xtype: 'proxmoxintegerfield',
193 name: 'mpid',
194 fieldLabel: gettext('Mount Point ID'),
195 minValue: 0,
196 maxValue: PVE.Utils.lxc_mp_counts.mp - 1,
197 hidden: true,
198 allowBlank: false,
199 disabled: true,
200 bind: {
201 hidden: '{hasMP}',
202 disabled: '{hasMP}',
203 },
204 validator: function(value) {
205 let view = this.up('inputpanel');
206 if (!view.rendered) {
207 return undefined;
208 }
209 if (Ext.isDefined(view.vmconfig["mp"+value])) {
210 return "Mount point is already in use.";
211 }
212 return true;
213 },
214 },
215 {
216 xtype: 'pveDiskStorageSelector',
217 itemId: 'diskstorage',
218 storageContent: 'rootdir',
219 hidden: true,
220 autoSelect: true,
221 selectformat: false,
222 defaultSize: 8,
223 bind: {
224 hidden: '{hideStorSelector}',
225 disabled: '{hideStorSelector}',
226 nodename: '{node}',
227 },
228 },
229 {
230 xtype: 'textfield',
231 disabled: true,
232 submitValue: false,
233 fieldLabel: gettext('Disk image'),
234 name: 'file',
235 bind: {
236 hidden: '{!hideStorSelector}',
237 },
238 },
239 ],
240
241 column2: [
242 {
243 xtype: 'textfield',
244 name: 'mp',
245 value: '',
246 emptyText: gettext('/some/path'),
247 allowBlank: false,
248 disabled: true,
249 fieldLabel: gettext('Path'),
250 bind: {
251 hidden: '{isRoot}',
252 disabled: '{isRoot}',
253 },
254 },
255 {
256 xtype: 'proxmoxcheckbox',
257 name: 'backup',
258 fieldLabel: gettext('Backup'),
259 autoEl: {
260 tag: 'div',
261 'data-qtip': gettext('Include volume in backup job'),
262 },
263 bind: {
264 hidden: '{isRoot}',
265 disabled: '{isBindOrRoot}',
266 value: '{isIncludedInBackup}',
267 },
268 },
269 ],
270
271 advancedColumn1: [
272 {
273 xtype: 'proxmoxcheckbox',
274 name: 'quota',
275 defaultValue: 0,
276 bind: {
277 disabled: '{!quota}',
278 },
279 fieldLabel: gettext('Enable quota'),
280 listeners: {
281 disable: function() {
282 this.reset();
283 },
284 },
285 },
286 {
287 xtype: 'proxmoxcheckbox',
288 name: 'ro',
289 defaultValue: 0,
290 bind: {
291 hidden: '{isRoot}',
292 disabled: '{isRoot}',
293 },
294 fieldLabel: gettext('Read-only'),
295 },
296 {
297 xtype: 'proxmoxKVComboBox',
298 name: 'mountoptions',
299 fieldLabel: gettext('Mount options'),
300 deleteEmpty: false,
301 comboItems: [
302 ['lazytime', 'lazytime'],
303 ['noatime', 'noatime'],
304 ['nodev', 'nodev'],
305 ['noexec', 'noexec'],
306 ['nosuid', 'nosuid'],
307 ],
308 multiSelect: true,
309 value: [],
310 allowBlank: true,
311 },
312 ],
313
314 advancedColumn2: [
315 {
316 xtype: 'proxmoxKVComboBox',
317 name: 'acl',
318 fieldLabel: 'ACLs',
319 deleteEmpty: false,
320 comboItems: [
321 ['__default__', Proxmox.Utils.defaultText],
322 ['1', Proxmox.Utils.enabledText],
323 ['0', Proxmox.Utils.disabledText],
324 ],
325 value: '__default__',
326 bind: {
327 disabled: '{isBind}',
328 },
329 allowBlank: true,
330 },
331 {
332 xtype: 'proxmoxcheckbox',
333 inputValue: '0', // reverses the logic
334 name: 'replicate',
335 fieldLabel: gettext('Skip replication'),
336 },
337 ],
338 });
339
340 Ext.define('PVE.lxc.MountPointEdit', {
341 extend: 'Proxmox.window.Edit',
342
343 unprivileged: false,
344
345 initComponent: function() {
346 let me = this;
347
348 let nodename = me.pveSelNode.data.node;
349 if (!nodename) {
350 throw "no node name specified";
351 }
352
353 let unused = me.confid && me.confid.match(/^unused\d+$/);
354
355 me.isCreate = me.confid ? unused : true;
356
357 let ipanel = Ext.create('PVE.lxc.MountPointInputPanel', {
358 confid: me.confid,
359 nodename: nodename,
360 unused: unused,
361 unprivileged: me.unprivileged,
362 isCreate: me.isCreate,
363 });
364
365 let subject;
366 if (unused) {
367 subject = gettext('Unused Disk');
368 } else if (me.isCreate) {
369 subject = gettext('Mount Point');
370 } else {
371 subject = gettext('Mount Point') + ' (' + me.confid + ')';
372 }
373
374 Ext.apply(me, {
375 subject: subject,
376 defaultFocus: me.confid !== 'rootfs' ? 'textfield[name=mp]' : 'tool',
377 items: ipanel,
378 });
379
380 me.callParent();
381
382 me.load({
383 success: function(response, options) {
384 ipanel.setVMConfig(response.result.data);
385
386 if (me.confid) {
387 let value = response.result.data[me.confid];
388 let mp = PVE.Parser.parseLxcMountPoint(value);
389 if (!mp) {
390 Ext.Msg.alert(gettext('Error'), 'Unable to parse mount point options');
391 me.close();
392 return;
393 }
394 ipanel.setMountPoint(mp);
395 me.isValid(); // trigger validation
396 }
397 },
398 });
399 },
400 });