Added support to enable/disable rules. Fixes #6794
parent
2aac87569b
commit
173cb60691
docs/en_US
web/pgadmin/browser/server_groups
servers/databases/schemas/tables
rules
templates/rules/sql
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
|
@ -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 #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 #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 #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
|
Housekeeping
|
||||||
************
|
************
|
||||||
|
|
|
@ -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
|
executed instead of the original command; if Do Instead specifies *No*, the
|
||||||
rule will be invoked in addition to the original command.
|
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.
|
Click the *Condition* tab to continue.
|
||||||
|
|
||||||
.. image:: images/rule_condition.png
|
.. image:: images/rule_condition.png
|
||||||
|
|
|
@ -177,7 +177,7 @@ class ServerGroupView(NodeView):
|
||||||
# if server group id is 1 we won't delete it.
|
# if server group id is 1 we won't delete it.
|
||||||
sg = groups.first()
|
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()
|
shared=True).all()
|
||||||
if shared_servers:
|
if shared_servers:
|
||||||
return make_json_response(
|
return make_json_response(
|
||||||
|
|
|
@ -249,7 +249,8 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||||
rset['rows'][0]['oid'],
|
rset['rows'][0]['oid'],
|
||||||
tid,
|
tid,
|
||||||
rset['rows'][0]['name'],
|
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(
|
return make_json_response(
|
||||||
|
@ -276,7 +277,9 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||||
row['oid'],
|
row['oid'],
|
||||||
tid,
|
tid,
|
||||||
row['name'],
|
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(
|
return make_json_response(
|
||||||
|
@ -385,7 +388,10 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||||
rid,
|
rid,
|
||||||
tid,
|
tid,
|
||||||
name,
|
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:
|
except Exception as e:
|
||||||
|
|
|
@ -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 |
|
@ -12,8 +12,8 @@ import RuleSchema from './rule.ui';
|
||||||
define('pgadmin.node.rule', [
|
define('pgadmin.node.rule', [
|
||||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform',
|
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform',
|
||||||
'pgadmin.node.schema.dir/schema_child_tree_node',
|
'pgadmin.node.schema.dir/schema_child_tree_node', 'pgadmin.alertifyjs',
|
||||||
], function(gettext, url_for, $, _, pgAdmin, pgBrowser, Backform, SchemaChildTreeNode) {
|
], function(gettext, url_for, $, _, pgAdmin, pgBrowser, Backform, SchemaChildTreeNode, alertify) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create and add a rule collection into nodes
|
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},
|
icon: 'wcTabIcon icon-rule', data: {action: 'create', check: true},
|
||||||
enable: 'canCreate',
|
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) {
|
getSchema: function(treeNodeInfo, itemNodeData) {
|
||||||
return new RuleSchema(
|
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);
|
||||||
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,24 @@ export default class RuleSchema extends BaseUISchema {
|
||||||
state.view = obj.fieldOptions.nodeData.label;
|
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',
|
id: 'event', label: gettext('Event'), control: 'select2',
|
||||||
group: gettext('Definition'), type: 'select',
|
group: gettext('Definition'), type: 'select',
|
||||||
|
@ -94,10 +112,6 @@ export default class RuleSchema extends BaseUISchema {
|
||||||
id: 'system_rule', label: gettext('System rule?'),
|
id: 'system_rule', label: gettext('System rule?'),
|
||||||
type: 'switch', mode: ['properties'],
|
type: 'switch', mode: ['properties'],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'enabled', label: gettext('Enabled?'),
|
|
||||||
type: 'switch', mode: ['properties'],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'comment', label: gettext('Comment'), cell: 'text', type: 'multiline',
|
id: 'comment', label: gettext('Comment'), cell: 'text', type: 'multiline',
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,3 +7,14 @@
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
height: 1.3em;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
SELECT
|
SELECT
|
||||||
rw.oid AS oid,
|
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
|
FROM
|
||||||
pg_catalog.pg_rewrite rw
|
pg_catalog.pg_rewrite rw
|
||||||
WHERE
|
WHERE
|
||||||
|
|
|
@ -12,6 +12,7 @@ SELECT
|
||||||
{# ===== Check whether it is system rule or not ===== #}
|
{# ===== Check whether it is system rule or not ===== #}
|
||||||
CASE WHEN rw.rulename = '_RETURN' THEN True ELSE False END AS system_rule,
|
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,
|
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
|
pg_catalog.pg_get_ruledef(rw.oid) AS definition
|
||||||
FROM
|
FROM
|
||||||
pg_catalog.pg_rewrite rw
|
pg_catalog.pg_rewrite rw
|
||||||
|
|
|
@ -35,3 +35,13 @@ CREATE OR REPLACE RULE {{ conn|qtIdent(rule_name) }} AS
|
||||||
{% set old_comment = o_data.comment|default('', true) %}
|
{% set old_comment = o_data.comment|default('', true) %}
|
||||||
{% if (data.comment is defined and (data.comment != old_comment)) %}
|
{% 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 %}
|
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 %}
|
||||||
|
|
Loading…
Reference in New Issue