pve-manager/www/manager6/form/VMSelector.js
Dominik Csapak 6f2940c7b1 ui: fix not opening 'bulk action' windows
we previously removed the 'filters' property from the store, but this
has the effect that the filter array is only ever initialized when
we try to access them via the specified api of extjs

so instead of adding them manually to their array, use the 'addFilter'
method of extjs

also use 'getStore()' instead of directly accessing the store to be
consistent with the extjs api use

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
2023-03-14 11:37:47 +01:00

351 lines
6.6 KiB
JavaScript

/* filter is a javascript builtin, but extjs calls it also filter */
Ext.define('PVE.form.VMSelector', {
extend: 'Ext.grid.Panel',
alias: 'widget.vmselector',
mixins: {
field: 'Ext.form.field.Field',
},
allowBlank: true,
selectAll: false,
isFormField: true,
plugins: 'gridfilters',
store: {
model: 'PVEResources',
sorters: 'vmid',
},
columnsDeclaration: [
{
header: 'ID',
dataIndex: 'vmid',
width: 80,
filter: {
type: 'number',
},
},
{
header: gettext('Node'),
dataIndex: 'node',
},
{
header: gettext('Status'),
dataIndex: 'status',
filter: {
type: 'list',
},
},
{
header: gettext('Name'),
dataIndex: 'name',
flex: 1,
filter: {
type: 'string',
},
},
{
header: gettext('Pool'),
dataIndex: 'pool',
filter: {
type: 'list',
},
},
{
header: gettext('Type'),
dataIndex: 'type',
width: 120,
renderer: function(value) {
if (value === 'qemu') {
return gettext('Virtual Machine');
} else if (value === 'lxc') {
return gettext('LXC Container');
}
return '';
},
filter: {
type: 'list',
store: {
data: [
{ id: 'qemu', text: gettext('Virtual Machine') },
{ id: 'lxc', text: gettext('LXC Container') },
],
un: function() {
// Due to EXTJS-18711. we have to do a static list via a store but to avoid
// creating an object, we have to have an empty pseudo un function
},
},
},
},
{
header: 'HA ' + gettext('Status'),
dataIndex: 'hastate',
flex: 1,
filter: {
type: 'list',
},
},
],
// should be a list of 'dataIndex' values, if 'undefined' all declared columns will be included
columnSelection: undefined,
selModel: {
selType: 'checkboxmodel',
mode: 'SIMPLE',
},
checkChangeEvents: [
'selectionchange',
'change',
],
listeners: {
selectionchange: function() {
// to trigger validity and error checks
this.checkChange();
},
},
getValue: function() {
var me = this;
if (me.savedValue !== undefined) {
return me.savedValue;
}
var sm = me.getSelectionModel();
var selection = sm.getSelection();
var values = [];
var store = me.getStore();
selection.forEach(function(item) {
// only add if not filtered
if (store.findExact('vmid', item.data.vmid) !== -1) {
values.push(item.data.vmid);
}
});
return values;
},
setValueSelection: function(value) {
let me = this;
let store = me.getStore();
let notFound = [];
let selection = value.map(item => {
let found = store.findRecord('vmid', item, 0, false, true, true);
if (!found) {
notFound.push(item);
}
return found;
}).filter(r => r);
for (const vmid of notFound) {
let rec = store.add({
vmid,
node: 'unknown',
});
selection.push(rec[0]);
}
let sm = me.getSelectionModel();
if (selection.length) {
sm.select(selection);
} else {
sm.deselectAll();
}
// to correctly trigger invalid class
me.getErrors();
},
setValue: function(value) {
let me = this;
if (!Ext.isArray(value)) {
value = value.split(',');
}
let store = me.getStore();
if (!store.isLoaded()) {
me.savedValue = value;
store.on('load', function() {
me.setValueSelection(value);
delete me.savedValue;
}, { single: true });
} else {
me.setValueSelection(value);
}
return me.mixins.field.setValue.call(me, value);
},
getErrors: function(value) {
let me = this;
if (!me.isDisabled() && me.allowBlank === false &&
me.getSelectionModel().getCount() === 0) {
me.addBodyCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']);
return [gettext('No VM selected')];
}
me.removeBodyCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']);
return [];
},
setDisabled: function(disabled) {
let me = this;
let res = me.callParent([disabled]);
me.getErrors();
return res;
},
initComponent: function() {
let me = this;
let columns = me.columnsDeclaration.filter((column) =>
me.columnSelection ? me.columnSelection.indexOf(column.dataIndex) !== -1 : true,
).map((x) => x);
me.columns = columns;
me.callParent();
me.getStore().load({ params: { type: 'vm' } });
if (me.nodename) {
me.getStore().addFilter({
property: 'node',
exactMatch: true,
value: me.nodename,
});
}
// only show the relevant guests by default
if (me.action) {
var statusfilter = '';
switch (me.action) {
case 'startall':
statusfilter = 'stopped';
break;
case 'stopall':
statusfilter = 'running';
break;
}
if (statusfilter !== '') {
me.getStore().addFilter([{
property: 'template',
value: 0,
}, {
id: 'x-gridfilter-status',
operator: 'in',
property: 'status',
value: [statusfilter],
}]);
}
}
if (me.selectAll) {
me.mon(me.getStore(), 'load', function() {
me.getSelectionModel().selectAll(false);
});
}
},
});
Ext.define('PVE.form.VMComboSelector', {
extend: 'Proxmox.form.ComboGrid',
alias: 'widget.vmComboSelector',
valueField: 'vmid',
displayField: 'vmid',
autoSelect: false,
editable: true,
anyMatch: true,
forceSelection: true,
store: {
model: 'PVEResources',
autoLoad: true,
sorters: 'vmid',
filters: [{
property: 'type',
value: /lxc|qemu/,
}],
},
listConfig: {
width: 600,
plugins: 'gridfilters',
columns: [
{
header: 'ID',
dataIndex: 'vmid',
width: 80,
filter: {
type: 'number',
},
},
{
header: gettext('Name'),
dataIndex: 'name',
flex: 1,
filter: {
type: 'string',
},
},
{
header: gettext('Node'),
dataIndex: 'node',
},
{
header: gettext('Status'),
dataIndex: 'status',
filter: {
type: 'list',
},
},
{
header: gettext('Pool'),
dataIndex: 'pool',
hidden: true,
filter: {
type: 'list',
},
},
{
header: gettext('Type'),
dataIndex: 'type',
width: 120,
renderer: function(value) {
if (value === 'qemu') {
return gettext('Virtual Machine');
} else if (value === 'lxc') {
return gettext('LXC Container');
}
return '';
},
filter: {
type: 'list',
store: {
data: [
{ id: 'qemu', text: gettext('Virtual Machine') },
{ id: 'lxc', text: gettext('LXC Container') },
],
un: function() { /* due to EXTJS-18711 */ },
},
},
},
{
header: 'HA ' + gettext('Status'),
dataIndex: 'hastate',
hidden: true,
flex: 1,
filter: {
type: 'list',
},
},
],
},
});