add usbselector and usb edit window for qemu
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@proxmox.com>
This commit is contained in:
parent
50b2a835a2
commit
7a995680a2
@ -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 \
|
||||
|
145
www/manager6/form/USBSelector.js
Normal file
145
www/manager6/form/USBSelector.js
Normal file
@ -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' }
|
||||
]
|
||||
});
|
||||
});
|
213
www/manager6/qemu/USBEdit.js
Normal file
213
www/manager6/qemu/USBEdit.js
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue
Block a user