pmg-gui/js/RuleInfo.js
Leo Nunner df2a647a72 mail filter: properly html-encode rule names
Rule names were not HTML-encoded in the rule overview. While some
encoding did happen, it was only on the first load for the info panel
on the right hand side, which was overriden as soon as the edit
window was opened/closed again.

The variable binding now gets HTML-encoded automatically, and the
renderer for rule names has been set to Ext.htmlEncode.

Signed-off-by: Leo Nunner <l.nunner@proxmox.com>
 [ T: rework commit message a bit (mostly subject) ]
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2023-05-17 12:01:35 +02:00

409 lines
8.4 KiB
JavaScript

Ext.define('PMG.RuleInfo', {
extend: 'Ext.panel.Panel',
xtype: 'pmgRuleInfo',
controller: {
xclass: 'Ext.app.ViewController',
setBaseUrl: function(baseurl) {
var me = this;
me.getViewModel().set('baseurl', baseurl);
me.reload();
},
reload: function() {
var me = this;
var viewmodel = me.getViewModel();
var baseurl = viewmodel.get('baseurl');
if (!baseurl) {
me.setRuleInfo(undefined);
return;
}
Proxmox.Utils.API2Request({
url: baseurl + "/config",
method: 'GET',
success: function(response, opts) {
me.setRuleInfo(response.result.data);
},
failure: function(response, opts) {
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
},
});
},
removeObjectGroup: function(rec) {
var me = this;
Ext.Msg.confirm(
gettext('Confirm'),
Ext.String.format(
gettext('Are you sure you want to remove entry {0}'),
"'" + rec.data.name + "'"),
function(button) {
if (button === 'yes') {
Proxmox.Utils.API2Request({
url: me.getViewModel().get('baseurl') + '/' + rec.data.oclass + '/'+ rec.data.typeid,
method: 'DELETE',
waitMsgTarget: me.getView(),
callback: function() {
me.reload();
},
failure: function(response, opts) {
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
},
});
}
},
);
},
addObjectGroup: function(type, record) {
var me = this;
var baseurl = me.getViewModel().get('baseurl');
var url = baseurl + '/' + type;
var id = type === 'action'?record.data.ogroup:record.data.id;
Proxmox.Utils.API2Request({
url: url,
params: { ogroup: id },
method: 'POST',
waitMsgTarget: me.getView(),
callback: function() {
me.reload();
},
failure: function(response, opts) {
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
},
});
},
setRuleInfo: function(ruledata) {
var me = this;
var viewmodel = me.getViewModel();
if (ruledata === undefined) {
viewmodel.set('selectedRule', null);
viewmodel.get('objects').setData([]);
} else {
viewmodel.set('selectedRule', ruledata);
var data = [];
Ext.Array.each(['from', 'to', 'when', 'what', 'action'], function(oc) {
var store = viewmodel.get(oc + 'objects');
if (ruledata[oc] === undefined || store === undefined) { return; }
// we build a filter for the objects,
// which are already added to the rule,
// so what we only show the ones,
// which are still available
var ids = Ext.Array.pluck(ruledata[oc], 'id');
// for the actions, we have a different id field
var idField = oc === 'action'?'ogroup':'id';
store.clearFilter();
store.addFilter({
filterFn: function(record) {
// FIXME
// actions have the ogroup as a string
// -> parseInt
return ids.indexOf(parseInt(record.data[idField], 10)) === -1;
},
});
store.load();
Ext.Array.each(ruledata[oc], function(og) {
data.push({ oclass: oc, name: og.name, typeid: og.id });
});
});
viewmodel.get('objects').setData(data);
}
},
removeIconClick: function(gridView, rowindex, colindex, button, event, record) {
var me = this;
me.removeObjectGroup(record);
},
removeDrop: function(gridView, data, overModel) {
var me = this;
var record = data.records[0]; // only one
me.removeObjectGroup(record);
return true;
},
addIconClick: function(gridView, rowindex, colindex, button, event, record) {
var me = this;
me.addObjectGroup(gridView.panel.type, record);
return true;
},
addDrop: function(gridView, data, overModel) {
var me = this;
var record = data.records[0]; // only one
me.addObjectGroup(data.view.panel.type, record);
return true;
},
control: {
'grid[reference=usedobjects]': {
drop: 'addDrop',
},
'tabpanel[reference=availobjects] > grid': {
drop: 'removeDrop',
},
},
},
viewModel: {
data: {
baseurl: '',
},
stores: {
objects: {
fields: ['oclass', 'name', 'typeid'],
groupField: 'oclass',
sorters: 'name',
},
actionobjects: {
model: 'pmg-action-list',
proxy: {
type: 'proxmox',
url: "/api2/json/config/ruledb/action/objects",
},
sorters: 'name',
},
fromobjects: {
model: 'pmg-object-group',
proxy: {
type: 'proxmox',
url: "/api2/json/config/ruledb/who",
},
sorters: 'name',
},
toobjects: {
model: 'pmg-object-group',
proxy: {
type: 'proxmox',
url: "/api2/json/config/ruledb/who",
},
sorters: 'name',
},
whatobjects: {
model: 'pmg-object-group',
proxy: {
type: 'proxmox',
url: "/api2/json/config/ruledb/what",
},
sorters: 'name',
},
whenobjects: {
model: 'pmg-object-group',
proxy: {
type: 'proxmox',
url: "/api2/json/config/ruledb/when",
},
sorters: 'name',
},
},
},
defaults: {
padding: '5 10 5 10',
},
bodyPadding: '5 0 5 0',
layout: {
type: 'vbox',
align: 'stretch',
},
scrollable: true,
items: [
{
xtype: 'panel',
bodyPadding: '10 10 10 10',
data: {
name: '',
},
bind: {
data: {
name: '{selectedRule.name:htmlEncode}',
priority: '{selectedRule.priority}',
active: '{selectedRule.active}',
direction: '{selectedRule.direction}',
selected: '{selectedRule}',
},
},
tpl: [
'<tpl if="selected">',
'<b>{name}</b><br><br>',
gettext('Priority') + ': {priority}<br>',
gettext('Direction') + ': {[PMG.Utils.format_rule_direction(values.direction)]}<br>',
gettext('Active') + ': {[Proxmox.Utils.format_boolean(values.active)]}<br>',
'<tpl else>',
gettext('Please select a rule.'),
'</tpl>',
],
},
{
xtype: 'grid',
reference: 'usedobjects',
hidden: true,
emptyText: gettext('No Objects'),
features: [{
id: 'group',
ftype: 'grouping',
enableGroupingMenu: false,
collapsible: false,
groupHeaderTpl: [
'{[PMG.Utils.format_oclass(values.name)]}',
],
}],
title: gettext('Used Objects'),
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
copy: true,
dragGroup: 'usedobjects',
dropGroup: 'unusedobjects',
// do not show default grid dragdrop behaviour
dropZone: {
indicatorHtml: '',
indicatorCls: '',
handleNodeDrop: Ext.emptyFn,
},
},
},
columns: [
{
header: gettext('Type'),
dataIndex: 'oclass',
hidden: true,
},
{
header: gettext('Name'),
dataIndex: 'name',
flex: 1,
},
{
text: '',
xtype: 'actioncolumn',
align: 'center',
width: 40,
items: [
{
iconCls: 'fa fa-fw fa-minus-circle',
tooltip: gettext('Remove'),
handler: 'removeIconClick',
},
],
},
],
bind: {
store: '{objects}',
hidden: '{!selectedRule}',
},
},
{
xtype: 'tabpanel',
title: gettext('Available Objects'),
reference: 'availobjects',
hidden: true,
bind: {
hidden: '{!selectedRule}',
},
defaults: {
xtype: 'grid',
emptyText: gettext('No Objects'),
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
dragGroup: 'unusedobjects',
dropGroup: 'usedobjects',
// do not show default grid dragdrop behaviour
dropZone: {
indicatorHtml: '',
indicatorCls: '',
handleNodeDrop: Ext.emptyFn,
},
},
},
columns: [
{
header: gettext('Name'),
dataIndex: 'name',
flex: 1,
},
{
text: '',
xtype: 'actioncolumn',
align: 'center',
width: 40,
items: [
{
iconCls: 'fa fa-fw fa-plus-circle',
tooltip: gettext('Add'),
handler: 'addIconClick',
},
],
},
],
},
items: [
{
title: gettext('Action'),
bind: {
store: '{actionobjects}',
},
type: 'action',
iconCls: 'fa fa-flag',
},
{
title: gettext('From'),
iconCls: 'fa fa-user-circle',
type: 'from',
bind: {
store: '{fromobjects}',
},
},
{
title: gettext('To'),
iconCls: 'fa fa-user-circle',
type: 'to',
bind: {
store: '{toobjects}',
},
},
{
title: gettext('What'),
iconCls: 'fa fa-cube',
type: 'what',
bind: {
store: '{whatobjects}',
},
},
{
title: gettext('When'),
iconCls: 'fa fa-clock-o',
type: 'when',
bind: {
store: '{whenobjects}',
},
},
],
},
],
});