ui: Show if Filter includes or excludes

To make the UI compatible, the Group Filter dialogue has been extended
by a second list, so it now features a list for all include filter and
one for all exclude filters.

Internally, all include as well as exclude filter are managed into one
list. The 2 list view is just for a cleaner representation in the UI.

Signed-off-by: Philipp Hufnagl <p.hufnagl@proxmox.com>
This commit is contained in:
Philipp Hufnagl 2024-01-02 12:06:53 +01:00 committed by Wolfgang Bumiller
parent 59c9273698
commit 4e45d84fb3

View File

@ -35,13 +35,36 @@ Ext.define('PBS.form.GroupFilter', {
// break cyclic reference // break cyclic reference
me.removeReferences(record); me.removeReferences(record);
me.lookup('grid').getStore().remove(record); me.lookup('grid-include').getStore().remove(record);
me.lookup('grid-exclude').getStore().remove(record);
me.updateRealField(); me.updateRealField();
}, },
addFilter: function() { addIncludeFilter: function() {
let me = this; let me = this;
me.lookup('grid').getStore().add({}); me.lookup('grid-include').getStore().add({ behavior: 'include' });
me.updateRealField();
},
addExcludeFilter: function() {
let me = this;
me.lookup('grid-exclude').getStore().add({ behavior: 'exclude' });
me.updateRealField();
},
onBehaviorChange: function(field, value) {
let me = this;
let record = field.getWidgetRecord();
if (record === undefined) {
return;
}
record.set('behavior', value);
record.commit();
if (record.widgets) {
me.setInputValue(record.widgets, record);
}
me.updateRealField(); me.updateRealField();
}, },
@ -77,8 +100,12 @@ Ext.define('PBS.form.GroupFilter', {
}, },
parseGroupFilter: function(filter) { parseGroupFilter: function(filter) {
let [, type, input] = filter.match(/^(type|group|regex):(.*)$/); let [, behavior, type, input] = filter.match(/^(?:(exclude|include):)?(type|group|regex):(.*)$/);
if (behavior === undefined) {
behavior = "include";
}
return { return {
behavior,
type, type,
input, input,
}; };
@ -86,13 +113,16 @@ Ext.define('PBS.form.GroupFilter', {
onValueChange: function(field, values) { onValueChange: function(field, values) {
let me = this; let me = this;
let grid = me.lookup('grid'); let grid_include = me.lookup('grid-include');
let grid_exclude = me.lookup('grid-exclude');
if (!values || values.length === 0) { if (!values || values.length === 0) {
grid.getStore().removeAll(); grid_include.getStore().removeAll();
grid_exclude.getStore().removeAll();
return; return;
} }
let records = values.map((filter) => me.parseGroupFilter(filter)); let records = values.map((filter) => me.parseGroupFilter(filter));
grid.getStore().setData(records); grid_include.getStore().setData(records);
grid_exclude.getStore().setData(records);
}, },
setInputValue: function(widgets, rec) { setInputValue: function(widgets, rec) {
@ -162,9 +192,18 @@ Ext.define('PBS.form.GroupFilter', {
let me = this; let me = this;
let filter = []; let filter = [];
me.lookup('grid').getStore().each((rec) => { me.lookup('grid-include').getStore().each((rec) => {
if (rec.data.type && rec.data.input) { if (rec.data.type && rec.data.input) {
filter.push(`${rec.data.type}:${rec.data.input}`); filter.push(`${rec.data.type}:${rec.data.input}`);
}
});
me.lookup('grid-exclude').getStore().each((rec) => {
if (rec.data.type && rec.data.input && rec.data.behavior) {
let behavior_string = '';
if (rec.data.behavior === 'exclude') {
behavior_string = 'exclude:';
}
filter.push(`${behavior_string}${rec.data.type}:${rec.data.input}`);
} }
}); });
@ -175,6 +214,9 @@ Ext.define('PBS.form.GroupFilter', {
}, },
control: { control: {
'grid pbsGroupBehaviorSelector': {
change: 'onBehaviorChange',
},
'grid pbsGroupFilterTypeSelector': { 'grid pbsGroupFilterTypeSelector': {
change: 'onTypeChange', change: 'onTypeChange',
}, },
@ -264,72 +306,59 @@ Ext.define('PBS.form.GroupFilter', {
items: [ items: [
{ {
xtype: 'grid', xtype: 'pbsGroupFilterGrid',
reference: 'grid', title: 'Include filters',
margin: '0 0 5 0', margin: '0 0 5 0',
scrollable: true, reference: 'grid-include',
height: 300,
store: { store: {
fields: ['type', 'input'], filters: [
}, function(item) {
return item.data.behavior === "include";
},
],
},
emptyText: gettext('Include all groups'), emptyText: gettext('Include all groups'),
viewConfig: { viewConfig: {
deferEmptyText: false, deferEmptyText: false,
}, },
columns: [ },
{
xtype: 'container',
layout: {
type: 'hbox',
},
items: [
{ {
text: gettext('Filter Type'), xtype: 'button',
xtype: 'widgetcolumn', text: gettext('Add include'),
dataIndex: 'type', iconCls: 'fa fa-plus-circle',
flex: 1, handler: 'addIncludeFilter',
widget: {
xtype: 'pbsGroupFilterTypeSelector',
isFormField: false,
},
}, },
{ {
text: gettext('Filter Value'), xtype: 'box',
xtype: 'widgetcolumn',
flex: 1, flex: 1,
onWidgetAttach: 'newInputColumn',
widget: {
padding: 0,
bodyPadding: 0,
xtype: 'fieldcontainer',
layout: 'fit',
defaults: {
margin: 0,
},
items: [
{
hidden: true,
xtype: 'pbsGroupTypeSelector',
isFormField: false,
},
{
hidden: true,
xtype: 'textfield',
type: 'regex',
isFormField: false,
},
{
hidden: true,
xtype: 'pbsGroupSelector',
isFormField: false,
},
],
},
}, },
{ {
xtype: 'widgetcolumn', xtype: 'box',
width: 40, style: 'margin: 3px 0px;',
widget: { html: `<span class="pmx-hint">${gettext('Note')}</span>: `
xtype: 'button', + gettext('Filters are additive'),
iconCls: 'fa fa-trash-o',
},
}, },
], ],
}, },
{
xtype: 'pbsGroupFilterGrid',
title: 'Exclude filters',
margin: '10 0 5 0',
reference: 'grid-exclude',
store: {
filters: [
function(item) {
return item.data.behavior === "exclude";
},
],
},
},
{ {
xtype: 'hiddenfield', xtype: 'hiddenfield',
reference: 'realfield', reference: 'realfield',
@ -356,9 +385,9 @@ Ext.define('PBS.form.GroupFilter', {
items: [ items: [
{ {
xtype: 'button', xtype: 'button',
text: gettext('Add'), text: gettext('Add exclude'),
iconCls: 'fa fa-plus-circle', iconCls: 'fa fa-plus-circle',
handler: 'addFilter', handler: 'addExcludeFilter',
}, },
{ {
xtype: 'box', xtype: 'box',
@ -368,7 +397,7 @@ Ext.define('PBS.form.GroupFilter', {
xtype: 'box', xtype: 'box',
style: 'margin: 3px 0px;', style: 'margin: 3px 0px;',
html: `<span class="pmx-hint">${gettext('Note')}</span>: ` html: `<span class="pmx-hint">${gettext('Note')}</span>: `
+ gettext('Filters are additive (OR-like)'), + gettext('Exclude filters will be applied after include filters'),
}, },
], ],
}, },
@ -384,6 +413,82 @@ Ext.define('PBS.form.GroupFilter', {
}, },
}); });
Ext.define('PBS.form.pbsGroupBehaviorSelector', {
extend: 'Proxmox.form.KVComboBox',
alias: 'widget.pbsGroupBehaviorSelector',
allowBlank: false,
comboItems: [
['include', gettext('Include')],
['exclude', gettext('Exclude')],
],
});
Ext.define('PBS.form.GroupFilterGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.pbsGroupFilterGrid',
scrollable: true,
height: 200,
store: {
fields: ['type', 'input'],
},
columns: [
{
text: gettext('Filter Type'),
xtype: 'widgetcolumn',
dataIndex: 'type',
flex: 1,
widget: {
xtype: 'pbsGroupFilterTypeSelector',
isFormField: false,
},
},
{
text: gettext('Filter Value'),
xtype: 'widgetcolumn',
flex: 1,
onWidgetAttach: 'newInputColumn',
widget: {
padding: 0,
bodyPadding: 0,
xtype: 'fieldcontainer',
layout: 'fit',
defaults:
{
margin: 0,
},
items: [
{
hidden: true,
xtype: 'pbsGroupTypeSelector',
isFormField: false,
},
{
hidden: true,
xtype: 'textfield',
type: 'regex',
isFormField: false,
},
{
hidden: true,
xtype: 'pbsGroupSelector',
isFormField: false,
},
],
},
},
{
xtype: 'widgetcolumn',
width: 40,
widget: {
xtype: 'button',
iconCls: 'fa fa-trash-o',
},
},
],
});
Ext.define('PBS.form.GroupFilterTypeSelector', { Ext.define('PBS.form.GroupFilterTypeSelector', {
extend: 'Proxmox.form.KVComboBox', extend: 'Proxmox.form.KVComboBox',
alias: 'widget.pbsGroupFilterTypeSelector', alias: 'widget.pbsGroupFilterTypeSelector',