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