]> git.proxmox.com Git - pve-manager.git/blobdiff - www/manager6/qemu/BootOrderEdit.js
update shipped appliance info index
[pve-manager.git] / www / manager6 / qemu / BootOrderEdit.js
index 9601313eacad11fb0ace51a221e550b0c9bf759d..c1f24ff4c9494d359d7c11478a1109dcfe37e245 100644 (file)
-Ext.define('PVE.qemu.BootOrderPanel', {
-    extend: 'PVE.panel.InputPanel',
-
-    vmconfig: {}, // store loaded vm config
+Ext.define('pve-boot-order-entry', {
+    extend: 'Ext.data.Model',
+    fields: [
+       { name: 'name', type: 'string' },
+       { name: 'enabled', type: 'bool' },
+       { name: 'desc', type: 'string' },
+    ],
+});
 
-    bootdisk: undefined,
-    curSel1: '',
-    curSel2: '',
-    curSel3: '',
+Ext.define('PVE.qemu.BootOrderPanel', {
+    extend: 'Proxmox.panel.InputPanel',
+    alias: 'widget.pveQemuBootOrderPanel',
 
-    onGetValues: function(values) {
-       var me = this;
+    onlineHelp: 'qm_bootorder',
 
-       var order = '';
+    vmconfig: {}, // store loaded vm config
+    store: undefined,
+
+    inUpdate: false,
+    controller: {
+       xclass: 'Ext.app.ViewController',
+
+       init: function(view) {
+           let me = this;
+
+           let grid = me.lookup('grid');
+           let marker = me.lookup('marker');
+           let emptyWarning = me.lookup('emptyWarning');
+
+           marker.originalValue = undefined;
+
+           view.store = Ext.create('Ext.data.Store', {
+               model: 'pve-boot-order-entry',
+               listeners: {
+                   update: function() {
+                       this.commitChanges();
+                       let val = view.calculateValue();
+                       if (marker.originalValue === undefined) {
+                           marker.originalValue = val;
+                       }
+                       view.inUpdate = true;
+                       marker.setValue(val);
+                       view.inUpdate = false;
+                       marker.checkDirty();
+                       emptyWarning.setHidden(val !== '');
+                       grid.getView().refresh();
+                   },
+               },
+           });
+           grid.setStore(view.store);
+       },
+    },
 
-       if (me.curSel1) {
-           order = order + me.curSel1;
-       }
-       if (me.curSel2) {
-           order = order + me.curSel2;
-       }
-       if (me.curSel3) {
-           order = order + me.curSel3;
-       }
+    isCloudinit: (v) => v.match(/media=cdrom/) && v.match(/[:/]vm-\d+-cloudinit/),
 
-       var res = { boot: order };
-       if (me.bootdisk && (me.curSel1 === 'c' || me.curSel2 === 'c' || me.curSel3 === 'c') ) {
-           res.bootdisk =  me.bootdisk;
-       } else {
-           res['delete'] = 'bootdisk';
-       } 
+    isDisk: function(value) {
+       return PVE.Utils.bus_match.test(value);
+    },
 
-       return res;
+    isBootdev: function(dev, value) {
+       return (this.isDisk(dev) && !this.isCloudinit(value)) ||
+           (/^net\d+/).test(dev) ||
+           (/^hostpci\d+/).test(dev) ||
+           ((/^usb\d+/).test(dev) && !(/spice/).test(value));
     },
 
     setVMConfig: function(vmconfig) {
-       var me = this;
-
+       let me = this;
        me.vmconfig = vmconfig;
 
-       var order = me.vmconfig.boot || 'cdn';
-       me.bootdisk = me.vmconfig.bootdisk;
-       if (!me.vmconfig[me.bootdisk]) {
-           me.bootdisk = undefined;
-       }
-       me.curSel1 = order.substring(0, 1) || '';
-       me.curSel2 = order.substring(1, 2) || '';
-       me.curSel3 = order.substring(2, 3) || '';
-
-       me.compute_sel1();
-
-       me.kv1.resetOriginalValue();
-       me.kv2.resetOriginalValue();
-       me.kv3.resetOriginalValue();
-    },
-
-    genList: function(includeNone, sel1, sel2) {
-       var me = this;
-       var list = [];
-
-       if (sel1 !== 'c' && (sel2 !== 'c')) {
-           Ext.Object.each(me.vmconfig, function(key, value) {
-               if ((/^(ide|sata|scsi|virtio)\d+$/).test(key) &&
-                   !(/media=cdrom/).test(value)) {
-                   list.push([key, "Disk '" + key + "'"]);
+       me.store.removeAll();
+
+       let boot = PVE.Parser.parsePropertyString(me.vmconfig.boot, "legacy");
+
+       let bootorder = [];
+       if (boot.order) {
+           bootorder = boot.order.split(';').map(dev => ({ name: dev, enabled: true }));
+       } else if (!(/^\s*$/).test(me.vmconfig.boot)) {
+           // legacy style, transform to new bootorder
+           let order = boot.legacy || 'cdn';
+           let bootdisk = me.vmconfig.bootdisk || undefined;
+
+           // get the first 4 characters (acdn)
+           // ignore the rest (there should never be more than 4)
+           let orderList = order.split('').slice(0, 4);
+
+           // build bootdev list
+           for (let i = 0; i < orderList.length; i++) {
+               let list = [];
+               if (orderList[i] === 'c') {
+                   if (bootdisk !== undefined && me.vmconfig[bootdisk]) {
+                       list.push(bootdisk);
+                   }
+               } else if (orderList[i] === 'd') {
+                   Ext.Object.each(me.vmconfig, function(key, value) {
+                       if (me.isDisk(key) && value.match(/media=cdrom/) && !me.isCloudinit(value)) {
+                           list.push(key);
+                       }
+                   });
+               } else if (orderList[i] === 'n') {
+                   Ext.Object.each(me.vmconfig, function(key, value) {
+                       if ((/^net\d+/).test(key)) {
+                           list.push(key);
+                       }
+                   });
                }
-           });
-       }
 
-       if (sel1 !== 'd' && (sel2 !== 'd')) {
-           list.push(['d', 'CD-ROM']);
-       }
-       if (sel1 !== 'n' && (sel2 !== 'n')) {
-           list.push(['n', gettext('Network')]);
-       }
-       //if (sel1 !== 'a' && (sel2 !== 'a')) {
-       //    list.push(['a', 'Floppy']);
-       //}
-       
-       if (includeNone) {
-           list.push(['', PVE.Utils.noneText]);
+               // Object.each iterates in random order, sort alphabetically
+               list.sort();
+               list.forEach(dev => bootorder.push({ name: dev, enabled: true }));
+           }
        }
 
-       return list;
-    },
-
-    compute_sel3: function() {
-       var me = this;
-       var list = me.genList(true, me.curSel1, me.curSel2);
-       me.kv3.store.loadData(list);
-       me.kv3.setValue((me.curSel3 === 'c') ? me.bootdisk : me.curSel3);
-    },
-
-    compute_sel2: function() {
-       var me = this;
-       var list = me.genList(true, me.curSel1);
-       me.kv2.store.loadData(list);
-       me.kv2.setValue((me.curSel2 === 'c') ? me.bootdisk : me.curSel2);
-       me.compute_sel3();
-    },
-
-    compute_sel1: function() {
-       var me = this;
-       var list = me.genList(false);
-       me.kv1.store.loadData(list);
-       me.kv1.setValue((me.curSel1 === 'c') ? me.bootdisk : me.curSel1);
-       me.compute_sel2();
-    },
-
-    initComponent : function() {
-       var me = this;
-
-       me.kv1 = Ext.create('PVE.form.KVComboBox', {
-           fieldLabel: gettext('Boot device') + " 1",
-           labelWidth: 120,
-           name: 'bd1',
-           allowBlank: false,
-           data: []
+       // add disabled devices as well
+       let disabled = [];
+       Ext.Object.each(me.vmconfig, function(key, value) {
+           if (me.isBootdev(key, value) &&
+               !Ext.Array.some(bootorder, x => x.name === key)) {
+               disabled.push(key);
+           }
        });
+       disabled.sort();
+       disabled.forEach(dev => bootorder.push({ name: dev, enabled: false }));
 
-       me.kv2 = Ext.create('PVE.form.KVComboBox', {
-           fieldLabel: gettext('Boot device') + " 2",
-           labelWidth: 120,
-           name: 'bd2',
-           allowBlank: false,
-           data: []
+       // add descriptions
+       bootorder.forEach(entry => {
+           entry.desc = me.vmconfig[entry.name];
        });
 
-       me.kv3 = Ext.create('PVE.form.KVComboBox', {
-           fieldLabel: gettext('Boot device') + " 3",
-           labelWidth: 120,
-           name: 'bd3',
-           allowBlank: false,
-           data: []
-       });
+       me.store.insert(0, bootorder);
+       me.store.fireEvent("update");
+    },
 
-       me.mon(me.kv1, 'change', function(t, value) {
-           if ((/^(ide|sata|scsi|virtio)\d+$/).test(value)) {
-               me.curSel1 = 'c';
-               me.bootdisk = value;
-           } else {
-               me.curSel1 = value;
-           }
-           me.compute_sel2();
-       });
+    calculateValue: function() {
+       let me = this;
+       return me.store.getData().items
+           .filter(x => x.data.enabled)
+           .map(x => x.data.name)
+           .join(';');
+    },
 
-       me.mon(me.kv2, 'change', function(t, value) {
-           if ((/^(ide|sata|scsi|virtio)\d+$/).test(value)) {
-               me.curSel2 = 'c';
-               me.bootdisk = value;
-           } else {
-               me.curSel2 = value;
-           }
-           me.compute_sel3();
-       });
+    onGetValues: function() {
+       let me = this;
+       // Note: we allow an empty value, so no 'delete' option
+       let val = { order: me.calculateValue() };
+       let res = { boot: PVE.Parser.printPropertyString(val) };
+       return res;
+    },
 
-       me.mon(me.kv3, 'change', function(t, value) {
-           if ((/^(ide|sata|scsi|virtio)\d+$/).test(value)) {
-               me.curSel3 = 'c';
-               me.bootdisk = value;
-           } else {
-               me.curSel3 = value;
-           }
-       });
+    items: [
+       {
+           xtype: 'grid',
+           reference: 'grid',
+           margin: '0 0 5 0',
+           minHeight: 150,
+           defaults: {
+               sortable: false,
+               hideable: false,
+               draggable: false,
+           },
+           columns: [
+               {
+                   header: '#',
+                   flex: 4,
+                   renderer: (value, metaData, record, rowIndex) => {
+                       let dragHandle = "<i class='pve-grid-fa fa fa-fw fa-reorder cursor-move'></i>";
+                       let idx = (rowIndex + 1).toString();
+                       if (record.get('enabled')) {
+                           return dragHandle + idx;
+                       } else {
+                           return dragHandle + "<span class='faded'>" + idx + "</span>";
+                       }
+                   },
+               },
+               {
+                   xtype: 'checkcolumn',
+                   header: gettext('Enabled'),
+                   dataIndex: 'enabled',
+                   flex: 4,
+               },
+               {
+                   header: gettext('Device'),
+                   dataIndex: 'name',
+                   flex: 6,
+                   renderer: (value, metaData, record, rowIndex) => {
+                       let desc = record.get('desc');
+
+                       let icon = '', iconCls;
+                       if (value.match(/^net\d+$/)) {
+                           iconCls = 'exchange';
+                       } else if (desc.match(/media=cdrom/)) {
+                           metaData.tdCls = 'pve-itype-icon-cdrom';
+                       } else {
+                           iconCls = 'hdd-o';
+                       }
+                       if (iconCls !== undefined) {
+                           metaData.tdCls += 'pve-itype-fa';
+                           icon = `<i class="pve-grid-fa fa fa-fw fa-${iconCls}"></i>`;
+                       }
+
+                       return icon + value;
+                   },
+               },
+               {
+                   header: gettext('Description'),
+                   dataIndex: 'desc',
+                   flex: 20,
+               },
+           ],
+           viewConfig: {
+               plugins: {
+                   ptype: 'gridviewdragdrop',
+                   dragText: gettext('Drag and drop to reorder'),
+               },
+           },
+           listeners: {
+               drop: function() {
+                   // doesn't fire automatically on reorder
+                   this.getStore().fireEvent("update");
+               },
+           },
+       },
+       {
+           xtype: 'component',
+           html: gettext('Drag and drop to reorder'),
+       },
+       {
+           xtype: 'displayfield',
+           reference: 'emptyWarning',
+           userCls: 'pmx-hint',
+           value: gettext('Warning: No devices selected, the VM will probably not boot!'),
+       },
+       {
+           // for dirty marking and 'reset' function
+           xtype: 'field',
+           reference: 'marker',
+           hidden: true,
+           setValue: function(val) {
+               let me = this;
+               let panel = me.up('pveQemuBootOrderPanel');
+
+               // on form reset, go back to original state
+               if (!panel.inUpdate) {
+                   panel.setVMConfig(panel.vmconfig);
+               }
 
-       Ext.apply(me, {
-           items: [ me.kv1, me.kv2, me.kv3 ]   
-       });
-       
-       me.callParent();
-    }
+               // not a subclass, so no callParent; just do it manually
+               me.setRawValue(me.valueToRaw(val));
+               return me.mixins.field.setValue.call(me, val);
+           },
+       },
+    ],
 });
 
 Ext.define('PVE.qemu.BootOrderEdit', {
-    extend: 'PVE.window.Edit',
+    extend: 'Proxmox.window.Edit',
 
-    initComponent : function() {
-       var me = this;
-       
-       var ipanel = Ext.create('PVE.qemu.BootOrderPanel', {});
+    items: [{
+       xtype: 'pveQemuBootOrderPanel',
+       itemId: 'inputpanel',
+    }],
 
-       me.items = [ ipanel ];
-
-       me.subject = gettext('Boot order');
+    subject: gettext('Boot Order'),
+    width: 640,
 
+    initComponent: function() {
+       let me = this;
        me.callParent();
-       
        me.load({
-           success: function(response, options) {
-               ipanel.setVMConfig(response.result.data);
-           }
+           success: ({ result }) => me.down('#inputpanel').setVMConfig(result.data),
        });
-    }
+    },
 });