From fe834d1ed2147243b7946488f8fc6ce0fd6a754f Mon Sep 17 00:00:00 2001 From: Dave Page Date: Tue, 10 Mar 2015 13:09:11 +0000 Subject: [PATCH] Re-organise node structure and loading to make things somewhat more simple. This also adds the ability to display servers on the treeview. --- runtime/pgAdmin4.cpp | 4 +- web/pgAdmin4.py | 5 +- web/pgadmin/__init__.py | 8 +- web/pgadmin/browser/__init__.py | 5 +- web/pgadmin/browser/hooks.py | 38 +----- .../browser/nodes/server_groups/__init__.py | 0 .../__init__.py} | 9 +- .../{nodes => }/server_groups/hooks.py | 20 ++- .../servers/__init__.py} | 11 +- .../browser/server_groups/servers/hooks.py | 61 +++++++++ .../servers/static/img/server.png | Bin 0 -> 553 bytes .../servers/templates/servers/servers.js | 82 ++++++++++++ .../browser/server_groups/servers/views.py | 117 ++++++++++++++++++ .../server_groups/static/img/server-group.png | Bin .../templates/server_groups/server_groups.js | 0 .../{nodes => }/server_groups/views.py | 32 +++-- .../browser/templates/browser/js/browser.js | 11 +- web/pgadmin/browser/utils.py | 53 ++++++++ web/pgadmin/browser/views.py | 18 +-- .../{browser/nodes => misc}/__init__.py | 0 web/pgadmin/{utils => misc}/views.py | 4 +- web/pgadmin/settings/views.py | 2 +- web/{ => pgadmin}/utils/ajax.py | 0 web/utils/__init__.py | 0 24 files changed, 400 insertions(+), 80 deletions(-) delete mode 100644 web/pgadmin/browser/nodes/server_groups/__init__.py rename web/pgadmin/browser/{nodes/CollectionNode.py => server_groups/__init__.py} (67%) rename web/pgadmin/browser/{nodes => }/server_groups/hooks.py (67%) rename web/pgadmin/browser/{nodes/ObjectNode.py => server_groups/servers/__init__.py} (70%) create mode 100644 web/pgadmin/browser/server_groups/servers/hooks.py create mode 100644 web/pgadmin/browser/server_groups/servers/static/img/server.png create mode 100644 web/pgadmin/browser/server_groups/servers/templates/servers/servers.js create mode 100644 web/pgadmin/browser/server_groups/servers/views.py rename web/pgadmin/browser/{nodes => }/server_groups/static/img/server-group.png (100%) rename web/pgadmin/browser/{nodes => }/server_groups/templates/server_groups/server_groups.js (100%) rename web/pgadmin/browser/{nodes => }/server_groups/views.py (83%) create mode 100644 web/pgadmin/browser/utils.py rename web/pgadmin/{browser/nodes => misc}/__init__.py (100%) rename web/pgadmin/{utils => misc}/views.py (91%) rename web/{ => pgadmin}/utils/ajax.py (100%) delete mode 100644 web/utils/__init__.py diff --git a/runtime/pgAdmin4.cpp b/runtime/pgAdmin4.cpp index 168451c53..1242ea0dc 100644 --- a/runtime/pgAdmin4.cpp +++ b/runtime/pgAdmin4.cpp @@ -84,7 +84,7 @@ int main(int argc, char * argv[]) } // Generate the app server URL - QString appServerUrl = QString("http://localhost:%1/utils/test").arg(port); + QString appServerUrl = QString("http://localhost:%1/").arg(port); // Now the server should be up, we'll attempt to connect and get a response. // We'll retry in a loop a few time before aborting if necessary. The browser @@ -128,7 +128,7 @@ bool PingServer(QUrl url) QNetworkReply *reply; QVariant redirectUrl; - url.setPath("/utils/ping"); + url.setPath("/ping"); do { diff --git a/web/pgAdmin4.py b/web/pgAdmin4.py index f3ad36ec4..63710852e 100644 --- a/web/pgAdmin4.py +++ b/web/pgAdmin4.py @@ -15,7 +15,9 @@ import os, sys # We need to include the root directory in sys.path to ensure that we can # find everything we need when running in the standalone runtime. -sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) +root = os.path.dirname(os.path.realpath(__file__)) +if sys.path[0] != root: + sys.path.insert(0, root) import config from pgadmin import create_app @@ -47,7 +49,6 @@ if not os.path.isfile(config.SQLITE_PATH): # Create the app! app = create_app() -app.logger.debug("Python syspath: %s", sys.path) # Start the web server. The port number should have already been set by the # runtime if we're running in desktop mode, otherwise we'll just use the diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py index b417bf3c9..ee8bc1200 100644 --- a/web/pgadmin/__init__.py +++ b/web/pgadmin/__init__.py @@ -19,7 +19,7 @@ from flask_mail import Mail from htmlmin.minify import html_minify from settings.settings_model import db, Role, User -import inspect, imp, logging, os +import inspect, imp, logging, os, sys # Configuration settings import config @@ -66,7 +66,8 @@ def create_app(app_name=config.APP_NAME): app.logger.info('################################################################################') app.logger.info('Starting %s v%s...', config.APP_NAME, config.APP_VERSION) app.logger.info('################################################################################') - + app.logger.debug("Python syspath: %s", sys.path) + ########################################################################## # Setup i18n ########################################################################## @@ -117,6 +118,9 @@ def create_app(app_name=config.APP_NAME): app.logger.info('Skipping blacklisted module: %s' % f) continue + # Construct the "real" module name + f = 'pgadmin.' + f + # Looks like a module, so import it, and register the blueprint if present # We rely on the ordering of syspath to ensure we actually get the right # module here. Note that we also try to load the 'hooks' module for diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py index f29c21290..5442b7dc2 100644 --- a/web/pgadmin/browser/__init__.py +++ b/web/pgadmin/browser/__init__.py @@ -7,5 +7,6 @@ # ########################################################################## -# Define the global node list -nodes = [ ] \ No newline at end of file +# Define the node lists +all_nodes = [ ] +sub_nodes = [ ] \ No newline at end of file diff --git a/web/pgadmin/browser/hooks.py b/web/pgadmin/browser/hooks.py index c6642b461..c38279566 100644 --- a/web/pgadmin/browser/hooks.py +++ b/web/pgadmin/browser/hooks.py @@ -12,40 +12,10 @@ import os, sys import config -from . import nodes +from pgadmin.browser.utils import register_modules +from pgadmin.browser import all_nodes +from . import sub_nodes def register_submodules(app): """Register any child node blueprints""" - path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'nodes') - sys.path.insert(0, path) - files = os.listdir(path) - - for f in files: - d = os.path.join(path, f) - if os.path.isdir(d) and os.path.isfile(os.path.join(d, '__init__.py')): - - if f in config.NODE_BLACKLIST: - app.logger.info('Skipping blacklisted node: %s' % f) - continue - - # Looks like a node, so import it, and register the blueprint if present - # We rely on the ordering of syspath to ensure we actually get the right - # module here. - app.logger.info('Examining potential node: %s' % d) - node = __import__(f, globals(), locals(), ['hooks', 'views'], -1) - - # Add the node to the global module list - nodes.append(node) - - # Register the blueprint if present - if 'views' in dir(node) and 'blueprint' in dir(node.views): - app.logger.info('Registering blueprint node: %s' % f) - app.register_blueprint(node.views.blueprint) - app.logger.debug(' - root_path: %s' % node.views.blueprint.root_path) - app.logger.debug(' - static_folder: %s' % node.views.blueprint.static_folder) - app.logger.debug(' - template_folder: %s' % node.views.blueprint.template_folder) - - # Register any sub-modules - if 'hooks' in dir(node) and 'register_submodules' in dir(node.hooks): - app.logger.info('Registering sub-modules in %s' % f) - node.hooks.register_submodules(app) \ No newline at end of file + register_modules(app, __file__, all_nodes, sub_nodes, 'pgadmin.browser') diff --git a/web/pgadmin/browser/nodes/server_groups/__init__.py b/web/pgadmin/browser/nodes/server_groups/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/web/pgadmin/browser/nodes/CollectionNode.py b/web/pgadmin/browser/server_groups/__init__.py similarity index 67% rename from web/pgadmin/browser/nodes/CollectionNode.py rename to web/pgadmin/browser/server_groups/__init__.py index ae0cc7c9c..95535f709 100644 --- a/web/pgadmin/browser/nodes/CollectionNode.py +++ b/web/pgadmin/browser/server_groups/__init__.py @@ -7,8 +7,9 @@ # ########################################################################## -"""Base class for Collection Nodes on the browser treeview""" +# Node meta data +NODE_TYPE = 'server-group' +NODE_PATH = '/browser/nodes/' + NODE_TYPE -def get_name(): - """Returns the display name of the collection""" - return "" \ No newline at end of file +# Define the child node list +sub_nodes = [ ] \ No newline at end of file diff --git a/web/pgadmin/browser/nodes/server_groups/hooks.py b/web/pgadmin/browser/server_groups/hooks.py similarity index 67% rename from web/pgadmin/browser/nodes/server_groups/hooks.py rename to web/pgadmin/browser/server_groups/hooks.py index 3316f63d9..4f011fe95 100644 --- a/web/pgadmin/browser/nodes/server_groups/hooks.py +++ b/web/pgadmin/browser/server_groups/hooks.py @@ -13,15 +13,23 @@ from flask import render_template, url_for from flask.ext.babel import gettext from flask.ext.security import current_user +from pgadmin.browser.utils import register_modules from pgadmin.settings.settings_model import db, ServerGroup +from pgadmin.browser import all_nodes +from . import NODE_TYPE, sub_nodes + +def register_submodules(app): + """Register any child node blueprints""" + register_modules(app, __file__, all_nodes, sub_nodes, 'pgadmin.browser.server_groups') + def get_nodes(): """Return a JSON document listing the server groups for the user""" groups = ServerGroup.query.filter_by(user_id=current_user.id) value = '' for group in groups: - value += '{"id":%d,"label":"%s","icon":"icon-server-group","inode":true},' % (group.id, group.name) + value += '{"id":"%s/%d","label":"%s","icon":"icon-%s","inode":true,"_type":"%s"},' % (NODE_TYPE, group.id, group.name, NODE_TYPE, NODE_TYPE) value = value[:-1] return value @@ -38,10 +46,10 @@ def get_file_menu_items(): def get_context_menu_items(): - """Return a (set) of dicts of content menu items with name, label, priority and JS""" + """Return a (set) of dicts of content menu items with name, node type, label, priority and JS""" return [ - {'name': 'delete', 'label': gettext('Delete server group'), 'priority': 100, 'onclick': 'delete_server_group(item);'}, - {'name': 'rename', 'label': gettext('Rename server group...'), 'priority': 200, 'onclick': 'rename_server_group(item);'} + {'name': 'delete_server_group', 'type': NODE_TYPE, 'label': gettext('Delete server group'), 'priority': 10, 'onclick': 'delete_server_group(item);'}, + {'name': 'rename_server_group', 'type': NODE_TYPE, 'label': gettext('Rename server group...'), 'priority': 20, 'onclick': 'rename_server_group(item);'} ] @@ -54,7 +62,7 @@ def get_css_snippets(): """Return the CSS needed to display the treeview node image.""" css = ".icon-server-group {\n" css += " background: url('%s') 0 0 no-repeat !important;\n" % \ - url_for('NODE-server-group.static', filename='img/server-group.png') - css += "{" + url_for('NODE-%s.static' % NODE_TYPE, filename='img/server-group.png') + css += "}\n" return css diff --git a/web/pgadmin/browser/nodes/ObjectNode.py b/web/pgadmin/browser/server_groups/servers/__init__.py similarity index 70% rename from web/pgadmin/browser/nodes/ObjectNode.py rename to web/pgadmin/browser/server_groups/servers/__init__.py index 0212fee7b..a9e5e3c5b 100644 --- a/web/pgadmin/browser/nodes/ObjectNode.py +++ b/web/pgadmin/browser/server_groups/servers/__init__.py @@ -7,9 +7,10 @@ # ########################################################################## -"""Base class for Object Nodes on the browser treeview""" +# Node meta data +NODE_TYPE = 'server' +NODE_PATH = '/browser/nodes/' + NODE_TYPE + +# Define the child node list +sub_nodes = [ ] -def get_name(): - """Returns the object's name""" - return "" - diff --git a/web/pgadmin/browser/server_groups/servers/hooks.py b/web/pgadmin/browser/server_groups/servers/hooks.py new file mode 100644 index 000000000..5809af52d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/hooks.py @@ -0,0 +1,61 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2015, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Integration hooks for servers.""" + +from flask import render_template, url_for +from flask.ext.babel import gettext +from flask.ext.security import current_user + +from pgadmin.settings.settings_model import db, Server +from . import NODE_TYPE + +def get_nodes(server_group): + """Return a JSON document listing the server groups for the user""" + servers = Server.query.filter_by(user_id=current_user.id, servergroup_id=server_group) + + value = '' + for server in servers: + value += '{"id":"%s/%d","label":"%s","icon":"icon-%s","inode":true,"_type":"%s"},' % (NODE_TYPE, server.id, server.name, NODE_TYPE, NODE_TYPE) + value = value[:-1] + + return value + + +def get_file_menu_items(): + """Return a (set) of dicts of file menu items, with name, priority, URL, + target and onclick code.""" + return [ + {'name': 'mnu_add_server', 'label': gettext('Add a server...'), 'priority': 50, 'url': '#', 'onclick': 'add_server()'}, + {'name': 'mnu_delete_server', 'label': gettext('Delete server'), 'priority': 60, 'url': '#', 'onclick': 'delete_server()'}, + {'name': 'mnu_rename_server', 'label': gettext('Rename server...'), 'priority': 70, 'url': '#', 'onclick': 'rename_server()'} + ] + + +def get_context_menu_items(): + """Return a (set) of dicts of content menu items with name, node type, label, priority and JS""" + return [ + {'name': 'delete_server', 'type': NODE_TYPE, 'label': gettext('Delete server'), 'priority': 50, 'onclick': 'delete_server(item);'}, + {'name': 'rename_server', 'type': NODE_TYPE, 'label': gettext('Rename server...'), 'priority': 60, 'onclick': 'rename_server(item);'} + ] + + +def get_script_snippets(): + """Return the script snippets needed to handle treeview node operations.""" + return render_template('servers/servers.js') + + +def get_css_snippets(): + """Return the CSS needed to display the treeview node image.""" + css = ".icon-server {\n" + css += " background: url('%s') 0 0 no-repeat !important;\n" % \ + url_for('NODE-%s.static' % NODE_TYPE, filename='img/server.png') + css += "}\n" + + return css diff --git a/web/pgadmin/browser/server_groups/servers/static/img/server.png b/web/pgadmin/browser/server_groups/servers/static/img/server.png new file mode 100644 index 0000000000000000000000000000000000000000..2ab73d5654a26b4d5acc3dc50dc659d4bdfee42f GIT binary patch literal 553 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMfr2wB0S0LS-Q!}lx|JD8HkFMUk zdGhLoy{C_DJg|S+&d#EynQfDItl0eW{?i*Lubkg|YX6EIb6cj}zIfx+{b!G^-aWtX z)Q0IRFC0Dn>EoxLKYo7w`03ZrUmxGTe{%c&hj;J4ef{>}^7SLDw{Dm)d&|^?N7in8 z|L)!QuiuWW-m+=Jyu)j^e*60M;guUl*6n!z?)~9an>S6Edt~kQ7r&y=mx z7BB3ZcJ|DfiKPu&rY$_YcH5do%RjvPuxrDX>M2XSXRPR1z2o7Pn+toUL@nAPf9rVA zlFjMOlcJYy+i~mtG@!2-OM?7@862M7NCR>>3p^r=fwTu0yPeFo12XzNT^vIsE+;22 zFu8FgG%%~BiG`V!@%c&2@1EV>I=z2xd;_=E0Syh6GunsFDRNytqM@dzsHv!`+bl3) z>g4c%kRUgX6)R4yUa6g_u=2u{px}^8ZX7RGEXtfX_41{w!I#`QBvwdCy_B4-kZE`| z$iR4e19wE!%Ba;hZ`@MMoVdBXprpv{;-c4&x&j#49rzfc()q>Pd9o)1U8Y*%8c~vx zSdwa$T$Bo=7>o=I4Rj5SbPWtcj0~(yjIB&ewGB+I3=HPI(_4k2AvZrIGp!P$!N3x% c0jS!<%D@bw;neidH9!pvp00i_>zopr0E;gKO#lD@ literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js b/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js new file mode 100644 index 000000000..78f2dca14 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js @@ -0,0 +1,82 @@ +// Add a server +function add_server() { + var alert = alertify.prompt( + '{{ _('Add a server') }}', + '{{ _('Enter a name for the new server') }}', + '', + function(evt, value) { + $.post("{{ url_for('NODE-server.add') }}", { name: value }) + .done(function(data) { + if (data.success == 0) { + report_error(data.errormsg, data.info); + } else { + var item = { + id: data.data.id, + label: data.data.name, + inode: true, + open: false, + icon: 'icon-server' + } + + tree.append(null, { + itemData: item + }); + + } + } + ) + }, + null + ); + alert.show(); +} + +// Delete a server +function delete_server(item) { + alertify.confirm( + '{{ _('Delete server?') }}', + '{{ _('Are you sure you wish to delete the server "{0}"?') }}'.replace('{0}', tree.getLabel(item)), + function() { + var id = tree.getId(item) + $.post("{{ url_for('NODE-server.delete') }}", { id: id }) + .done(function(data) { + if (data.success == 0) { + report_error(data.errormsg, data.info); + } else { + var next = tree.next(item); + var prev = tree.prev(item); + tree.remove(item); + if (next.length) { + tree.select(next); + } else if (prev.length) { + tree.select(prev); + } + } + } + ) + }, + null + ) +} + +// Rename a server +function rename_server(item) { + alertify.prompt( + '{{ _('Rename server') }}', + '{{ _('Enter a new name for the server') }}', + tree.getLabel(item), + function(evt, value) { + var id = tree.getId(item) + $.post("{{ url_for('NODE-server.rename') }}", { id: id, name: value }) + .done(function(data) { + if (data.success == 0) { + report_error(data.errormsg, data.info); + } else { + tree.setLabel(item, { label: value }); + } + } + ) + }, + null + ) +} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/views.py b/web/pgadmin/browser/server_groups/servers/views.py new file mode 100644 index 000000000..318b365e5 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/views.py @@ -0,0 +1,117 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2015, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Defines views for management of servers""" + +from flask import Blueprint, Response, current_app, request +from flask.ext.babel import gettext +from flask.ext.security import current_user, login_required + +from . import NODE_TYPE, NODE_PATH +from pgadmin.utils.ajax import make_json_response +from pgadmin.settings.settings_model import db, ServerGroup +import config + +# Initialise the module +blueprint = Blueprint("NODE-" + NODE_TYPE, __name__, static_folder='static', static_url_path='', template_folder='templates', url_prefix=NODE_PATH) + +@blueprint.route('/add/', methods=['POST']) +@login_required +def add(): + """Add a server node to the settings database""" + success = 1 + errormsg = '' + data = { } + + if request.form['name'] != '': + server = Server(user_id=current_user.id, name=request.form['name']) + + try: + db.session.add(server) + db.session.commit() + except Exception as e: + success = 0 + errormsg = e.message + + else: + success = 0 + errormsg = gettext('No server name was specified') + + if success == 1: + data['id'] = server.id + data['name'] = server.name + + return make_json_response(success=success, + errormsg=errormsg, + info=traceback.format_exc(), + result=request.form, + data=data) + +@blueprint.route('/delete/', methods=['POST']) +@login_required +def delete(): + """Delete a server node in the settings database""" + success = 1 + errormsg = '' + + if request.form['id'] != '': + # There can be only one record at most + servergroup = Server.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first() + + if server is None: + success = 0 + errormsg = gettext('The specified server could not be found.') + else: + try: + db.session.delete(server) + db.session.commit() + except Exception as e: + success = 0 + errormsg = e.message + + else: + success = 0 + errormsg = gettext('No server was specified.') + + return make_json_response(success=success, + errormsg=errormsg, + info=traceback.format_exc(), + result=request.form) + +@blueprint.route('/rename/', methods=['POST']) +@login_required +def rename(): + """Rename a server node in the settings database""" + success = 1 + errormsg = '' + + if request.form['id'] != '': + # There can be only one record at most + servergroup = Server.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first() + + if server is None: + success = 0 + errormsg = gettext('The specified server could not be found.') + else: + try: + server.name = request.form['name'] + db.session.commit() + except Exception as e: + success = 0 + errormsg = e.message + + else: + success = 0 + errormsg = gettext('No server was specified.') + + return make_json_response(success=success, + errormsg=errormsg, + info=traceback.format_exc(), + result=request.form) + \ No newline at end of file diff --git a/web/pgadmin/browser/nodes/server_groups/static/img/server-group.png b/web/pgadmin/browser/server_groups/static/img/server-group.png similarity index 100% rename from web/pgadmin/browser/nodes/server_groups/static/img/server-group.png rename to web/pgadmin/browser/server_groups/static/img/server-group.png diff --git a/web/pgadmin/browser/nodes/server_groups/templates/server_groups/server_groups.js b/web/pgadmin/browser/server_groups/templates/server_groups/server_groups.js similarity index 100% rename from web/pgadmin/browser/nodes/server_groups/templates/server_groups/server_groups.js rename to web/pgadmin/browser/server_groups/templates/server_groups/server_groups.js diff --git a/web/pgadmin/browser/nodes/server_groups/views.py b/web/pgadmin/browser/server_groups/views.py similarity index 83% rename from web/pgadmin/browser/nodes/server_groups/views.py rename to web/pgadmin/browser/server_groups/views.py index 531700118..6f410a21f 100644 --- a/web/pgadmin/browser/nodes/server_groups/views.py +++ b/web/pgadmin/browser/server_groups/views.py @@ -9,22 +9,40 @@ """Defines views for management of server groups""" -NODE_NAME = 'server-group' - -NODE_PATH = '/browser/' + NODE_NAME - -import traceback from flask import Blueprint, Response, current_app, request from flask.ext.babel import gettext from flask.ext.security import current_user, login_required -from utils.ajax import make_json_response +from . import NODE_TYPE, NODE_PATH, sub_nodes +from pgadmin.utils.ajax import make_json_response from pgadmin.settings.settings_model import db, ServerGroup import config # Initialise the module -blueprint = Blueprint("NODE-" + NODE_NAME, __name__, static_folder='static', static_url_path='', template_folder='templates', url_prefix=NODE_PATH) +blueprint = Blueprint("NODE-" + NODE_TYPE, __name__, static_folder='static', static_url_path='', template_folder='templates', url_prefix=NODE_PATH) +@blueprint.route("/") +@login_required +def get_nodes(server_group): + """Build a list of treeview nodes from the child nodes.""" + value = '[' + + for node in sub_nodes: + if 'hooks' in dir(node) and 'get_nodes' in dir(node.hooks): + value += node.hooks.get_nodes(server_group) + ',' + + if value[-1:] == ',': + value = value[:-1] + + value += ']' + + resp = Response(response=value, + status=200, + mimetype="text/json") + + return resp + + @blueprint.route('/add/', methods=['POST']) @login_required def add(): diff --git a/web/pgadmin/browser/templates/browser/js/browser.js b/web/pgadmin/browser/templates/browser/js/browser.js index f597d77e3..1dab6f82d 100644 --- a/web/pgadmin/browser/templates/browser/js/browser.js +++ b/web/pgadmin/browser/templates/browser/js/browser.js @@ -170,10 +170,12 @@ ALTER TABLE tickets_detail \n\ }; {% if context_items is defined %} {% for context_item in context_items %} - menu['{{ context_item.name }}'] = { - name: '{{ context_item.label }}', - callback: function() { {{ context_item.onclick }} } - }; + if (tree.itemData(item)._type == '{{ context_item.type }}') { + menu['{{ context_item.name }}'] = { + name: '{{ context_item.label }}', + callback: function() { {{ context_item.onclick }} } + }; + } {% endfor %}{% endif %} return { autoHide: true, @@ -184,6 +186,7 @@ ALTER TABLE tickets_detail \n\ }); }); + function report_error(message, info) { text = '
\ diff --git a/web/pgadmin/browser/utils.py b/web/pgadmin/browser/utils.py new file mode 100644 index 000000000..4cf955f41 --- /dev/null +++ b/web/pgadmin/browser/utils.py @@ -0,0 +1,53 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2015, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Browser helper utilities""" + +import os, sys +import config + +def register_modules(app, file, all_nodes, sub_nodes, prefix): + """Register any child node blueprints for the specified file""" + path = os.path.dirname(os.path.realpath(file)) + files = os.listdir(path) + + for f in files: + d = os.path.join(path, f) + if os.path.isdir(d) and os.path.isfile(os.path.join(d, '__init__.py')): + + if f in config.NODE_BLACKLIST: + app.logger.info('Skipping blacklisted node: %s' % f) + continue + + # Construct the 'real' module name + if prefix != '': + f = prefix + '.' + f + + # Looks like a node, so import it, and register the blueprint if present + # We rely on the ordering of syspath to ensure we actually get the right + # module here. + app.logger.info('Examining potential node: %s' % d) + node = __import__(f, globals(), locals(), ['hooks', 'views'], -1) + + # Add the node to the node lists + all_nodes.append(node) + sub_nodes.append(node) + + # Register the blueprint if present + if 'views' in dir(node) and 'blueprint' in dir(node.views): + app.logger.info('Registering blueprint node: %s' % f) + app.register_blueprint(node.views.blueprint) + app.logger.debug(' - root_path: %s' % node.views.blueprint.root_path) + app.logger.debug(' - static_folder: %s' % node.views.blueprint.static_folder) + app.logger.debug(' - template_folder: %s' % node.views.blueprint.template_folder) + + # Register any sub-modules + if 'hooks' in dir(node) and 'register_submodules' in dir(node.hooks): + app.logger.info('Registering sub-modules in %s' % f) + node.hooks.register_submodules(app) \ No newline at end of file diff --git a/web/pgadmin/browser/views.py b/web/pgadmin/browser/views.py index 54103a9b4..a4b981b27 100644 --- a/web/pgadmin/browser/views.py +++ b/web/pgadmin/browser/views.py @@ -16,10 +16,12 @@ from flask.ext.security import login_required from flask.ext.login import current_user from inspect import getmoduleinfo, getmembers -from . import nodes +from . import sub_nodes +from pgadmin.browser import all_nodes from pgadmin import modules from pgadmin.settings import get_setting + import config # Initialise the module @@ -47,7 +49,7 @@ def index(): stylesheets = [ ] scripts = [ ] - modules_and_nodes = modules + nodes + modules_and_nodes = modules + all_nodes # Add browser stylesheets stylesheets.append(url_for('static', filename='css/codemirror/codemirror.css')) @@ -129,15 +131,13 @@ def index(): def browser_js(): """Render and return JS snippets from the nodes and modules.""" snippets = '' - modules_and_nodes = modules + nodes + modules_and_nodes = modules + all_nodes # Load the core browser code first # Get the context menu items context_items = [ ] panel_items = [ ] - - modules_and_nodes = modules + nodes for module in modules_and_nodes: # Get any context menu items @@ -174,7 +174,7 @@ def browser_js(): def browser_css(): """Render and return CSS snippets from the nodes and modules.""" snippets = '' - modules_and_nodes = modules + nodes + modules_and_nodes = modules + all_nodes for module in modules_and_nodes: if 'hooks' in dir(module) and 'get_css_snippets' in dir(module.hooks): @@ -187,13 +187,13 @@ def browser_css(): return resp -@blueprint.route("/root-nodes.json") +@blueprint.route("/nodes/") @login_required def get_nodes(): - """Build a list of treeview nodes from the child modules.""" + """Build a list of treeview nodes from the child nodes.""" value = '[' - for node in nodes: + for node in sub_nodes: if 'hooks' in dir(node) and 'get_nodes' in dir(node.hooks): value += node.hooks.get_nodes() + ',' diff --git a/web/pgadmin/browser/nodes/__init__.py b/web/pgadmin/misc/__init__.py similarity index 100% rename from web/pgadmin/browser/nodes/__init__.py rename to web/pgadmin/misc/__init__.py diff --git a/web/pgadmin/utils/views.py b/web/pgadmin/misc/views.py similarity index 91% rename from web/pgadmin/utils/views.py rename to web/pgadmin/misc/views.py index b0937313f..9b166b253 100644 --- a/web/pgadmin/utils/views.py +++ b/web/pgadmin/misc/views.py @@ -8,14 +8,14 @@ ########################################################################## """A blueprint module providing utility functions for the application.""" -MODULE_NAME = 'utils' +MODULE_NAME = 'misc' import config from flask import Blueprint, render_template from flask.ext.security import login_required # Initialise the module -blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static', template_folder='templates', url_prefix='/' + MODULE_NAME) +blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static', template_folder='templates', url_prefix='') ########################################################################## # A special URL used to "ping" the server diff --git a/web/pgadmin/settings/views.py b/web/pgadmin/settings/views.py index 7aaebda36..67e0d5ae2 100644 --- a/web/pgadmin/settings/views.py +++ b/web/pgadmin/settings/views.py @@ -15,7 +15,7 @@ from flask import Blueprint, Response, abort, request, render_template from flask.ext.security import login_required import config -from utils.ajax import make_json_response +from pgadmin.utils.ajax import make_json_response from . import get_setting, store_setting # Initialise the module diff --git a/web/utils/ajax.py b/web/pgadmin/utils/ajax.py similarity index 100% rename from web/utils/ajax.py rename to web/pgadmin/utils/ajax.py diff --git a/web/utils/__init__.py b/web/utils/__init__.py deleted file mode 100644 index e69de29bb..000000000