mirror of
https://git.proxmox.com/git/pve-manager
synced 2025-07-21 18:02:47 +00:00

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>
351 lines
6.6 KiB
JavaScript
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',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
});
|