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