]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/qemu/BootOrderEdit.js
ui: bootorder: set minHeight for grid to conceal the long load time a bit
[pve-manager.git] / www / manager6 / qemu / BootOrderEdit.js
CommitLineData
1cc7c672
SR
1Ext.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 10Ext.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
242Ext.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});