]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/form/VMCPUFlagSelector.js
gui: vm: add CPU flag selector with tri-state awareness
[pve-manager.git] / www / manager6 / form / VMCPUFlagSelector.js
1 /*jslint confusion: true*/
2 Ext.define('PVE.form.VMCPUFlagSelector', {
3 extend: 'Ext.grid.Panel',
4 alias: 'widget.vmcpuflagselector',
5
6 mixins: {
7 field: 'Ext.form.field.Field'
8 },
9
10 disableSelection: true,
11 columnLines: false,
12 selectable: false,
13 hideHeaders: true,
14
15 scrollable: 'y',
16 height: 200,
17
18 unkownFlags: [],
19
20 store: {
21 type: 'store',
22 fields: ['flag', { name: 'state', defaultValue: '=' }, 'desc'],
23 data: [
24 // FIXME: let qemu-server host this and autogenerate or get from API call??
25 { flag: 'md-clear', desc: 'Required to let the guest OS know if MDS is mitigated correctly' },
26 { flag: 'pcid', desc: 'Meltdown fix cost reduction on Westmere, Sandy-, and IvyBridge Intel CPUs' },
27 { flag: 'spec-ctrl', desc: 'Allows improved Spectre mitigation with Intel CPUs' },
28 { flag: 'ssbd', desc: 'Protection for "Speculative Store Bypass" for Intel models' },
29 { flag: 'ibpb', desc: 'Allows improved Spectre mitigation with AMD CPUs' },
30 { flag: 'virt-ssbd', desc: 'Basis for "Speculative Store Bypass" protection for AMD models' },
31 { flag: 'amd-ssbd', desc: 'Improves Spectre mitigation performance with AMD CPUs, best used with "virt-ssbd"' },
32 { flag: 'amd-no-ssb', desc: 'Notifies guest OS that host is not vulnerable for Spectre on AMD CPUs' },
33 { flag: 'pdpe1gb', desc: 'Allow guest OS to use 1GB size pages, if host HW supports it' }
34 ],
35 listeners: {
36 update: function() {
37 this.commitChanges();
38 }
39 }
40 },
41
42 getValue: function() {
43 var me = this;
44 var store = me.getStore();
45 var flags = '';
46
47 // ExtJS does not has a nice getAllRecords interface for stores :/
48 store.queryBy(Ext.returnTrue).each(function(rec) {
49 var s = rec.get('state');
50 if (s && s !== '=') {
51 var f = rec.get('flag');
52 if (flags === '') {
53 flags = s + f;
54 } else {
55 flags += ';' + s + f;
56 }
57 }
58 });
59
60 flags += me.unkownFlags.join(';');
61
62 return flags;
63 },
64
65 setValue: function(value) {
66 var me = this;
67 var store = me.getStore();
68
69 me.value = value || '';
70
71 me.unkownFlags = [];
72
73 me.getStore().queryBy(Ext.returnTrue).each(function(rec) {
74 rec.set('state', '=');
75 });
76
77 var flags = value ? value.split(';') : [];
78 flags.forEach(function(flag) {
79 var sign = flag.substr(0, 1);
80 flag = flag.substr(1);
81
82 var rec = store.findRecord('flag', flag);
83 if (rec !== null) {
84 rec.set('state', sign);
85 } else {
86 me.unkownFlags.push(flag);
87 }
88 });
89 store.reload();
90
91 var res = me.mixins.field.setValue.call(me, value);
92
93 return res;
94 },
95 columns: [
96 {
97 dataIndex: 'state',
98 renderer: function(v) {
99 switch(v) {
100 case '=': return 'Default';
101 case '-': return 'Off';
102 case '+': return 'On';
103 default: return 'Unknown';
104 }
105 },
106 width: 65
107 },
108 {
109 xtype: 'widgetcolumn',
110 dataIndex: 'state',
111 width: 95,
112 onWidgetAttach: function (column, widget, record) {
113 var val = record.get('state') || '=';
114 widget.down('[inputValue=' + val + ']').setValue(true);
115 // TODO: disable if selected CPU model and flag are incompatible
116 },
117 widget: {
118 xtype: 'radiogroup',
119 hideLabel: true,
120 layout: 'hbox',
121 validateOnChange: false,
122 value: '=',
123 listeners: {
124 change: function(f, value) {
125 var v = Object.values(value)[0];
126 f.getWidgetRecord().set('state', v);
127
128 var view = this.up('grid');
129 view.dirty = view.getValue() !== view.originalValue;
130 view.checkDirty();
131 //view.checkChange();
132 }
133 },
134 items: [
135 {
136 boxLabel: '-',
137 boxLabelAlign: 'before',
138 inputValue: '-'
139 },
140 {
141 checked: true,
142 inputValue: '='
143 },
144 {
145 boxLabel: '+',
146 inputValue: '+'
147 }
148 ]
149 }
150 },
151 {
152 dataIndex: 'flag',
153 width: 100
154 },
155 {
156 dataIndex: 'desc',
157 cellWrap: true,
158 flex: 1
159 }
160 ],
161
162 initComponent: function() {
163 var me = this;
164
165 // static class store, thus gets not recreated, so ensure defaults are set!
166 me.getStore().data.forEach(function(v) {
167 v.state = '=';
168 });
169
170 me.value = me.originalValue = '';
171
172 me.callParent(arguments);
173 }
174 });