[pve-devel] [PATCH manager 3/4] add usbselector and usb edit window for qemu
Dominik Csapak
d.csapak at proxmox.com
Mon May 29 10:46:33 CEST 2017
the edit window has 3 radiobuttons (spice,device,port)
and a checkbox for usb3 (which gets disabled and checked
if you choose a usb3 device)
also it makes use of the help feature
Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
this need my previous patch for pve-docs to get the help section
www/manager6/Makefile | 2 +
www/manager6/form/USBSelector.js | 145 ++++++++++++++++++++++++++
www/manager6/qemu/USBEdit.js | 213 +++++++++++++++++++++++++++++++++++++++
3 files changed, 360 insertions(+)
create mode 100644 www/manager6/form/USBSelector.js
create mode 100644 www/manager6/qemu/USBEdit.js
diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 0c266ef7..4bfc5fd0 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -70,6 +70,7 @@ JSSRC= \
form/GlobalSearchField.js \
form/QemuBiosSelector.js \
form/VMSelector.js \
+ form/USBSelector.js \
dc/Tasks.js \
dc/Log.js \
panel/StatusPanel.js \
@@ -158,6 +159,7 @@ JSSRC= \
qemu/SnapshotTree.js \
qemu/Config.js \
qemu/CreateWizard.js \
+ qemu/USBEdit.js \
lxc/Summary.js \
lxc/Network.js \
lxc/Resources.js \
diff --git a/www/manager6/form/USBSelector.js b/www/manager6/form/USBSelector.js
new file mode 100644
index 00000000..bc09b8d6
--- /dev/null
+++ b/www/manager6/form/USBSelector.js
@@ -0,0 +1,145 @@
+Ext.define('PVE.form.USBSelector', {
+ extend: 'PVE.form.ComboGrid',
+ alias: ['widget.pveUSBSelector'],
+ allowBlank: false,
+ autoSelect: false,
+ displayField: 'usbid',
+ valueField: 'usbid',
+ editable: true,
+
+ getUSBValue: function() {
+ var me = this;
+ var rec = me.store.findRecord('usbid', me.value);
+ var val = 'host='+ me.value;
+ if (rec && rec.data.speed === "5000") {
+ val = 'host=' + me.value + ",usb3=1";
+ }
+ return val;
+ },
+
+ validator: function(value) {
+ var me = this;
+ if (me.type === 'device') {
+ return (/^[a-f0-9]{4}\:[a-f0-9]{4}$/i).test(value);
+ } else if (me.type === 'port') {
+ return (/^[0-9]+\-[0-9]+(\.[0-9]+)*$/).test(value);
+ }
+ return false;
+ },
+
+ initComponent: function() {
+ var me = this;
+
+ var nodename = me.pveSelNode.data.node;
+
+ if (!nodename) {
+ throw "no nodename specified";
+ }
+
+ if (me.type !== 'device' && me.type !== 'port') {
+ throw "no valid type specified";
+ }
+
+ var store = new Ext.data.Store({
+ model: 'pve-usb-' + me.type,
+ proxy: {
+ type: 'pve',
+ url: "/api2/json/nodes/" + nodename + "/scan/usb"
+ },
+ filters: [
+ function (item) {
+ return !!item.data.usbpath && !!item.data.prodid && item.data['class'] != 9;
+ }
+ ]
+ });
+
+ Ext.apply(me, {
+ store: store,
+ listConfig: {
+ columns: [
+ {
+ header: (me.type === 'device')?gettext('Device'):gettext('Port'),
+ sortable: true,
+ dataIndex: 'usbid',
+ width: 80
+ },
+ {
+ header: gettext('Manufacturer'),
+ sortable: true,
+ dataIndex: 'manufacturer',
+ width: 100
+ },
+ {
+ header: gettext('Product'),
+ sortable: true,
+ dataIndex: 'product',
+ flex: 1
+ },
+ {
+ header: gettext('Speed'),
+ width: 70,
+ sortable: true,
+ dataIndex: 'speed',
+ renderer: function(value) {
+ if (value === "5000") {
+ return "USB 3.0";
+ } else if (value === "480") {
+ return "USB 2.0";
+ } else {
+ return "USB 1.x";
+ }
+ }
+ }
+ ]
+ }
+ });
+
+ me.callParent();
+
+ store.load();
+ }
+
+}, function() {
+
+ Ext.define('pve-usb-device', {
+ extend: 'Ext.data.Model',
+ fields: [
+ {
+ name: 'usbid',
+ convert: function(val, data) {
+ if (val) {
+ return val;
+ }
+ return data.get('vendid') + ':' + data.get('prodid');
+ }
+ },
+ 'speed', 'product', 'manufacturer', 'vendid', 'prodid', 'usbpath',
+ { name: 'port' , type: 'number' },
+ { name: 'level' , type: 'number' },
+ { name: 'class' , type: 'number' },
+ { name: 'devnum' , type: 'number' },
+ { name: 'busnum' , type: 'number' }
+ ]
+ });
+
+ Ext.define('pve-usb-port', {
+ extend: 'Ext.data.Model',
+ fields: [
+ {
+ name: 'usbid',
+ convert: function(val,data) {
+ if (val) {
+ return val;
+ }
+ return data.get('busnum') + '-' + data.get('usbpath');
+ }
+ },
+ 'speed', 'product', 'manufacturer', 'vendid', 'prodid', 'usbpath',
+ { name: 'port' , type: 'number' },
+ { name: 'level' , type: 'number' },
+ { name: 'class' , type: 'number' },
+ { name: 'devnum' , type: 'number' },
+ { name: 'busnum' , type: 'number' }
+ ]
+ });
+});
diff --git a/www/manager6/qemu/USBEdit.js b/www/manager6/qemu/USBEdit.js
new file mode 100644
index 00000000..ad360506
--- /dev/null
+++ b/www/manager6/qemu/USBEdit.js
@@ -0,0 +1,213 @@
+Ext.define('PVE.qemu.USBInputPanel', {
+ extend: 'PVE.panel.InputPanel',
+
+ autoComplete: false,
+ onlineHelp: 'qm_usb_passthrough',
+
+ controller: {
+ xclass: 'Ext.app.ViewController',
+
+ control: {
+ 'field[name=usb]': {
+ change: function(field, newValue, oldValue) {
+ var hwidfield = this.lookupReference('hwid');
+ var portfield = this.lookupReference('port');
+ var usb3field = this.lookupReference('usb3');
+ if (field.inputValue === 'hostdevice') {
+ hwidfield.setDisabled(!newValue);
+ } else if(field.inputValue === 'port') {
+ portfield.setDisabled(!newValue);
+ } else if(field.inputValue === 'spice') {
+ usb3field.setDisabled(newValue);
+ }
+ }
+ },
+ 'pveUSBSelector': {
+ change: function(field, newValue, oldValue) {
+ var usbval = field.getUSBValue();
+ var usb3field = this.lookupReference('usb3');
+ var usb3 = /usb3/.test(usbval);
+ if(usb3 && !usb3field.isDisabled()) {
+ usb3field.savedVal = usb3field.getValue();
+ usb3field.setValue(true);
+ usb3field.setDisabled(true);
+ } else if(!usb3 && usb3field.isDisabled()){
+ var val = (usb3field.savedVal === undefined)?usb3field.originalValue:usb3field.savedVal;
+ usb3field.setValue(val);
+ usb3field.setDisabled(false);
+ }
+ }
+ }
+ }
+ },
+
+ setVMConfig: function(vmconfig) {
+ var me = this;
+ me.vmconfig = vmconfig;
+ },
+
+ onGetValues: function(values) {
+ var me = this;
+ if(!me.confid) {
+ var i;
+ for (i = 0; i < 6; i++) {
+ if (!me.vmconfig['usb' + i.toString()]) {
+ me.confid = 'usb' + i.toString();
+ break;
+ }
+ }
+ }
+ var val = "";
+ var type = me.down('radiofield').getGroupValue();
+ switch (type) {
+ case 'spice':
+ val = 'spice'; break;
+ case 'hostdevice':
+ case 'port':
+ val = me.down('pveUSBSelector[name=' + type + ']').getUSBValue();
+ if (!/usb3/.test(val) && me.down('field[name=usb3]').getValue() === true) {
+ val += ',usb3=1';
+ }
+ break;
+ default:
+ throw "invalid type selected";
+ }
+
+ values[me.confid] = val;
+ return values;
+ },
+
+ initComponent: function () {
+ var me = this;
+
+ var items = [
+ {
+ xtype: 'fieldcontainer',
+ defaultType: 'radiofield',
+ items:[
+ {
+ name: 'usb',
+ inputValue: 'spice',
+ boxLabel: gettext('Spice Port'),
+ submitValue: false,
+ checked: true
+ },
+ {
+ name: 'usb',
+ inputValue: 'hostdevice',
+ boxLabel: gettext('Use USB Vendor/Device ID'),
+ submitValue: false
+ },
+ {
+ xtype: 'pveUSBSelector',
+ disabled: true,
+ type: 'device',
+ name: 'hostdevice',
+ pveSelNode: me.pveSelNode,
+ editable: true,
+ reference: 'hwid',
+ allowBlank: false,
+ fieldLabel: 'Choose Device',
+ labelAlign: 'right',
+ submitValue: false
+ },
+ {
+ name: 'usb',
+ inputValue: 'port',
+ boxLabel: gettext('Use USB Port'),
+ submitValue: false
+ },
+ {
+ xtype: 'pveUSBSelector',
+ disabled: true,
+ name: 'port',
+ pveSelNode: me.pveSelNode,
+ editable: true,
+ type: 'port',
+ reference: 'port',
+ allowBlank: false,
+ fieldLabel: gettext('Choose Port'),
+ labelAlign: 'right',
+ submitValue: false
+ },
+ {
+ xtype: 'checkbox',
+ name: 'usb3',
+ submitValue: false,
+ reference: 'usb3',
+ fieldLabel: gettext('Use USB3')
+ }
+ ]
+ }
+ ];
+
+ Ext.apply(me, {
+ items: items
+ });
+
+ me.callParent();
+ }
+});
+
+Ext.define('PVE.qemu.USBEdit', {
+ extend: 'PVE.window.Edit',
+
+ vmconfig: undefined,
+
+ isAdd: true,
+
+ subject: gettext('USB Device'),
+
+
+ initComponent : function() {
+ var me = this;
+
+ me.isCreate = !me.confid;
+
+ var ipanel = Ext.create('PVE.qemu.USBInputPanel', {
+ confid: me.confid,
+ pveSelNode: me.pveSelNode
+ });
+
+ Ext.apply(me, {
+ items: [ ipanel ]
+ });
+
+ me.callParent();
+
+ me.load({
+ success: function(response, options) {
+ ipanel.setVMConfig(response.result.data);
+ if (me.confid) {
+ var data = response.result.data[me.confid].split(',');
+ var port, hostdevice, usb3 = false;
+ var type = 'spice';
+ var i;
+ for (i = 0; i < data.length; i++) {
+ if (/^(host=)?(0x)?[a-zA-Z0-9]{4}\:(0x)?[a-zA-Z0-9]{4}$/.test(data[i])) {
+ hostdevice = data[i];
+ hostdevice = hostdevice.replace('host=', '').replace('0x','');
+ type = 'hostdevice';
+ } else if (/^(host=)?(\d+)\-(\d+(\.\d+)*)$/.test(data[i])) {
+ port = data[i];
+ port = port.replace('host=','');
+ type = 'port';
+ }
+
+ if (/^usb3=(1|on|true)$/.test(data[i])) {
+ usb3 = true;
+ }
+ }
+ var values = {
+ usb : type,
+ hostdevice: hostdevice,
+ port: port,
+ usb3: usb3
+ };
+
+ ipanel.setValues(values);
+ }
+ }
+ });
+ }
+});
--
2.11.0
More information about the pve-devel
mailing list