Supports viewing, deleting, adding and editing existing custom CPU
models. All properties except CPU flags are supported in the editor.

A new control for selecting between different Phys-Bits (default, host,
custom number) is added.

This also seems to be the first use of a non-fa icon in the sidebar, so
add a new class that correctly aligns pve-itype-icon-* elements.

Signed-off-by: Stefan Reiter <s.rei...@proxmox.com>
---
 www/css/ext6-pve.css                  |   4 +
 www/manager6/Makefile                 |   3 +
 www/manager6/dc/CPUTypeEdit.js        |  81 ++++++++++++++
 www/manager6/dc/CPUTypeView.js        | 148 ++++++++++++++++++++++++++
 www/manager6/dc/Config.js             |   6 ++
 www/manager6/form/PhysBitsSelector.js | 128 ++++++++++++++++++++++
 6 files changed, 370 insertions(+)
 create mode 100644 www/manager6/dc/CPUTypeEdit.js
 create mode 100644 www/manager6/dc/CPUTypeView.js
 create mode 100644 www/manager6/form/PhysBitsSelector.js

diff --git a/www/css/ext6-pve.css b/www/css/ext6-pve.css
index e5d792f8..bb9bd8c0 100644
--- a/www/css/ext6-pve.css
+++ b/www/css/ext6-pve.css
@@ -447,6 +447,10 @@
     padding: 0;
 }
 
+.pve-icon-sidebar {
+    margin-top: 5px;
+}
+
 /* displayfield minheight is wrong */
 .x-form-display-field-default {
     min-height: 20px;
diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index e5e85aed..abca0a05 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -48,6 +48,7 @@ JSSRC=                                                        
\
        form/NodeSelector.js                            \
        form/PCISelector.js                             \
        form/PermPathSelector.js                        \
+       form/PhysBitsSelector.js                        \
        form/PoolSelector.js                            \
        form/PreallocationSelector.js                   \
        form/PrivilegesSelector.js                      \
@@ -131,6 +132,8 @@ JSSRC=                                                      
\
        dc/ClusterEdit.js                               \
        dc/Config.js                                    \
        dc/CorosyncLinkEdit.js                          \
+       dc/CPUTypeView.js                               \
+       dc/CPUTypeEdit.js                               \
        dc/GroupEdit.js                                 \
        dc/GroupView.js                                 \
        dc/Guests.js                                    \
diff --git a/www/manager6/dc/CPUTypeEdit.js b/www/manager6/dc/CPUTypeEdit.js
new file mode 100644
index 00000000..3ad527c4
--- /dev/null
+++ b/www/manager6/dc/CPUTypeEdit.js
@@ -0,0 +1,81 @@
+Ext.define('PVE.dc.CPUTypeEdit', {
+    extend: 'Proxmox.window.Edit',
+    alias: ['widget.pveCpuTypeEdit'],
+    mixins: ['Proxmox.Mixin.CBind'],
+
+    subject: gettext('CPU Type'),
+
+    cbindData: {
+       cputype: '',
+       isCreate: (cfg) => !cfg.cputype,
+    },
+
+    cbind: {
+       autoLoad: get => !get('isCreate'),
+       url: get => 
`/api2/extjs/nodes/localhost/capabilities/qemu/cpu/model/${get('cputype')}`,
+       method: get => get('isCreate') ? 'POST' : 'PUT',
+       isCreate: get => get('isCreate'),
+    },
+
+    getValues: function() {
+       let me = this;
+       let values = me.callParent();
+
+       PVE.Utils.delete_if_default(values, 'reported-model', '', me.isCreate);
+       PVE.Utils.delete_if_default(values, 'hv-vendor-id', '', me.isCreate);
+       PVE.Utils.delete_if_default(values, 'phys-bits', '', me.isCreate);
+       PVE.Utils.delete_if_default(values, 'flags', '', me.isCreate);
+
+       if (me.isCreate && !values.cputype.match(/^custom-/)) {
+           values.cputype = 'custom-' + values.cputype;
+       }
+
+       return values;
+    },
+
+    items: [
+       {
+           xtype: 'inputpanel',
+           column1: [
+               {
+                   xtype: 'pmxDisplayEditField',
+                   fieldLabel: gettext('Name'),
+                   cbind: {
+                       editable: '{isCreate}',
+                       value: '{cputype}',
+                   },
+                   name: 'cputype',
+                   allowBlank: false,
+               },
+               {
+                   xtype: 'CPUModelSelector',
+                   fieldLabel: gettext('Reported Model'),
+                   allowCustom: false,
+                   name: 'reported-model',
+               },
+               {
+                   xtype: 'textfield',
+                   fieldLabel: gettext('Hyper-V Vendor'),
+                   name: 'hv-vendor-id',
+                   allowBlank: true,
+                   emptyText: gettext('None'),
+                   maxLength: 12,
+               },
+           ],
+           column2: [
+               {
+                   xtype: 'checkbox',
+                   fieldLabel: gettext('Hidden'),
+                   name: 'hidden',
+                   inputValue: 1,
+                   uncheckedValue: 0,
+               },
+               {
+                   xtype: 'PhysBitsSelector',
+                   fieldLabel: gettext('Phys-Bits'),
+                   name: 'phys-bits',
+               },
+           ],
+       },
+    ],
+});
diff --git a/www/manager6/dc/CPUTypeView.js b/www/manager6/dc/CPUTypeView.js
new file mode 100644
index 00000000..0d560369
--- /dev/null
+++ b/www/manager6/dc/CPUTypeView.js
@@ -0,0 +1,148 @@
+Ext.define('PVE.dc.CPUTypeView', {
+    extend: 'Ext.grid.GridPanel',
+    alias: ['widget.pveCPUTypeView'],
+
+    onlineHelp: 'qm_cpu',
+
+    store: {
+       model: 'pve-custom-cpu-type',
+       proxy: {
+           type: 'proxmox',
+           url: "/api2/json/nodes/localhost/capabilities/qemu/cpu/model",
+           root: 'data.ids',
+       },
+       autoLoad: true,
+       sorters: ['cputype'],
+    },
+
+    controller: {
+       xclass: 'Ext.app.ViewController',
+
+       getSelection: function() {
+           let me = this;
+           let grid = me.getView();
+           let selection = grid.getSelection();
+           if (selection.length === 1) {
+               return selection[0].data;
+           }
+           return null;
+       },
+
+       showEditor: function(cputype) {
+           let me = this;
+           let param = {};
+           if (cputype) {
+               Ext.apply(param, { cputype: cputype });
+           }
+           let win = Ext.create('PVE.dc.CPUTypeEdit', param);
+           win.on('destroy', () => me.reload());
+           win.show();
+       },
+
+       onAdd: function() {
+           let me = this;
+           me.showEditor();
+       },
+
+       onEdit: function() {
+           let me = this;
+           let selection = me.getSelection();
+           me.showEditor(selection.cputype);
+       },
+
+       reload: function() {
+           let me = this;
+           let grid = me.getView();
+           let store = grid.store;
+           store.reload();
+       },
+    },
+
+    columns: [
+       {
+           header: 'Name',
+           flex: 1,
+           sortable: true,
+           dataIndex: 'cputype',
+           renderer: val => val.replace(/^custom-/, ''),
+       },
+       {
+           header: 'Reported Model',
+           width: '80px',
+           sortable: true,
+           dataIndex: 'reported-model',
+       },
+       {
+           header: 'Phys-Bits',
+           width: '40px',
+           sortable: true,
+           dataIndex: 'phys-bits',
+       },
+       {
+           header: 'Hidden',
+           width: '40px',
+           sortable: true,
+           dataIndex: 'hidden',
+       },
+       {
+           header: 'HyperV-Vendor',
+           width: '80px',
+           sortable: true,
+           dataIndex: 'hv-vendor-id',
+       },
+       {
+           header: 'Flags',
+           flex: 2,
+           sortable: true,
+           dataIndex: 'flags',
+       },
+    ],
+
+    tbar: [
+       {
+           text: gettext('Add'),
+           handler: 'onAdd',
+       },
+       '-',
+       {
+           xtype: 'proxmoxStdRemoveButton',
+           baseurl: '/api2/extjs/nodes/localhost/capabilities/qemu/cpu/model/',
+           getRecordName: (rec) => rec.data.cputype,
+           getUrl: function(rec) {
+               let me = this;
+               return me.baseurl + rec.data.cputype;
+           },
+           callback: 'reload',
+       },
+       {
+           text: gettext('Edit'),
+           handler: 'onEdit',
+       },
+    ],
+
+    selModel: {
+       xtype: 'Ext.selection.RowModel',
+    },
+
+    listeners: {
+       itemdblclick: function(_, rec) {
+           let me = this;
+           me.getController().showEditor(rec.data.cputype);
+       },
+    },
+
+    initComponent: function() {
+       let me = this;
+       me.callParent();
+       Proxmox.Utils.monStoreErrors(me, me.store);
+    },
+
+}, function() {
+    Ext.define('pve-custom-cpu-type', {
+       extend: 'Ext.data.Model',
+       fields: [
+           'cputype', 'reported-model', 'hv-vendor-id', 'flags', 'phys-bits',
+           { name: 'hidden', type: 'boolean' },
+       ],
+    });
+});
diff --git a/www/manager6/dc/Config.js b/www/manager6/dc/Config.js
index 934952d9..cbaabb9e 100644
--- a/www/manager6/dc/Config.js
+++ b/www/manager6/dc/Config.js
@@ -70,6 +70,12 @@ Ext.define('PVE.dc.Config', {
                title: gettext('Replication'),
                itemId: 'replication',
            },
+           {
+               xtype: 'pveCPUTypeView',
+               iconCls: 'pve-itype-icon-processor pve-icon pve-icon-sidebar',
+               title: gettext('CPU Types'),
+               itemId: 'cputypes',
+           },
            {
                xtype: 'pveACLView',
                title: gettext('Permissions'),
diff --git a/www/manager6/form/PhysBitsSelector.js 
b/www/manager6/form/PhysBitsSelector.js
new file mode 100644
index 00000000..a18b675f
--- /dev/null
+++ b/www/manager6/form/PhysBitsSelector.js
@@ -0,0 +1,128 @@
+Ext.define('PVE.form.PhysBitsSelector', {
+    extend: 'Ext.form.FieldContainer',
+    alias: 'widget.PhysBitsSelector',
+    mixins: ['Ext.form.field.Field'],
+
+    layout: 'vbox',
+    initialValue: '',
+    originalValue: '',
+
+    controller: {
+       xclass: 'Ext.app.ViewController',
+
+       updateNumberField: function() {
+           let me = this;
+           let modeCustom = me.lookupReference('modeCustom');
+           let customNum = me.lookupReference('customNum');
+
+           customNum.setDisabled(!modeCustom.getValue());
+           me.getView().validate();
+       },
+
+       listen: {
+           component: {
+               '*': {
+                   change: function() {
+                       let me = this;
+                       me.getView().checkChange();
+                   },
+               },
+           },
+       },
+    },
+
+    getValue: function() {
+       let me = this;
+       let ctrl = me.getController();
+       if (ctrl.lookupReference('modeDefault').getValue()) {
+           return '';
+       } else if (ctrl.lookupReference('modeHost').getValue()) {
+           return 'host';
+       } else if (ctrl.lookupReference('modeCustom').getValue()) {
+           return ctrl.lookupReference('customNum').getValue();
+       }
+       return ''; // shouldn't happen
+    },
+
+    setValue: function(value) {
+       let me = this;
+       let ctrl = me.getController();
+       let modeField;
+
+       if (!value) {
+           modeField = ctrl.lookupReference('modeDefault');
+       } else if (value === 'host') {
+           modeField = ctrl.lookupReference('modeHost');
+       } else {
+           let customNum = me.lookupReference('customNum');
+           customNum.setValue(value);
+           modeField = ctrl.lookupReference('modeCustom');
+       }
+
+       modeField.setValue(true);
+       me.checkChange();
+
+       return value;
+    },
+
+    getErrors: function() {
+       let me = this;
+       let ctrl = me.getController();
+       if (ctrl.lookupReference('modeCustom').getValue()) {
+           return ctrl.lookupReference('customNum').getErrors();
+       }
+       return [];
+    },
+
+    isValid: function() {
+       let me = this;
+       let ctrl = me.getController();
+       return ctrl.lookupReference('customNum').isValid();
+    },
+
+    items: [
+       {
+           xtype: 'radiofield',
+           boxLabel: gettext('Default'),
+           inputValue: 'default',
+           checked: true,
+           reference: 'modeDefault',
+           isFormField: false,
+       },
+       {
+           xtype: 'radiofield',
+           boxLabel: gettext('Host'),
+           inputValue: 'host',
+           reference: 'modeHost',
+           isFormField: false,
+       },
+       {
+           xtype: 'fieldcontainer',
+           layout: 'hbox',
+           items: [
+               {
+                   xtype: 'radiofield',
+                   boxLabel: gettext('Custom'),
+                   inputValue: 'custom',
+                   listeners: {
+                       change: 'updateNumberField',
+                   },
+                   reference: 'modeCustom',
+                   isFormField: false,
+               },
+               {
+                   xtype: 'numberfield',
+                   width: '60px',
+                   margin: '0 0 0 10px',
+                   minValue: 8,
+                   maxValue: 64,
+                   reference: 'customNum',
+                   allowBlank: false,
+                   isFormField: false,
+                   disabled: true,
+               },
+           ],
+       },
+    ],
+});
+
-- 
2.30.2



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to