]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/form/VMSelector.js
22f7dd11d5b6619d6d372dbe46a61a8aa8b8a225
[pve-manager.git] / www / manager6 / form / VMSelector.js
1 /* filter is a javascript builtin, but extjs calls it also filter */
2 Ext.define('PVE.form.VMSelector', {
3 extend: 'Ext.grid.Panel',
4 alias: 'widget.vmselector',
5
6 mixins: {
7 field: 'Ext.form.field.Field',
8 },
9
10 allowBlank: true,
11 selectAll: false,
12 isFormField: true,
13
14 plugins: 'gridfilters',
15
16 store: {
17 model: 'PVEResources',
18 sorters: 'vmid',
19 },
20
21 columnsDeclaration: [
22 {
23 header: 'ID',
24 dataIndex: 'vmid',
25 width: 80,
26 filter: {
27 type: 'number',
28 },
29 },
30 {
31 header: gettext('Node'),
32 dataIndex: 'node',
33 },
34 {
35 header: gettext('Status'),
36 dataIndex: 'status',
37 filter: {
38 type: 'list',
39 },
40 },
41 {
42 header: gettext('Name'),
43 dataIndex: 'name',
44 flex: 1,
45 filter: {
46 type: 'string',
47 },
48 },
49 {
50 header: gettext('Pool'),
51 dataIndex: 'pool',
52 filter: {
53 type: 'list',
54 },
55 },
56 {
57 header: gettext('Type'),
58 dataIndex: 'type',
59 width: 120,
60 renderer: function(value) {
61 if (value === 'qemu') {
62 return gettext('Virtual Machine');
63 } else if (value === 'lxc') {
64 return gettext('LXC Container');
65 }
66
67 return '';
68 },
69 filter: {
70 type: 'list',
71 store: {
72 data: [
73 { id: 'qemu', text: gettext('Virtual Machine') },
74 { id: 'lxc', text: gettext('LXC Container') },
75 ],
76 un: function() {
77 // Due to EXTJS-18711. we have to do a static list via a store but to avoid
78 // creating an object, we have to have an empty pseudo un function
79 },
80 },
81 },
82 },
83 {
84 header: 'HA ' + gettext('Status'),
85 dataIndex: 'hastate',
86 flex: 1,
87 filter: {
88 type: 'list',
89 },
90 },
91 ],
92
93 // should be a list of 'dataIndex' values, if 'undefined' all declared columns will be included
94 columnSelection: undefined,
95
96 selModel: {
97 selType: 'checkboxmodel',
98 mode: 'SIMPLE',
99 },
100
101 checkChangeEvents: [
102 'selectionchange',
103 'change',
104 ],
105
106 listeners: {
107 selectionchange: function() {
108 // to trigger validity and error checks
109 this.checkChange();
110 },
111 },
112
113 getValue: function() {
114 var me = this;
115 if (me.savedValue !== undefined) {
116 return me.savedValue;
117 }
118 var sm = me.getSelectionModel();
119 var selection = sm.getSelection();
120 var values = [];
121 var store = me.getStore();
122 selection.forEach(function(item) {
123 // only add if not filtered
124 if (store.findExact('vmid', item.data.vmid) !== -1) {
125 values.push(item.data.vmid);
126 }
127 });
128 return values;
129 },
130
131 setValueSelection: function(value) {
132 let me = this;
133
134 let store = me.getStore();
135 let notFound = [];
136 let selection = value.map(item => {
137 let found = store.findRecord('vmid', item, 0, false, true, true);
138 if (!found) {
139 if (Ext.isNumeric(item)) {
140 notFound.push(item);
141 } else {
142 console.warn(`invalid item in vm selection: ${item}`);
143 }
144 }
145 return found;
146 }).filter(r => r);
147
148 for (const vmid of notFound) {
149 let rec = store.add({
150 vmid,
151 node: 'unknown',
152 });
153 selection.push(rec[0]);
154 }
155
156 let sm = me.getSelectionModel();
157 if (selection.length) {
158 sm.select(selection);
159 } else {
160 sm.deselectAll();
161 }
162 // to correctly trigger invalid class
163 me.getErrors();
164 },
165
166 setValue: function(value) {
167 let me = this;
168 if (!Ext.isArray(value)) {
169 value = value.split(',').filter(v => v !== '');
170 }
171
172 let store = me.getStore();
173 if (!store.isLoaded()) {
174 me.savedValue = value;
175 store.on('load', function() {
176 me.setValueSelection(value);
177 delete me.savedValue;
178 }, { single: true });
179 } else {
180 me.setValueSelection(value);
181 }
182 return me.mixins.field.setValue.call(me, value);
183 },
184
185 getErrors: function(value) {
186 let me = this;
187 if (!me.isDisabled() && me.allowBlank === false &&
188 me.getSelectionModel().getCount() === 0) {
189 me.addBodyCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']);
190 return [gettext('No VM selected')];
191 }
192
193 me.removeBodyCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']);
194 return [];
195 },
196
197 setDisabled: function(disabled) {
198 let me = this;
199 let res = me.callParent([disabled]);
200 me.getErrors();
201 return res;
202 },
203
204 initComponent: function() {
205 let me = this;
206
207 let columns = me.columnsDeclaration.filter((column) =>
208 me.columnSelection ? me.columnSelection.indexOf(column.dataIndex) !== -1 : true,
209 ).map((x) => x);
210
211 me.columns = columns;
212
213 me.callParent();
214
215 me.getStore().load({ params: { type: 'vm' } });
216
217 if (me.nodename) {
218 me.getStore().addFilter({
219 property: 'node',
220 exactMatch: true,
221 value: me.nodename,
222 });
223 }
224
225 // only show the relevant guests by default
226 if (me.action) {
227 var statusfilter = '';
228 switch (me.action) {
229 case 'startall':
230 statusfilter = 'stopped';
231 break;
232 case 'stopall':
233 statusfilter = 'running';
234 break;
235 }
236 if (statusfilter !== '') {
237 me.getStore().addFilter([{
238 property: 'template',
239 value: 0,
240 }, {
241 id: 'x-gridfilter-status',
242 operator: 'in',
243 property: 'status',
244 value: [statusfilter],
245 }]);
246 }
247 }
248
249 if (me.selectAll) {
250 me.mon(me.getStore(), 'load', function() {
251 me.getSelectionModel().selectAll(false);
252 });
253 }
254 },
255 });
256
257
258 Ext.define('PVE.form.VMComboSelector', {
259 extend: 'Proxmox.form.ComboGrid',
260 alias: 'widget.vmComboSelector',
261
262 valueField: 'vmid',
263 displayField: 'vmid',
264
265 autoSelect: false,
266 editable: true,
267 anyMatch: true,
268 forceSelection: true,
269
270 store: {
271 model: 'PVEResources',
272 autoLoad: true,
273 sorters: 'vmid',
274 filters: [{
275 property: 'type',
276 value: /lxc|qemu/,
277 }],
278 },
279
280 listConfig: {
281 width: 600,
282 plugins: 'gridfilters',
283 columns: [
284 {
285 header: 'ID',
286 dataIndex: 'vmid',
287 width: 80,
288 filter: {
289 type: 'number',
290 },
291 },
292 {
293 header: gettext('Name'),
294 dataIndex: 'name',
295 flex: 1,
296 filter: {
297 type: 'string',
298 },
299 },
300 {
301 header: gettext('Node'),
302 dataIndex: 'node',
303 },
304 {
305 header: gettext('Status'),
306 dataIndex: 'status',
307 filter: {
308 type: 'list',
309 },
310 },
311 {
312 header: gettext('Pool'),
313 dataIndex: 'pool',
314 hidden: true,
315 filter: {
316 type: 'list',
317 },
318 },
319 {
320 header: gettext('Type'),
321 dataIndex: 'type',
322 width: 120,
323 renderer: function(value) {
324 if (value === 'qemu') {
325 return gettext('Virtual Machine');
326 } else if (value === 'lxc') {
327 return gettext('LXC Container');
328 }
329
330 return '';
331 },
332 filter: {
333 type: 'list',
334 store: {
335 data: [
336 { id: 'qemu', text: gettext('Virtual Machine') },
337 { id: 'lxc', text: gettext('LXC Container') },
338 ],
339 un: function() { /* due to EXTJS-18711 */ },
340 },
341 },
342 },
343 {
344 header: 'HA ' + gettext('Status'),
345 dataIndex: 'hastate',
346 hidden: true,
347 flex: 1,
348 filter: {
349 type: 'list',
350 },
351 },
352 ],
353 },
354 });