mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Add support for displaying dependency and dependents info.
This commit is contained in:
28
web/pgadmin/misc/depends/__init__.py
Normal file
28
web/pgadmin/misc/depends/__init__.py
Normal file
@@ -0,0 +1,28 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2016, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
"""A blueprint module providing utility functions for the application."""
|
||||
|
||||
from flask import session, url_for
|
||||
from pgadmin.utils import PgAdminModule
|
||||
|
||||
MODULE_NAME = 'depends'
|
||||
|
||||
|
||||
class DependsModule(PgAdminModule):
|
||||
|
||||
def get_own_javascripts(self):
|
||||
return [{
|
||||
'name': 'pgadmin.browser.object_depends',
|
||||
'path': url_for('depends.static', filename='js/depends'),
|
||||
'when': None
|
||||
}]
|
||||
|
||||
# Initialise the module
|
||||
blueprint = DependsModule(MODULE_NAME, __name__, url_prefix='/misc/depends')
|
||||
271
web/pgadmin/misc/depends/static/js/depends.js
Normal file
271
web/pgadmin/misc/depends/static/js/depends.js
Normal file
@@ -0,0 +1,271 @@
|
||||
define(
|
||||
['underscore', 'underscore.string', 'jquery', 'pgadmin.browser'],
|
||||
function(_, S, $, pgBrowser) {
|
||||
|
||||
if (pgBrowser.ShowNodeDepends)
|
||||
return pgBrowser.ShowNodeDepends;
|
||||
|
||||
pgBrowser.ShowNodeDepends = pgBrowser.ShowNodeDepends || {};
|
||||
|
||||
_.extend(pgBrowser.ShowNodeDepends, {
|
||||
init: function() {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.initialized = true;
|
||||
/* Parameter is used to set the proper label of the
|
||||
* backgrid header cell.
|
||||
*/
|
||||
var dependent = true,
|
||||
dependentGrid = null, // Refer to the backgrid object render under Dependents tab
|
||||
dependenciesGrid = null; // Refer to the backgrid object render under Dependencies tab
|
||||
|
||||
_.bindAll(this, 'showDependents', 'dependentsPanelVisibilityChanged',
|
||||
'showDependencies', 'dependenciesPanelVisibilityChanged', '__updateCollection'
|
||||
);
|
||||
|
||||
// Find the panels to render the grid.
|
||||
var dependenciesPanels = this.dependenciesPanels = pgBrowser.docker.findPanels('dependencies');
|
||||
var dependentsPanels = this.dependentsPanels = pgBrowser.docker.findPanels('dependents');
|
||||
|
||||
// We will listened to the visibility change of the Dependencies and Dependents panel
|
||||
pgBrowser.Events.on('pgadmin-browser:panel-dependencies:' + wcDocker.EVENT.VISIBILITY_CHANGED,
|
||||
this.dependenciesPanelVisibilityChanged);
|
||||
pgBrowser.Events.on('pgadmin-browser:panel-dependents:' + wcDocker.EVENT.VISIBILITY_CHANGED,
|
||||
this.dependentsPanelVisibilityChanged);
|
||||
|
||||
// If Dependencies panel exists and is focused then we need to listen the browser tree selection events.
|
||||
if ((dependenciesPanels.length == 1 && dependenciesPanels[0].isVisible()) || dependenciesPanels.length != 1) {
|
||||
pgBrowser.Events.on('pgadmin-browser:tree:selected', this.showDependencies);
|
||||
}
|
||||
|
||||
// If Dependents panel exists and is focused then we need to listen the browser tree selection events.
|
||||
if ((dependentsPanels.length == 1 && dependentsPanels[0].isVisible()) || dependentsPanels.length != 1) {
|
||||
pgBrowser.Events.on('pgadmin-browser:tree:selected', this.showDependents);
|
||||
}
|
||||
|
||||
// Defining Backbone Model for Dependencies and Dependents.
|
||||
var Model = Backbone.Model.extend({
|
||||
defaults: {
|
||||
icon: 'icon-unknown',
|
||||
type: undefined,
|
||||
name: undefined,
|
||||
/* field contains 'Database Name' for 'Tablespace and Role node',
|
||||
* for other node it contains 'Restriction'.
|
||||
*/
|
||||
field: undefined
|
||||
},
|
||||
// This function is used to fetch/set the icon for the type(Function, Role, Database, ....)
|
||||
parse: function(res) {
|
||||
var node = pgBrowser.Nodes[res.type];
|
||||
res.icon = node ? (_.isFunction(node['node_image']) ?
|
||||
(node['node_image']).apply(node, [null, null]) :
|
||||
(node['node_image'] || ('icon-' + res.type))) :
|
||||
('icon-' + res.type);
|
||||
res.type = S.capitalize(res.type, true);
|
||||
return res;
|
||||
}
|
||||
});
|
||||
|
||||
// Defining Backbone Collection for Dependents.
|
||||
this.dependentCollection = new (Backbone.Collection.extend({
|
||||
model: Model
|
||||
}))(null);
|
||||
|
||||
// Defining Backbone Collection for Dependencies.
|
||||
this.dependenciesCollection = new (Backbone.Collection.extend({
|
||||
model: Model
|
||||
}))(null);
|
||||
|
||||
var self = this;
|
||||
|
||||
/* Function is used to create and render backgrid with
|
||||
* empty collection. We just want to add backgrid into the
|
||||
* panel only once.
|
||||
*/
|
||||
var appendGridToPanel = function(collection, panel, is_dependent) {
|
||||
var $container = panel[0].layout().$table.find('.pg-panel-content'),
|
||||
$gridContainer = $container.find('.pg-panel-depends-container'),
|
||||
grid = new Backgrid.Grid({
|
||||
columns: [
|
||||
{
|
||||
name : 'type',
|
||||
label: 'Type',
|
||||
// Extend it to render the icon as per the type.
|
||||
cell: Backgrid.Cell.extend({
|
||||
render: function() {
|
||||
Backgrid.Cell.prototype.render.apply(this, arguments);
|
||||
this.$el.addClass(this.model.get('icon')).css({"padding-left": "18px"});
|
||||
return this;
|
||||
}
|
||||
}),
|
||||
editable: false
|
||||
},
|
||||
{
|
||||
name : 'name',
|
||||
label: 'Name',
|
||||
cell: 'string',
|
||||
editable: false
|
||||
},
|
||||
{
|
||||
name : 'field',
|
||||
label: '', // label kept blank, it will change dynamically
|
||||
cell: 'string',
|
||||
editable: false
|
||||
}
|
||||
],
|
||||
|
||||
collection: collection,
|
||||
className: "backgrid table-bordered"
|
||||
});
|
||||
|
||||
// Condition is used to save grid object to change the label of the header.
|
||||
if (is_dependent)
|
||||
self.dependentGrid = grid;
|
||||
else
|
||||
self.dependenciesGrid = grid;
|
||||
|
||||
$gridContainer.append(grid.render().el);
|
||||
};
|
||||
|
||||
appendGridToPanel(this.dependentCollection, this.dependentsPanels, true);
|
||||
appendGridToPanel(this.dependenciesCollection, this.dependenciesPanels, false);
|
||||
},
|
||||
|
||||
// Fetch the actual data and update the collection
|
||||
__updateCollection: function(collection, panel, url, messages, node) {
|
||||
var msg = messages[0],
|
||||
$container = panel[0].layout().$table.find('.pg-panel-content'),
|
||||
$msgContainer = $container.find('.pg-panel-depends-message'),
|
||||
$gridContainer = $container.find('.pg-panel-depends-container');
|
||||
|
||||
// Hide the grid container and show the default message container
|
||||
if (!$gridContainer.hasClass('hidden'))
|
||||
$gridContainer.addClass('hidden');
|
||||
$msgContainer.removeClass('hidden');
|
||||
|
||||
if (node) {
|
||||
msg = messages[1];
|
||||
/* We fetch the Dependencies and Dependents tab only for
|
||||
* those node who set the parameter hasDepends to true.
|
||||
*/
|
||||
if (node.hasDepends) {
|
||||
/* Set the message because ajax request may take time to
|
||||
* fetch the information from the server.
|
||||
*/
|
||||
msg = messages[2];
|
||||
$msgContainer.text(msg);
|
||||
|
||||
/* Updating the label for the 'field' type of the backbone model.
|
||||
* Label should be "Database" if the node type is tablespace or role
|
||||
* and dependent tab is selected. For other nodes and dependencies tab
|
||||
* it should be 'Restriction'.
|
||||
*/
|
||||
if (this.dependent && (node.type == 'tablespace' || node.type == 'role'))
|
||||
this.dependentGrid.columns.models[2].set({'label': 'Database'});
|
||||
else {
|
||||
this.dependenciesGrid.columns.models[2].set({'label': 'Restriction'});
|
||||
this.dependentGrid.columns.models[2].set({'label': 'Restriction'});
|
||||
}
|
||||
|
||||
// Set the url, fetch the data and update the collection
|
||||
collection.url = url;
|
||||
collection.fetch({
|
||||
reset: true,
|
||||
success: function(res) {
|
||||
|
||||
// In case of success hide the message container and show the grid container.
|
||||
$gridContainer.removeClass('hidden');
|
||||
$msgContainer.addClass('hidden');
|
||||
},
|
||||
error: function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (msg != '') {
|
||||
$msgContainer.text(msg);
|
||||
}
|
||||
},
|
||||
showDependents: function(item, data, node) {
|
||||
/**
|
||||
* We can't start fetching the Dependents immediately, it is possible the user
|
||||
* is just using the keyboard to select the node, and just traversing
|
||||
* through. We will wait for some time before fetching the Dependents
|
||||
**/
|
||||
var self = this;
|
||||
self.dependent = true;
|
||||
if (self.timeout) {
|
||||
clearTimeout(self.timeout);
|
||||
}
|
||||
self.timeout = setTimeout(
|
||||
self.__updateCollection(
|
||||
self.dependentCollection,
|
||||
self.dependentsPanels,
|
||||
node.generate_url(item, 'dependent', data, true),
|
||||
['-- No object selected!', '-- No dependent information is available for the current selection.',
|
||||
'-- Please wait while we fetch the dependent information from the server.'],
|
||||
node
|
||||
), 400
|
||||
);
|
||||
},
|
||||
dependentsPanelVisibilityChanged: function(panel) {
|
||||
if (panel.isVisible()) {
|
||||
var t = pgBrowser.tree,
|
||||
i = t.selected(),
|
||||
d = i && t.itemData(i),
|
||||
n = i && d && pgBrowser.Nodes[d._type];
|
||||
|
||||
pgBrowser.ShowNodeDepends.showDependents.apply(pgBrowser.ShowNodeDepends, [i, d, n]);
|
||||
|
||||
// We will start listening the tree selection event.
|
||||
pgBrowser.Events.on('pgadmin-browser:tree:selected', pgBrowser.ShowNodeDepends.showDependents);
|
||||
} else {
|
||||
|
||||
// We don't need to listen the tree item selection event.
|
||||
pgBrowser.Events.off('pgadmin-browser:tree:selected', pgBrowser.ShowNodeDepends.showDependents);
|
||||
}
|
||||
},
|
||||
showDependencies: function(item, data, node) {
|
||||
/**
|
||||
* We can't start fetching the Dependencies immediately, it is possible the user
|
||||
* is just using the keyboard to select the node, and just traversing
|
||||
* through. We will wait for some time before fetching the Dependencies
|
||||
**/
|
||||
var self = this;
|
||||
self.dependent = false;
|
||||
if (self.timeout) {
|
||||
clearTimeout(self.timeout);
|
||||
}
|
||||
self.timeout = setTimeout(
|
||||
self.__updateCollection(
|
||||
self.dependenciesCollection,
|
||||
self.dependenciesPanels,
|
||||
node.generate_url(item, 'dependency', data, true),
|
||||
['-- No object selected!', '-- No dependency information is available for the current selection.',
|
||||
'-- Please wait while we fetch the dependency information from the server.'],
|
||||
node
|
||||
), 400
|
||||
);
|
||||
},
|
||||
dependenciesPanelVisibilityChanged: function(panel) {
|
||||
if (panel.isVisible()) {
|
||||
var t = pgBrowser.tree,
|
||||
i = t.selected(),
|
||||
d = i && t.itemData(i),
|
||||
n = i && d && pgBrowser.Nodes[d._type];
|
||||
|
||||
pgBrowser.ShowNodeDepends.showDependencies.apply(pgBrowser.ShowNodeDepends, [i, d, n]);
|
||||
|
||||
// We will start listening the tree selection event.
|
||||
pgBrowser.Events.on('pgadmin-browser:tree:selected', pgBrowser.ShowNodeDepends.showDependencies);
|
||||
} else {
|
||||
// We don't need to listen the tree item selection event.
|
||||
pgBrowser.Events.off('pgadmin-browser:tree:selected', pgBrowser.ShowNodeDepends.showDependencies);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return pgBrowser.ShowNodeDepends;
|
||||
});
|
||||
Reference in New Issue
Block a user