rewrite ruleinfo

complete rewrite of the ruleinfo sidebar

* uses mvvm system
* show tabpanel with all unused objects, each category in a tab
* group the used objects by type
* allow for drag/drop or the actionbuttons for adding/removing

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2017-04-04 13:48:56 +02:00 committed by Dietmar Maurer
parent d75b37b80b
commit c3339ea165

View File

@ -1,120 +1,73 @@
Ext.define('PMG.RuleInfo', {
extend: 'Ext.grid.GridPanel',
alias: 'widget.pmgRuleInfo',
extend: 'Ext.panel.Panel',
xtype: 'pmgRuleInfo',
baseurl: undefined,
controller: {
xclass: 'Ext.app.ViewController',
ruledata: undefined,
setBaseUrl: function(baseurl) {
var me = this;
me.getViewModel().set('baseurl', baseurl);
me.reload();
},
emptyText: gettext('Please select a rule.'),
reload: function() {
var me = this;
var viewmodel = me.getViewModel();
var baseurl = viewmodel.get('baseurl');
setBaseUrl: function(baseurl) {
var me = this;
me.baseurl = baseurl;
me.reload();
},
reload: function() {
var me = this;
if (!me.baseurl) {
me.setRuleInfo(undefined);
return;
}
Proxmox.Utils.API2Request({
url: me.baseurl + "/config",
method: 'GET',
waitMsgTarget: me,
success: function(response, opts) {
me.setRuleInfo(response.result.data);
},
failure: function (response, opts) {
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
if (!baseurl) {
me.setRuleInfo(undefined);
return;
}
});
},
setRuleInfo: function(ruledata) {
var me = this;
me.ruledata = ruledata;
me.down('#addFromButton').setDisabled(me.ruledata === undefined);
me.down('#addToButton').setDisabled(me.ruledata === undefined);
me.down('#addWhenButton').setDisabled(me.ruledata === undefined);
me.down('#addWhatButton').setDisabled(me.ruledata === undefined);
me.down('#addActionButton').setDisabled(me.ruledata === undefined);
if (me.ruledata === undefined) {
me.store.setData([]);
me.down('#ruleinfo').update(me.emtpyText);
me.down('#ruledata').setHidden(true);
} else {
var html = '<b>' + Ext.String.htmlEncode(me.ruledata.name) + '</b>';
html += '<br><br>';
html += 'Priority: ' + me.ruledata.priority + '<br>';
html += 'Direction: ' + PMG.Utils.format_rule_direction(me.ruledata.direction) + '<br>';
html += 'Active: ' + Proxmox.Utils.format_boolean(me.ruledata.active) + '<br>';
var data = [];
Ext.Array.each(['from', 'to', 'when', 'what', 'action'], function(oc) {
var list = ruledata[oc];
if (list === undefined) { return; }
Ext.Array.each(list, function(og) {
data.push({ oclass: oc, name: og.name, id: og.id });
});
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);
}
});
},
me.store.setData(data);
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);
}
});
}
}
);
},
me.down('#ruleinfo').update(html);
me.down('#ruledata').setHidden(false);
}
},
initComponent : function() {
var me = this;
me.store = new Ext.data.Store({
fields: [ 'oclass', 'name' ]
});
me.columns = [
{
header: gettext('Type'),
dataIndex: 'oclass',
},
{
header: gettext('name'),
dataIndex: 'name',
flex: 1
}
];
me.selModel = Ext.create('Ext.selection.RowModel', {});
var remove_btn = Ext.createWidget('proxmoxStdRemoveButton', {
selModel: me.selModel,
getUrl: function(rec) {
return me.baseurl + '/' + rec.data.oclass + '/'+ rec.data.id;
},
callback: function() { me.reload(); },
getRecordName: function(rec) { return rec.data.name; },
waitMsgTarget: me
});
var add_object_group = function(url, ogroupId) {
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: ogroupId },
params: { ogroup: id },
method: 'POST',
waitMsgTarget: me,
waitMsgTarget: me.getView(),
callback: function() {
me.reload();
},
@ -122,140 +75,337 @@ Ext.define('PMG.RuleInfo', {
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
}
});
};
},
me.dockedItems = [];
setRuleInfo: function(ruledata) {
var me = this;
me.dockedItems.push({
xtype: 'toolbar',
dock: 'top',
items: [
{
text: gettext('From'),
disabled: true,
itemId: 'addFromButton',
handler: function() {
var win = Ext.create('PMG.ObjectGroupSelector', {
rulegroup: 'from',
listeners: {
selectObjectGroup: function(view, rec) {
win.destroy();
add_object_group(me.baseurl + '/from', rec.data.id);
}
}
});
win.show();
}
},
{
text: gettext('To'),
disabled: true,
itemId: 'addToButton',
handler: function() {
var win = Ext.create('PMG.ObjectGroupSelector', {
rulegroup: 'to',
listeners: {
selectObjectGroup: function(view, rec) {
win.destroy();
add_object_group(me.baseurl + '/to', rec.data.id);
}
}
});
win.show();
}
},
{
text: gettext('When'),
disabled: true,
itemId: 'addWhenButton',
handler: function() {
var win = Ext.create('PMG.ObjectGroupSelector', {
rulegroup: 'when',
listeners: {
selectObjectGroup: function(view, rec) {
win.destroy();
add_object_group(me.baseurl + '/when', rec.data.id);
}
}
});
win.show();
}
},
{
text: gettext('What'),
disabled: true,
itemId: 'addWhatButton',
handler: function() {
var win = Ext.create('PMG.ObjectGroupSelector', {
rulegroup: 'what',
listeners: {
selectObjectGroup: function(view, rec) {
win.destroy();
add_object_group(me.baseurl + '/what', rec.data.id);
}
}
});
win.show();
}
},
{
text: gettext('Action'),
disabled: true,
itemId: 'addActionButton',
handler: function() {
var win = Ext.create('PMG.ObjectGroupSelector', {
rulegroup: 'action',
listeners: {
selectObjectGroup: function(view, rec) {
win.destroy();
add_object_group(me.baseurl + '/action', rec.data.ogroup);
}
}
});
win.show();
}
},
remove_btn
]
});
var viewmodel = me.getViewModel();
me.dockedItems.push({
dock: 'top',
border: 1,
layout: 'anchor',
itemId: 'ruledata',
items: [
{
xtype: 'component',
anchor: '100%',
itemId: 'ruleinfo',
style: { 'white-space': 'pre' },
padding: 10,
html: me.emptyText,
listeners: {
dblclick: {
fn: function(e, t) {
if (me.ruledata === undefined) { return; }
me.fireEvent('dblclickRuleInfo', me, e, t, me.ruledata);
},
element: 'el',
scope: this,
if (ruledata === undefined) {
viewmodel.set('selectedRule', null);
viewmodel.get('objects').setData([]);
} else {
ruledata.name = Ext.String.htmlEncode(ruledata.name);
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])) === -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: undefined,
},
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,
data: {
name: false,
},
bind: {
data: {
name: '{selectedRule.name}',
priority: '{selectedRule.priority}',
active: '{selectedRule.active}',
direction: '{selectedRule.direction}',
selected: '{selectedRule}'
}
},
tpl: [
'<tpl if="selected">',
'<b>{name}</b><br><br>',
'Priority: {priority}<br>',
'Direction: {[PMG.Utils.format_rule_direction(values.direction)]}<br>',
'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
},
{
header: gettext('Actions'),
xtype: 'actioncolumn',
width: 65,
items: [
{
iconCls: 'x-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
},
{
header: gettext('Actions'),
width: 65,
xtype: 'actioncolumn',
items: [
{
iconCls: 'x-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}'
},
},
]
});
Ext.apply(me, {
listeners: {
activate: function() { me.reload() }
}
});
me.callParent();
if (me.baseurl) {
me.reload();
}
}
]
});