]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/window/PCIMapEdit.js
f243362b11564cdb94e36bafc906ab8e482f50d7
[pve-manager.git] / www / manager6 / window / PCIMapEdit.js
1 Ext.define('PVE.window.PCIMapEditWindow', {
2 extend: 'Proxmox.window.Edit',
3
4 mixins: ['Proxmox.Mixin.CBind'],
5
6 width: 800,
7
8 subject: gettext('PCI mapping'),
9
10 onlineHelp: 'resource_mapping',
11
12 method: 'POST',
13
14 cbindData: function(initialConfig) {
15 let me = this;
16 me.isCreate = !me.name || !me.nodename;
17 me.method = me.name ? 'PUT' : 'POST';
18 return {
19 name: me.name,
20 nodename: me.nodename,
21 };
22 },
23
24 submitUrl: function(_url, data) {
25 let me = this;
26 let name = me.method === 'PUT' ? me.name : '';
27 return `/cluster/mapping/pci/${name}`;
28 },
29
30 controller: {
31 xclass: 'Ext.app.ViewController',
32
33 onGetValues: function(values) {
34 let me = this;
35 let view = me.getView();
36 if (view.method === "POST") {
37 delete me.digest;
38 }
39
40 if (values.iommugroup === -1) {
41 delete values.iommugroup;
42 }
43
44 let nodename = values.node ?? view.nodename;
45 delete values.node;
46 if (me.originalMap) {
47 let otherMaps = PVE.Parser
48 .filterPropertyStringList(me.originalMap, (e) => e.node !== nodename);
49 if (otherMaps.length) {
50 values.map = values.map.concat(otherMaps);
51 }
52 }
53
54 return values;
55 },
56
57 onSetValues: function(values) {
58 let me = this;
59 let view = me.getView();
60 me.originalMap = [...values.map];
61 let configuredNodes = [];
62 values.map = PVE.Parser.filterPropertyStringList(values.map, (e) => {
63 configuredNodes.push(e.node);
64 return e.node === view.nodename;
65 });
66
67 me.lookup('nodeselector').disallowedNodes = configuredNodes;
68 return values;
69 },
70
71 checkIommu: function(store, records, success) {
72 let me = this;
73 if (!success || !records.length) {
74 return;
75 }
76 me.lookup('iommu_warning').setVisible(
77 records.every((val) => val.data.iommugroup === -1),
78 );
79
80 let value = me.lookup('pciselector').getValue();
81 me.checkIsolated(value);
82 },
83
84 checkIsolated: function(value) {
85 let me = this;
86
87 let store = me.lookup('pciselector').getStore();
88
89 let isIsolated = function(entry) {
90 let isolated = true;
91 let parsed = PVE.Parser.parsePropertyString(entry);
92 parsed.iommugroup = parseInt(parsed.iommugroup, 10);
93 if (!parsed.iommugroup) {
94 return isolated;
95 }
96 store.each(({ data }) => {
97 let isSubDevice = data.id.startsWith(parsed.path);
98 if (data.iommugroup === parsed.iommugroup && data.id !== parsed.path && !isSubDevice) {
99 isolated = false;
100 return false;
101 }
102 return true;
103 });
104 return isolated;
105 };
106
107 let showWarning = false;
108 if (Ext.isArray(value)) {
109 for (const entry of value) {
110 if (!isIsolated(entry)) {
111 showWarning = true;
112 break;
113 }
114 }
115 } else {
116 showWarning = isIsolated(value);
117 }
118 me.lookup('group_warning').setVisible(showWarning);
119 },
120
121 mdevChange: function(mdevField, value) {
122 this.lookup('pciselector').setMdev(value);
123 },
124
125 nodeChange: function(_field, value) {
126 this.lookup('pciselector').setNodename(value);
127 },
128
129 pciChange: function(_field, value) {
130 let me = this;
131 me.lookup('multiple_warning').setVisible(Ext.isArray(value) && value.length > 1);
132 me.checkIsolated(value);
133 },
134
135 control: {
136 'field[name=mdev]': {
137 change: 'mdevChange',
138 },
139 'pveNodeSelector': {
140 change: 'nodeChange',
141 },
142 'pveMultiPCISelector': {
143 change: 'pciChange',
144 },
145 },
146 },
147
148 items: [
149 {
150 xtype: 'inputpanel',
151 onGetValues: function(values) {
152 return this.up('window').getController().onGetValues(values);
153 },
154
155 onSetValues: function(values) {
156 return this.up('window').getController().onSetValues(values);
157 },
158
159 columnT: [
160 {
161 xtype: 'displayfield',
162 reference: 'iommu_warning',
163 hidden: true,
164 columnWidth: 1,
165 padding: '0 0 10 0',
166 value: 'No IOMMU detected, please activate it.' +
167 'See Documentation for further information.',
168 userCls: 'pmx-hint',
169 },
170 {
171 xtype: 'displayfield',
172 reference: 'multiple_warning',
173 hidden: true,
174 columnWidth: 1,
175 padding: '0 0 10 0',
176 value: 'When multiple devices are selected, the first free one will be chosen' +
177 ' on guest start.',
178 userCls: 'pmx-hint',
179 },
180 {
181 xtype: 'displayfield',
182 reference: 'group_warning',
183 hidden: true,
184 columnWidth: 1,
185 padding: '0 0 10 0',
186 itemId: 'iommuwarning',
187 value: 'The selected Device is not in a seperate IOMMU group, make sure this is intended.',
188 userCls: 'pmx-hint',
189 },
190 ],
191
192 column1: [
193 {
194 xtype: 'pmxDisplayEditField',
195 fieldLabel: gettext('Name'),
196 labelWidth: 120,
197 cbind: {
198 editable: '{!name}',
199 value: '{name}',
200 submitValue: '{isCreate}',
201 },
202 name: 'id',
203 allowBlank: false,
204 },
205 {
206 xtype: 'pmxDisplayEditField',
207 fieldLabel: gettext('Mapping on Node'),
208 labelWidth: 120,
209 name: 'node',
210 editConfig: {
211 xtype: 'pveNodeSelector',
212 reference: 'nodeselector',
213 },
214 cbind: {
215 editable: '{!nodename}',
216 value: '{nodename}',
217 },
218 allowBlank: false,
219 },
220 ],
221
222 column2: [
223 {
224 // as spacer
225 xtype: 'displayfield',
226 },
227 {
228 xtype: 'proxmoxcheckbox',
229 fieldLabel: gettext('Mediated Devices'),
230 labelWidth: 120,
231 reference: 'mdev',
232 name: 'mdev',
233 cbind: {
234 deleteEmpty: '{!isCreate}',
235 },
236 },
237 ],
238
239 columnB: [
240 {
241 xtype: 'pveMultiPCISelector',
242 fieldLabel: gettext('Device'),
243 labelWidth: 120,
244 height: 300,
245 reference: 'pciselector',
246 name: 'map',
247 cbind: {
248 nodename: '{nodename}',
249 },
250 allowBlank: false,
251 onLoadCallBack: 'checkIommu',
252 margin: '0 0 10 0',
253 },
254 {
255 xtype: 'proxmoxtextfield',
256 fieldLabel: gettext('Comment'),
257 labelWidth: 120,
258 submitValue: true,
259 name: 'description',
260 cbind: {
261 deleteEmpty: '{!isCreate}',
262 },
263 },
264 ],
265 },
266 ],
267 });