mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-01-23 23:13:38 -06:00
Added support to view trigger function under the respective trigger node. Fixes #2519
This commit is contained in:
parent
365ec0ba9f
commit
556278dbc5
@ -10,6 +10,7 @@ New features
|
|||||||
************
|
************
|
||||||
|
|
||||||
| `Issue #1402 <https://redmine.postgresql.org/issues/1402>`_ - Added Macro support.
|
| `Issue #1402 <https://redmine.postgresql.org/issues/1402>`_ - Added Macro support.
|
||||||
|
| `Issue #2519 <https://redmine.postgresql.org/issues/2519>`_ - Added support to view trigger function under the respective trigger node.
|
||||||
| `Issue #3794 <https://redmine.postgresql.org/issues/3794>`_ - Allow user to change the database connection from an open query tool tab.
|
| `Issue #3794 <https://redmine.postgresql.org/issues/3794>`_ - Allow user to change the database connection from an open query tool tab.
|
||||||
| `Issue #5200 <https://redmine.postgresql.org/issues/5200>`_ - Added support to ignore the owner while comparing objects in the Schema Diff tool.
|
| `Issue #5200 <https://redmine.postgresql.org/issues/5200>`_ - Added support to ignore the owner while comparing objects in the Schema Diff tool.
|
||||||
| `Issue #5857 <https://redmine.postgresql.org/issues/5857>`_ - Added documentation for Macro support.
|
| `Issue #5857 <https://redmine.postgresql.org/issues/5857>`_ - Added documentation for Macro support.
|
||||||
|
@ -1151,6 +1151,14 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
|||||||
else:
|
else:
|
||||||
object_type = 'function'
|
object_type = 'function'
|
||||||
|
|
||||||
|
# We are showing trigger functions under the trigger node.
|
||||||
|
# It may possible that trigger is in one schema and trigger
|
||||||
|
# function is in another schema, so to show the SQL we need to
|
||||||
|
# change the schema id i.e scid.
|
||||||
|
if self.node_type == 'trigger_function' and \
|
||||||
|
scid != resp_data['pronamespace']:
|
||||||
|
scid = resp_data['pronamespace']
|
||||||
|
|
||||||
# Get Schema Name from its OID.
|
# Get Schema Name from its OID.
|
||||||
self._get_schema_name_from_oid(resp_data)
|
self._get_schema_name_from_oid(resp_data)
|
||||||
|
|
||||||
|
@ -38,9 +38,26 @@ define('pgadmin.node.trigger_function', [
|
|||||||
dialogHelp: url_for('help.static', {'filename': 'trigger_function_dialog.html'}),
|
dialogHelp: url_for('help.static', {'filename': 'trigger_function_dialog.html'}),
|
||||||
label: gettext('Trigger function'),
|
label: gettext('Trigger function'),
|
||||||
collection_type: 'coll-trigger_function',
|
collection_type: 'coll-trigger_function',
|
||||||
|
canEdit: function(itemData, item) {
|
||||||
|
let node = pgBrowser.treeMenu.findNodeByDomElement(item);
|
||||||
|
|
||||||
|
if (!node || node.parentNode.getData()._type === 'trigger')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
hasSQL: true,
|
hasSQL: true,
|
||||||
|
showMenu: function(itemData, item) {
|
||||||
|
let node = pgBrowser.treeMenu.findNodeByDomElement(item);
|
||||||
|
|
||||||
|
if (!node || node.parentNode.getData()._type === 'trigger')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
hasDepends: true,
|
hasDepends: true,
|
||||||
hasStatistics: true,
|
hasStatistics: true,
|
||||||
|
url_jump_after_node: 'schema',
|
||||||
Init: function() {
|
Init: function() {
|
||||||
/* Avoid mulitple registration of menus */
|
/* Avoid mulitple registration of menus */
|
||||||
if (this.initialized)
|
if (this.initialized)
|
||||||
@ -68,7 +85,6 @@ define('pgadmin.node.trigger_function', [
|
|||||||
enable: 'canCreate',
|
enable: 'canCreate',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
},
|
},
|
||||||
model: pgBrowser.Node.Model.extend({
|
model: pgBrowser.Node.Model.extend({
|
||||||
idAttribute: 'oid',
|
idAttribute: 'oid',
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
SELECT p.oid AS tfuncoid, p.proname AS tfunction,
|
||||||
|
p.pronamespace AS tfuncschoid, n.nspname AS tfuncschema, l.lanname
|
||||||
|
FROM pg_trigger t
|
||||||
|
LEFT OUTER JOIN pg_proc p ON p.oid=t.tgfoid
|
||||||
|
LEFT OUTER JOIN pg_namespace n ON n.oid = p.pronamespace
|
||||||
|
LEFT OUTER JOIN pg_language l ON l.oid=p.prolang
|
||||||
|
WHERE NOT tgisinternal
|
||||||
|
AND tgrelid = {{tid}}::OID
|
||||||
|
AND t.oid = {{trid}}::OID
|
@ -0,0 +1,9 @@
|
|||||||
|
SELECT p.oid AS tfuncoid, p.proname AS tfunction,
|
||||||
|
p.pronamespace AS tfuncschoid, n.nspname AS tfuncschema, l.lanname
|
||||||
|
FROM pg_trigger t
|
||||||
|
LEFT OUTER JOIN pg_proc p ON p.oid=t.tgfoid
|
||||||
|
LEFT OUTER JOIN pg_namespace n ON n.oid = p.pronamespace
|
||||||
|
LEFT OUTER JOIN pg_language l ON l.oid=p.prolang
|
||||||
|
WHERE NOT tgisinternal
|
||||||
|
AND tgrelid = {{tid}}::OID
|
||||||
|
AND t.oid = {{trid}}::OID
|
@ -121,7 +121,7 @@ class TriggerModule(CollectionNodeModule):
|
|||||||
"""
|
"""
|
||||||
Load the module node as a leaf node
|
Load the module node as a leaf node
|
||||||
"""
|
"""
|
||||||
return False
|
return True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def module_use_template_javascript(self):
|
def module_use_template_javascript(self):
|
||||||
@ -280,6 +280,11 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||||||
)
|
)
|
||||||
self.template_path = 'triggers/sql/{0}/#{1}#'.format(
|
self.template_path = 'triggers/sql/{0}/#{1}#'.format(
|
||||||
self.manager.server_type, self.manager.version)
|
self.manager.server_type, self.manager.version)
|
||||||
|
|
||||||
|
self.trigger_function_template_path = \
|
||||||
|
'trigger_functions/{0}/sql/#{1}#'.format(
|
||||||
|
self.manager.server_type, self.manager.version)
|
||||||
|
|
||||||
# Store server type
|
# Store server type
|
||||||
self.server_type = self.manager.server_type
|
self.server_type = self.manager.server_type
|
||||||
# We need parent's name eg table name and schema name
|
# We need parent's name eg table name and schema name
|
||||||
@ -293,6 +298,69 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||||||
|
|
||||||
return wrap
|
return wrap
|
||||||
|
|
||||||
|
@check_precondition
|
||||||
|
def get_children_nodes(self, manager, **kwargs):
|
||||||
|
"""
|
||||||
|
Function is used to get the child nodes.
|
||||||
|
:param manager:
|
||||||
|
:param kwargs:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
nodes = []
|
||||||
|
scid = kwargs.get('scid')
|
||||||
|
tid = kwargs.get('tid')
|
||||||
|
trid = kwargs.get('trid')
|
||||||
|
|
||||||
|
try:
|
||||||
|
SQL = render_template(
|
||||||
|
"/".join([self.template_path, 'get_function_oid.sql']),
|
||||||
|
tid=tid, trid=trid
|
||||||
|
)
|
||||||
|
status, rset = self.conn.execute_2darray(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=rset)
|
||||||
|
|
||||||
|
if len(rset['rows']) == 0:
|
||||||
|
return gone(
|
||||||
|
gettext("Could not find the specified trigger function"))
|
||||||
|
|
||||||
|
# For language EDB SPL we should not display any node.
|
||||||
|
if rset['rows'][0]['lanname'] != 'edbspl':
|
||||||
|
trigger_function_schema_oid = rset['rows'][0]['tfuncschoid']
|
||||||
|
|
||||||
|
sql = render_template("/".join(
|
||||||
|
[self.trigger_function_template_path, self._NODE_SQL]),
|
||||||
|
scid=trigger_function_schema_oid,
|
||||||
|
fnid=rset['rows'][0]['tfuncoid']
|
||||||
|
)
|
||||||
|
status, res = self.conn.execute_2darray(sql)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=rset)
|
||||||
|
|
||||||
|
if len(res['rows']) == 0:
|
||||||
|
return gone(gettext(
|
||||||
|
"Could not find the specified trigger function"))
|
||||||
|
|
||||||
|
row = res['rows'][0]
|
||||||
|
func_name = row['name']
|
||||||
|
# If trigger function is from another schema then we should
|
||||||
|
# display the name as schema qulified name.
|
||||||
|
if scid != trigger_function_schema_oid:
|
||||||
|
func_name = \
|
||||||
|
rset['rows'][0]['tfuncschema'] + '.' + row['name']
|
||||||
|
|
||||||
|
trigger_func = current_app.blueprints['NODE-trigger_function']
|
||||||
|
nodes.append(trigger_func.generate_browser_node(
|
||||||
|
row['oid'], trigger_function_schema_oid,
|
||||||
|
gettext(func_name),
|
||||||
|
icon="icon-trigger_function", funcowner=row['funcowner'],
|
||||||
|
language=row['lanname'], inode=False)
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return internal_server_error(errormsg=str(e))
|
||||||
|
|
||||||
|
return nodes
|
||||||
|
|
||||||
@check_precondition
|
@check_precondition
|
||||||
def get_trigger_functions(self, gid, sid, did, scid, tid, trid=None):
|
def get_trigger_functions(self, gid, sid, did, scid, tid, trid=None):
|
||||||
"""
|
"""
|
||||||
|
@ -404,7 +404,7 @@ define('pgadmin.browser', [
|
|||||||
// Create the object menu dynamically
|
// Create the object menu dynamically
|
||||||
if (item && obj.menus['object'] && obj.menus['object'][d._type]) {
|
if (item && obj.menus['object'] && obj.menus['object'][d._type]) {
|
||||||
pgAdmin.Browser.MenuCreator(
|
pgAdmin.Browser.MenuCreator(
|
||||||
$obj_mnu, obj.menus['object'][d._type], obj.menu_categories, d, item
|
obj.Nodes, $obj_mnu, obj.menus['object'][d._type], obj.menu_categories, d, item
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Create a dummy 'no object seleted' menu
|
// Create a dummy 'no object seleted' menu
|
||||||
@ -503,7 +503,7 @@ define('pgadmin.browser', [
|
|||||||
context_menu = {};
|
context_menu = {};
|
||||||
|
|
||||||
pgAdmin.Browser.MenuCreator(
|
pgAdmin.Browser.MenuCreator(
|
||||||
$div, menus, obj.menu_categories, d, item, context_menu
|
obj.Nodes, $div, menus, obj.menu_categories, d, item, context_menu
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -877,7 +877,7 @@ define('pgadmin.browser', [
|
|||||||
$dropdown.empty();
|
$dropdown.empty();
|
||||||
|
|
||||||
if (pgAdmin.Browser.MenuCreator(
|
if (pgAdmin.Browser.MenuCreator(
|
||||||
$dropdown, obj.menus[o.menu], obj.menu_categories
|
obj.Nodes, $dropdown, obj.menus[o.menu], obj.menu_categories
|
||||||
)) {
|
)) {
|
||||||
$mnu.removeClass('d-none');
|
$mnu.removeClass('d-none');
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'underscore', 'sources/pgadmin', 'jquery', 'sources/utils',
|
'underscore', 'sources/pgadmin', 'jquery', 'sources/utils', 'sources/gettext',
|
||||||
], function(_, pgAdmin, $, pgadminUtils) {
|
], function(_, pgAdmin, $, pgadminUtils, gettext) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
pgAdmin.Browser = pgAdmin.Browser || {};
|
pgAdmin.Browser = pgAdmin.Browser || {};
|
||||||
@ -274,20 +274,38 @@ define([
|
|||||||
* menu-items.
|
* menu-items.
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 1. jQuery Element on which you may want to created the menus
|
* 1. nodes_obj - Nodes object contains each node object.
|
||||||
* 2. list of menu-items
|
* 2. jQuery Element on which you may want to created the menus
|
||||||
* 3. categories - metadata information about the categories, based on which
|
* 3. list of menu-items
|
||||||
|
* 4. categories - metadata information about the categories, based on which
|
||||||
* the submenu (menu-group) will be created (if any).
|
* the submenu (menu-group) will be created (if any).
|
||||||
* 4. d - Data object for the selected browser tree item.
|
* 5. d - Data object for the selected browser tree item.
|
||||||
* 5. item - The selected browser tree item
|
* 6. item - The selected browser tree item
|
||||||
* 6. menu_items - A empty object on which the context menu for the given
|
* 7. menu_items - A empty object on which the context menu for the given
|
||||||
* list of menu-items.
|
* list of menu-items.
|
||||||
*
|
*
|
||||||
* Returns if any menu generated for the given input.
|
* Returns if any menu generated for the given input.
|
||||||
*/
|
*/
|
||||||
pgAdmin.Browser.MenuCreator = function(
|
pgAdmin.Browser.MenuCreator = function(
|
||||||
$mnu, menus, categories, d, item, menu_items
|
nodes_obj, $mnu, menus, categories, d, item, menu_items
|
||||||
) {
|
) {
|
||||||
|
let showMenu = true;
|
||||||
|
|
||||||
|
/* We check showMenu function is defined by the respective node, if it is
|
||||||
|
* defined then call the function which will return true or false.
|
||||||
|
*/
|
||||||
|
if (d && nodes_obj[d._type] && !_.isUndefined(nodes_obj[d._type].showMenu))
|
||||||
|
showMenu = nodes_obj[d._type].showMenu(d, item);
|
||||||
|
|
||||||
|
if (!showMenu) {
|
||||||
|
menu_items = menu_items || {};
|
||||||
|
menu_items[_.uniqueId('ctx_')+ '1_1_ms'] = {
|
||||||
|
disabled : true,
|
||||||
|
name: gettext('No menu available for this object.'),
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var groups = {
|
var groups = {
|
||||||
'common': [],
|
'common': [],
|
||||||
},
|
},
|
||||||
|
@ -132,6 +132,10 @@ define('pgadmin.browser.node', [
|
|||||||
'action': 'edit',
|
'action': 'edit',
|
||||||
},
|
},
|
||||||
icon: 'fa fa-edit',
|
icon: 'fa fa-edit',
|
||||||
|
enable: _.isFunction(self.canEdit) ?
|
||||||
|
function() {
|
||||||
|
return !!(self.canEdit.apply(self, arguments));
|
||||||
|
} : (!!self.canEdit),
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1233,7 +1237,7 @@ define('pgadmin.browser.node', [
|
|||||||
tooltip: gettext('Edit'),
|
tooltip: gettext('Edit'),
|
||||||
extraClasses: ['btn', 'btn-primary', 'pull-right', 'm-1'],
|
extraClasses: ['btn', 'btn-primary', 'pull-right', 'm-1'],
|
||||||
icon: 'fa fa-sm fa-pencil-alt',
|
icon: 'fa fa-sm fa-pencil-alt',
|
||||||
disabled: !that.canEdit,
|
disabled: _.isFunction(that.canEdit) ? !that.canEdit.apply(that, [d, i]) : !that.canEdit,
|
||||||
register: function(btn) {
|
register: function(btn) {
|
||||||
btn.on('click',() => {
|
btn.on('click',() => {
|
||||||
onEdit();
|
onEdit();
|
||||||
|
Loading…
Reference in New Issue
Block a user