]>
Commit | Line | Data |
---|---|---|
1cc7c672 SR |
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 | ||
638a57e7 | 10 | Ext.define('PVE.qemu.BootOrderPanel', { |
ef4ef788 | 11 | extend: 'Proxmox.panel.InputPanel', |
adaac36f | 12 | alias: 'widget.pveQemuBootOrderPanel', |
1cc7c672 | 13 | |
638a57e7 | 14 | vmconfig: {}, // store loaded vm config |
1cc7c672 | 15 | store: undefined, |
638a57e7 | 16 | |
1cc7c672 SR |
17 | inUpdate: false, |
18 | controller: { | |
19 | xclass: 'Ext.app.ViewController', | |
20 | }, | |
638a57e7 | 21 | |
1cc7c672 | 22 | isDisk: function(value) { |
98a01af2 | 23 | return PVE.Utils.bus_match.test(value); |
4edfc518 DC |
24 | }, |
25 | ||
1cc7c672 SR |
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 | ||
638a57e7 | 33 | setVMConfig: function(vmconfig) { |
1cc7c672 | 34 | let me = this; |
638a57e7 | 35 | me.vmconfig = vmconfig; |
adaac36f | 36 | |
1cc7c672 | 37 | me.store.removeAll(); |
638a57e7 | 38 | |
1cc7c672 | 39 | let boot = PVE.Parser.parsePropertyString(me.vmconfig.boot, "legacy"); |
638a57e7 | 40 | |
1cc7c672 SR |
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; | |
9e7b4d8d | 48 | |
1cc7c672 SR |
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); | |
638a57e7 | 52 | |
1cc7c672 SR |
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 | } | |
638a57e7 | 73 | |
1cc7c672 SR |
74 | // Object.each iterates in random order, sort alphabetically |
75 | list.sort(); | |
76 | list.forEach(dev => bootorder.push({name: dev, enabled: true})); | |
77 | } | |
638a57e7 DM |
78 | } |
79 | ||
1cc7c672 SR |
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); | |
adaac36f | 87 | } |
1cc7c672 SR |
88 | }); |
89 | disabled.sort(); | |
90 | disabled.forEach(dev => bootorder.push({name: dev, enabled: false})); | |
638a57e7 | 91 | |
1cc7c672 SR |
92 | // add descriptions |
93 | bootorder.forEach(entry => { | |
94 | entry.desc = me.vmconfig[entry.name]; | |
adaac36f | 95 | }); |
638a57e7 | 96 | |
1cc7c672 SR |
97 | me.store.insert(0, bootorder); |
98 | me.store.fireEvent("update"); | |
638a57e7 DM |
99 | }, |
100 | ||
1cc7c672 SR |
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(';'); | |
adaac36f | 107 | }, |
638a57e7 | 108 | |
1cc7c672 SR |
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', | |
eacd918e | 122 | minHeight: 150, |
93775406 TL |
123 | defaults: { |
124 | sortable: false, | |
125 | hideable: false, | |
126 | draggable: false, | |
127 | }, | |
1cc7c672 SR |
128 | columns: [ |
129 | { | |
130 | header: '', | |
131 | renderer: () => "<i class='fa fa-reorder cursor-move'></i>", | |
132 | width: 30, | |
1cc7c672 SR |
133 | }, |
134 | { | |
135 | header: '#', | |
136 | width: 30, | |
1cc7c672 SR |
137 | renderer: (value, metaData, record, rowIndex) => { |
138 | let idx = (rowIndex + 1).toString(); | |
139 | if (record.get('enabled')) { | |
140 | return idx; | |
141 | } else { | |
142 | return "<span class='faded'>" + idx + "</span>"; | |
143 | } | |
144 | }, | |
145 | }, | |
146 | { | |
147 | xtype: 'checkcolumn', | |
148 | header: gettext('Enabled'), | |
149 | dataIndex: 'enabled', | |
150 | width: 70, | |
1cc7c672 SR |
151 | }, |
152 | { | |
153 | header: gettext('Device'), | |
154 | dataIndex: 'name', | |
155 | width: 70, | |
1cc7c672 SR |
156 | }, |
157 | { | |
158 | header: gettext('Description'), | |
159 | dataIndex: 'desc', | |
160 | flex: true, | |
1cc7c672 SR |
161 | }, |
162 | ], | |
163 | viewConfig: { | |
164 | plugins: { | |
165 | ptype: 'gridviewdragdrop', | |
166 | dragText: gettext('Drag and drop to reorder'), | |
adaac36f | 167 | } |
1cc7c672 SR |
168 | }, |
169 | listeners: { | |
170 | drop: function() { | |
171 | // doesn't fire automatically on reorder | |
172 | this.getStore().fireEvent("update"); | |
adaac36f | 173 | } |
1cc7c672 SR |
174 | }, |
175 | }, | |
176 | { | |
177 | xtype: 'component', | |
178 | html: gettext('Drag and drop to reorder'), | |
179 | }, | |
180 | { | |
181 | xtype: 'displayfield', | |
182 | reference: 'emptyWarning', | |
183 | userCls: 'pmx-hint', | |
184 | value: gettext('Warning: No devices selected, the VM will probably not boot!'), | |
185 | }, | |
186 | { | |
187 | // for dirty marking and 'reset' function | |
188 | xtype: 'field', | |
189 | reference: 'marker', | |
190 | hidden: true, | |
191 | setValue: function(val) { | |
192 | let me = this; | |
193 | let panel = me.up('pveQemuBootOrderPanel'); | |
194 | ||
195 | // on form reset, go back to original state | |
196 | if (!panel.inUpdate) { | |
197 | panel.setVMConfig(panel.vmconfig); | |
adaac36f | 198 | } |
1cc7c672 SR |
199 | |
200 | // not a subclass, so no callParent; just do it manually | |
201 | me.setRawValue(me.valueToRaw(val)); | |
202 | return me.mixins.field.setValue.call(me, val); | |
203 | } | |
204 | }, | |
205 | ], | |
206 | ||
207 | initComponent: function() { | |
208 | let me = this; | |
209 | ||
638a57e7 | 210 | me.callParent(); |
1cc7c672 SR |
211 | |
212 | let controller = me.getController(); | |
213 | ||
214 | let grid = controller.lookup('grid'); | |
215 | let marker = controller.lookup('marker'); | |
216 | let emptyWarning = controller.lookup('emptyWarning'); | |
217 | ||
218 | marker.originalValue = undefined; | |
219 | ||
220 | me.store = Ext.create('Ext.data.Store', { | |
221 | model: 'pve-boot-order-entry', | |
222 | listeners: { | |
223 | update: function() { | |
224 | this.commitChanges(); | |
225 | let val = me.calculateValue(); | |
226 | if (marker.originalValue === undefined) { | |
227 | marker.originalValue = val; | |
228 | } | |
229 | me.inUpdate = true; | |
230 | marker.setValue(val); | |
231 | me.inUpdate = false; | |
232 | marker.checkDirty(); | |
233 | emptyWarning.setHidden(val !== ''); | |
234 | grid.getView().refresh(); | |
235 | } | |
236 | } | |
237 | }); | |
238 | grid.setStore(me.store); | |
638a57e7 DM |
239 | } |
240 | }); | |
241 | ||
242 | Ext.define('PVE.qemu.BootOrderEdit', { | |
9fccc702 | 243 | extend: 'Proxmox.window.Edit', |
638a57e7 | 244 | |
ec0bd652 | 245 | items: [{ |
adaac36f | 246 | xtype: 'pveQemuBootOrderPanel', |
ec0bd652 DC |
247 | itemId: 'inputpanel' |
248 | }], | |
638a57e7 | 249 | |
adaac36f | 250 | subject: gettext('Boot Order'), |
1cc7c672 | 251 | width: 600, |
638a57e7 | 252 | |
adaac36f | 253 | initComponent : function() { |
1cc7c672 | 254 | let me = this; |
638a57e7 | 255 | me.callParent(); |
638a57e7 DM |
256 | me.load({ |
257 | success: function(response, options) { | |
adaac36f | 258 | me.down('#inputpanel').setVMConfig(response.result.data); |
638a57e7 DM |
259 | } |
260 | }); | |
261 | } | |
262 | }); |