Added support to enable/disable rules. Fixes #6794

This commit is contained in:
Pradip Parkale 2021-10-14 11:44:03 +05:30 committed by Akshay Joshi
parent 2aac87569b
commit 173cb60691
12 changed files with 191 additions and 11 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -13,6 +13,7 @@ New features
| `Issue #6081 <https://redmine.postgresql.org/issues/6081>`_ - Added support for advanced table fields like the foreign key, primary key in the ERD tool.
| `Issue #6529 <https://redmine.postgresql.org/issues/6529>`_ - Added index creation when generating SQL in the ERD tool.
| `Issue #6657 <https://redmine.postgresql.org/issues/6657>`_ - Added support for authentication via the webserver (REMOTE_USER).
| `Issue #6794 <https://redmine.postgresql.org/issues/6794>`_ - Added support to enable/disable rules.
Housekeeping
************

View File

@ -37,6 +37,13 @@ Use the fields in the *Definition* tab to write parameters:
executed instead of the original command; if Do Instead specifies *No*, the
rule will be invoked in addition to the original command.
.. image:: images/rule_definition_enabled.png
:alt: Trigger enabled in dialog tab
:align: center
* *Rule enabled* field is available in rule dialog once the rule is created.
You can select one of the four options available.
Click the *Condition* tab to continue.
.. image:: images/rule_condition.png

View File

@ -177,7 +177,7 @@ class ServerGroupView(NodeView):
# if server group id is 1 we won't delete it.
sg = groups.first()
shared_servers = Server.query.filter_by(servergroup_id=sg.id,
shared_servers = Server.query.filter_by(servergroup_id=gid,
shared=True).all()
if shared_servers:
return make_json_response(

View File

@ -249,7 +249,8 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
rset['rows'][0]['oid'],
tid,
rset['rows'][0]['name'],
icon="icon-rule"
icon="icon-rule" if
rset['rows'][0]['is_enable_rule'] == 'D' else "icon-rule-bad"
)
return make_json_response(
@ -276,7 +277,9 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
row['oid'],
tid,
row['name'],
icon="icon-rule"
icon="icon-rule-bad"
if 'is_enable_rule' in row and
row['is_enable_rule'] == 'D' else "icon-rule"
))
return make_json_response(
@ -385,7 +388,10 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
rid,
tid,
name,
icon="icon-%s" % self.node_type
icon="icon-%s-bad" % self.node_type
if 'is_enable_rule' in data and
data['is_enable_rule'] == 'D'
else "icon-%s" % self.node_type
)
)
except Exception as e:

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FEE07B;stroke:#DDA91D;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;}
.st1{fill:none;stroke:#DDA91D;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;}
.st2{fill:#D0021B;}
</style>
<g>
<g id="_8">
<rect x="2.4" y="5" class="st0" width="11.1" height="6"/>
<line class="st1" x1="10.9" y1="5.4" x2="10.9" y2="8.9"/>
<line class="st1" x1="6.9" y1="5.4" x2="6.9" y2="8.9"/>
<line class="st1" x1="8.9" y1="5.4" x2="8.9" y2="7.9"/>
<line class="st1" x1="4.9" y1="5.4" x2="4.9" y2="7.9"/>
</g>
<path class="st2" d="M14,5.1l1-1c0.3-0.3,0.3-0.8,0-1.1s-0.8-0.3-1.1,0l-1,1l-1-1c-0.3-0.3-0.8-0.3-1.1,0s-0.3,0.8,0,1.1l1,1l-1,1
c-0.3,0.3-0.3,0.8,0,1.1c0.1,0.1,0.3,0.2,0.5,0.2s0.6-0.1,0.7-0.3l1-1l1,1c0.1,0.1,0.3,0.2,0.5,0.2s0.4,0,0.5-0.2
c0.3-0.3,0.3-0.8,0-1.1L14,5.1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -12,8 +12,8 @@ import RuleSchema from './rule.ui';
define('pgadmin.node.rule', [
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform',
'pgadmin.node.schema.dir/schema_child_tree_node',
], function(gettext, url_for, $, _, pgAdmin, pgBrowser, Backform, SchemaChildTreeNode) {
'pgadmin.node.schema.dir/schema_child_tree_node', 'pgadmin.alertifyjs',
], function(gettext, url_for, $, _, pgAdmin, pgBrowser, Backform, SchemaChildTreeNode, alertify) {
/**
Create and add a rule collection into nodes
@ -112,8 +112,93 @@ define('pgadmin.node.rule', [
icon: 'wcTabIcon icon-rule', data: {action: 'create', check: true},
enable: 'canCreate',
},
{
name: 'enable_rule', node: 'rule', module: this,
applies: ['object', 'context'], callback: 'enable_rule',
category: 'connect', priority: 3, label: gettext('Enable rule'),
icon: 'fa fa-check', enable: 'canCreate_with_rule_enable',
},{
name: 'disable_rule', node: 'rule', module: this,
applies: ['object', 'context'], callback: 'disable_rule',
category: 'drop', priority: 3, label: gettext('Disable rule'),
icon: 'fa fa-times', enable: 'canCreate_with_rule_disable'
}
]);
},
callbacks: {
/* Enable rule */
enable_rule: function(args) {
var input = args || {},
obj = this,
t = pgBrowser.tree,
i = input.item || t.selected(),
d = i ? t.itemData(i) : undefined;
if (!d)
return false;
var data = d;
$.ajax({
url: obj.generate_url(i, 'obj' , d, true),
type:'PUT',
data: {'is_enable_rule' : 'O'},
dataType: 'json',
})
.done(function() {
alertify.success('Rule updated.');
t.removeIcon(i);
data.icon = 'icon-rule';
t.addIcon(i, {icon: data.icon});
t.unload(i);
t.setInode(false);
t.deselect(i);
// Fetch updated data from server
setTimeout(function() {
t.select(i);
}, 10);
})
.fail(function(xhr, status, error) {
alertify.pgRespErrorNotify(xhr, error);
t.unload(i);
});
},
/* Disable rule */
disable_rule: function(args) {
var input = args || {},
obj = this,
t = pgBrowser.tree,
i = input.item || t.selected(),
d = i ? t.itemData(i) : undefined;
if (!d)
return false;
var data = d;
$.ajax({
url: obj.generate_url(i, 'obj' , d, true),
type:'PUT',
data: {'is_enable_rule' : 'D'},
dataType: 'json',
})
.done(function() {
alertify.success('Rule updated');
t.removeIcon(i);
data.icon = 'icon-rule-bad';
t.addIcon(i, {icon: data.icon});
t.unload(i);
t.setInode(false);
t.deselect(i);
// Fetch updated data from server
setTimeout(function() {
t.select(i);
}, 10);
})
.fail(function(xhr, status, error) {
alertify.pgRespErrorNotify(xhr, error, gettext('Disable rule failed'));
t.unload(i);
});
},
},
getSchema: function(treeNodeInfo, itemNodeData) {
return new RuleSchema(
{
@ -216,6 +301,26 @@ define('pgadmin.node.rule', [
},
canCreate_with_rule_enable: function(itemData, item, data) {
var treeData = pgBrowser.tree.getTreeNodeHierarchy(item);
if ('view' in treeData) {
return false;
}
return itemData.icon === 'icon-rule-bad' &&
this.canCreate.apply(this,[itemData, item, data]);
},
// Check to whether rule is enable ?
canCreate_with_rule_disable: function(itemData, item, data) {
var treeData = pgBrowser.tree.getTreeNodeHierarchy(item);
if ('view' in treeData) {
return false;
}
return itemData.icon === 'icon-rule' &&
this.canCreate.apply(itemData, item, data);
},
});
}

View File

@ -66,6 +66,24 @@ export default class RuleSchema extends BaseUISchema {
state.view = obj.fieldOptions.nodeData.label;
},
},
{
id: 'is_enable_rule', label: gettext('Rule enabled?'),
mode: ['edit', 'properties'], group: gettext('Definition'),
type: 'select',
disabled: () => {
if('catalog' in obj.fieldOptions.nodeInfo || 'view' in obj.fieldOptions.nodeInfo) {
return true;
}
return false;
},
options: [
{label: gettext('Enable'), value: 'O'},
{label: gettext('Enable Replica'), value: 'R'},
{label: gettext('Enable Always'), value: 'A'},
{label: gettext('Disable'), value: 'D'},
],
controlProps: { allowClear: false },
},
{
id: 'event', label: gettext('Event'), control: 'select2',
group: gettext('Definition'), type: 'select',
@ -94,10 +112,6 @@ export default class RuleSchema extends BaseUISchema {
id: 'system_rule', label: gettext('System rule?'),
type: 'switch', mode: ['properties'],
},
{
id: 'enabled', label: gettext('Enabled?'),
type: 'switch', mode: ['properties'],
},
{
id: 'comment', label: gettext('Comment'), cell: 'text', type: 'multiline',
},

View File

@ -7,3 +7,14 @@
vertical-align: middle;
height: 1.3em;
}
.icon-rule-bad{
background-image: url('{{ url_for('NODE-rule.static', filename='img/rule-bad.svg') }}') !important;
border-radius: 10px;
background-size: 20px !important;
background-repeat: no-repeat;
align-content: center;
vertical-align: middle;
height: 1.3em;
}

View File

@ -1,6 +1,9 @@
SELECT
rw.oid AS oid,
rw.rulename AS name
rw.rulename AS name,
CASE WHEN rw.ev_enabled != 'D' THEN True ELSE False END AS enabled,
rw.ev_enabled AS is_enable_rule
FROM
pg_catalog.pg_rewrite rw
WHERE

View File

@ -12,6 +12,7 @@ SELECT
{# ===== Check whether it is system rule or not ===== #}
CASE WHEN rw.rulename = '_RETURN' THEN True ELSE False END AS system_rule,
CASE WHEN rw.ev_enabled != 'D' THEN True ELSE False END AS enabled,
rw.ev_enabled AS is_enable_rule,
pg_catalog.pg_get_ruledef(rw.oid) AS definition
FROM
pg_catalog.pg_rewrite rw

View File

@ -35,3 +35,13 @@ CREATE OR REPLACE RULE {{ conn|qtIdent(rule_name) }} AS
{% set old_comment = o_data.comment|default('', true) %}
{% if (data.comment is defined and (data.comment != old_comment)) %}
COMMENT ON RULE {{ conn|qtIdent(rule_name) }} ON {{ conn|qtIdent(o_data.schema, o_data.view) }} IS {{ data.comment|qtLiteral }};{% endif %}
{% if data.enabled is defined and o_data.enabled != data.enabled %}
ALTER TABLE {{ conn|qtIdent(o_data.schema, o_data.view) }} {% if (data.enabled in ['false', False]) %}DISABLE{% endif %}{% if (data.enabled in ['true', True]) %}ENABLE{% endif %} RULE {{ conn|qtIdent(o_data.name) }};
{% endif %}
{% if data.is_enable_rule is defined and o_data.is_enable_rule != data.is_enable_rule %}
{% set enable_map = {'R':'ENABLE REPLICA', 'A':'ENABLE ALWAYS', 'O':'ENABLE', 'D':'DISABLE'} %}
ALTER TABLE {{ conn|qtIdent(o_data.schema, o_data.view) }}
{{ enable_map[data.is_enable_rule] }} RULE {{ conn|qtIdent(o_data.name) }};
{% endif %}