]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/qemu/BootOrderEdit.js
ui: bootorder: define all column widths flex
[pve-manager.git] / www / manager6 / qemu / BootOrderEdit.js
1 Ext.define('pve-boot-order-entry', {
2 extend: 'Ext.data.Model',
3 fields: [
4 {name: 'name', type: 'string'},
5 {name: 'enabled', type: 'bool'},
6 {name: 'desc', type: 'string'},
7 ]
8 });
9
10 Ext.define('PVE.qemu.BootOrderPanel', {
11 extend: 'Proxmox.panel.InputPanel',
12 alias: 'widget.pveQemuBootOrderPanel',
13
14 vmconfig: {}, // store loaded vm config
15 store: undefined,
16
17 inUpdate: false,
18 controller: {
19 xclass: 'Ext.app.ViewController',
20 },
21
22 isDisk: function(value) {
23 return PVE.Utils.bus_match.test(value);
24 },
25
26 isBootdev: function(dev, value) {
27 return this.isDisk(dev) ||
28 (/^net\d+/).test(dev) ||
29 (/^hostpci\d+/).test(dev) ||
30 ((/^usb\d+/).test(dev) && !(/spice/).test(value));
31 },
32
33 setVMConfig: function(vmconfig) {
34 let me = this;
35 me.vmconfig = vmconfig;
36
37 me.store.removeAll();
38
39 let boot = PVE.Parser.parsePropertyString(me.vmconfig.boot, "legacy");
40
41 let bootorder = [];
42 if (boot.order) {
43 bootorder = boot.order.split(';').map(dev => ({name: dev, enabled: true}));
44 } else if (!(/^\s*$/).test(me.vmconfig.boot)) {
45 // legacy style, transform to new bootorder
46 let order = boot.legacy || 'cdn';
47 let bootdisk = me.vmconfig.bootdisk || undefined;
48
49 // get the first 4 characters (acdn)
50 // ignore the rest (there should never be more than 4)
51 let orderList = order.split('').slice(0,4);
52
53 // build bootdev list
54 for (let i = 0; i < orderList.length; i++) {
55 let list = [];
56 if (orderList[i] === 'c') {
57 if (bootdisk !== undefined && me.vmconfig[bootdisk]) {
58 list.push(bootdisk);
59 }
60 } else if (orderList[i] === 'd') {
61 Ext.Object.each(me.vmconfig, function(key, value) {
62 if (me.isDisk(key) && (/media=cdrom/).test(value)) {
63 list.push(key);
64 }
65 });
66 } else if (orderList[i] === 'n') {
67 Ext.Object.each(me.vmconfig, function(key, value) {
68 if ((/^net\d+/).test(key)) {
69 list.push(key);
70 }
71 });
72 }
73
74 // Object.each iterates in random order, sort alphabetically
75 list.sort();
76 list.forEach(dev => bootorder.push({name: dev, enabled: true}));
77 }
78 }
79
80 // add disabled devices as well
81 let disabled = [];
82 Ext.Object.each(me.vmconfig, function(key, value) {
83 if (me.isBootdev(key, value) &&
84 !Ext.Array.some(bootorder, x => x.name === key))
85 {
86 disabled.push(key);
87 }
88 });
89 disabled.sort();
90 disabled.forEach(dev => bootorder.push({name: dev, enabled: false}));
91
92 // add descriptions
93 bootorder.forEach(entry => {
94 entry.desc = me.vmconfig[entry.name];
95 });
96
97 me.store.insert(0, bootorder);
98 me.store.fireEvent("update");
99 },
100
101 calculateValue: function() {
102 let me = this;
103 return me.store.getData().items
104 .filter(x => x.data.enabled)
105 .map(x => x.data.name)
106 .join(';');
107 },
108
109 onGetValues: function() {
110 let me = this;
111 // Note: we allow an empty value, so no 'delete' option
112 let val = { order: me.calculateValue() };
113 let res = { boot: PVE.Parser.printPropertyString(val) };
114 return res;
115 },
116
117 items: [
118 {
119 xtype: 'grid',
120 reference: 'grid',
121 margin: '0 0 5 0',
122 minHeight: 150,
123 defaults: {
124 sortable: false,
125 hideable: false,
126 draggable: false,
127 },
128 columns: [
129 {
130 header: '#',
131 flex: 4,
132 renderer: (value, metaData, record, rowIndex) => {
133 let dragHandle = "<i class='pve-grid-fa fa fa-fw fa-reorder cursor-move'></i>";
134 let idx = (rowIndex + 1).toString();
135 if (record.get('enabled')) {
136 return dragHandle + idx;
137 } else {
138 return dragHandle + "<span class='faded'>" + idx + "</span>";
139 }
140 },
141 },
142 {
143 xtype: 'checkcolumn',
144 header: gettext('Enabled'),
145 dataIndex: 'enabled',
146 flex: 4,
147 },
148 {
149 header: gettext('Device'),
150 dataIndex: 'name',
151 flex: 6,
152 },
153 {
154 header: gettext('Description'),
155 dataIndex: 'desc',
156 flex: 20,
157 },
158 ],
159 viewConfig: {
160 plugins: {
161 ptype: 'gridviewdragdrop',
162 dragText: gettext('Drag and drop to reorder'),
163 }
164 },
165 listeners: {
166 drop: function() {
167 // doesn't fire automatically on reorder
168 this.getStore().fireEvent("update");
169 }
170 },
171 },
172 {
173 xtype: 'component',
174 html: gettext('Drag and drop to reorder'),
175 },
176 {
177 xtype: 'displayfield',
178 reference: 'emptyWarning',
179 userCls: 'pmx-hint',
180 value: gettext('Warning: No devices selected, the VM will probably not boot!'),
181 },
182 {
183 // for dirty marking and 'reset' function
184 xtype: 'field',
185 reference: 'marker',
186 hidden: true,
187 setValue: function(val) {
188 let me = this;
189 let panel = me.up('pveQemuBootOrderPanel');
190
191 // on form reset, go back to original state
192 if (!panel.inUpdate) {
193 panel.setVMConfig(panel.vmconfig);
194 }
195
196 // not a subclass, so no callParent; just do it manually
197 me.setRawValue(me.valueToRaw(val));
198 return me.mixins.field.setValue.call(me, val);
199 }
200 },
201 ],
202
203 initComponent: function() {
204 let me = this;
205
206 me.callParent();
207
208 let controller = me.getController();
209
210 let grid = controller.lookup('grid');
211 let marker = controller.lookup('marker');
212 let emptyWarning = controller.lookup('emptyWarning');
213
214 marker.originalValue = undefined;
215
216 me.store = Ext.create('Ext.data.Store', {
217 model: 'pve-boot-order-entry',
218 listeners: {
219 update: function() {
220 this.commitChanges();
221 let val = me.calculateValue();
222 if (marker.originalValue === undefined) {
223 marker.originalValue = val;
224 }
225 me.inUpdate = true;
226 marker.setValue(val);
227 me.inUpdate = false;
228 marker.checkDirty();
229 emptyWarning.setHidden(val !== '');
230 grid.getView().refresh();
231 }
232 }
233 });
234 grid.setStore(me.store);
235 }
236 });
237
238 Ext.define('PVE.qemu.BootOrderEdit', {
239 extend: 'Proxmox.window.Edit',
240
241 items: [{
242 xtype: 'pveQemuBootOrderPanel',
243 itemId: 'inputpanel'
244 }],
245
246 subject: gettext('Boot Order'),
247 width: 640,
248
249 initComponent : function() {
250 let me = this;
251 me.callParent();
252 me.load({
253 success: function(response, options) {
254 me.down('#inputpanel').setVMConfig(response.result.data);
255 }
256 });
257 }
258 });