diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py
index 2eb0982f4..efd4b7cc3 100644
--- a/web/pgadmin/__init__.py
+++ b/web/pgadmin/__init__.py
@@ -9,7 +9,7 @@
"""The main pgAdmin module. This handles the application initialisation tasks,
such as setup of logging, dynamic loading of modules etc."""
-
+from collections import defaultdict
from flask import Flask, abort, request, current_app
from flask.ext.babel import Babel
from flask.ext.security import Security, SQLAlchemyUserDatastore
@@ -42,6 +42,32 @@ class PgAdmin(Flask):
if isinstance(value, PgAdminModule):
yield value
+ @property
+ def submodules(self):
+ for blueprint in self.blueprints.values():
+ if isinstance(blueprint, PgAdminModule):
+ yield blueprint
+
+ @property
+ def stylesheets(self):
+ stylesheets = []
+ for module in self.submodules:
+ stylesheets.extend(getattr(module, "stylesheets", []))
+ return stylesheets
+
+ @property
+ def javascripts(self):
+ stylesheets = []
+ for module in self.submodules:
+ stylesheets.extend(getattr(module, "javascripts", []))
+ return stylesheets
+
+ @property
+ def panels(self):
+ panels = []
+ for module in self.submodules:
+ panels.extend(module.get_panels())
+ return panels
def _find_blueprint():
if request.blueprint:
@@ -169,9 +195,13 @@ def create_app(app_name=config.APP_NAME):
@app.context_processor
def inject_blueprint():
"""Inject a reference to the current blueprint, if any."""
+ menu_items = defaultdict(list)
+ for blueprint in app.submodules:
+ menu_items.update(getattr(blueprint, "menu_items", {}))
return {
+ 'current_app': current_app,
'current_blueprint': current_blueprint,
- 'menu_items': getattr(current_blueprint, "menu_items", {})}
+ 'menu_items': menu_items }
##########################################################################
# All done!
diff --git a/web/pgadmin/about/__init__.py b/web/pgadmin/about/__init__.py
index e69de29bb..5830c7cc6 100644
--- a/web/pgadmin/about/__init__.py
+++ b/web/pgadmin/about/__init__.py
@@ -0,0 +1,67 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2015, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""A blueprint module implementing the about box."""
+MODULE_NAME = 'about'
+
+from pgadmin.utils import PgAdminModule
+from pgadmin.utils.menu import MenuItem
+from flask import Response, current_app, render_template, __version__, url_for
+from flask.ext.babel import gettext
+from flask.ext.security import current_user, login_required
+
+import sys
+
+import config
+
+class AboutModule(PgAdminModule):
+
+ def get_own_menuitems(self):
+ return {
+ 'help_items': [
+ MenuItem(name='mnu_about',
+ priority=999,
+ url='#',
+ onclick='about_show()',
+ label=gettext('About %(appname)s', appname=config.APP_NAME))
+ ]
+ }
+
+ def get_own_javascripts(self):
+ return [url_for('about.script')]
+
+
+blueprint = AboutModule(MODULE_NAME, __name__,
+ static_url_path='')
+
+##########################################################################
+# A test page
+##########################################################################
+@blueprint.route("/")
+@login_required
+def index():
+ """Render the about box."""
+ info = { }
+ info['python_version'] = sys.version
+ info['flask_version'] = __version__
+ if config.SERVER_MODE == True:
+ info['app_mode'] = gettext('Server')
+ else:
+ info['app_mode'] = gettext('Desktop')
+ info['current_user'] = current_user.email
+
+ return render_template(MODULE_NAME + '/index.html', info=info)
+
+@blueprint.route("/about.js")
+@login_required
+def script():
+ """Render the required Javascript"""
+ return Response(response=render_template("about/about.js"),
+ status=200,
+ mimetype="application/javascript")
diff --git a/web/pgadmin/about/hooks.py b/web/pgadmin/about/hooks.py
deleted file mode 100644
index f0c0ac804..000000000
--- a/web/pgadmin/about/hooks.py
+++ /dev/null
@@ -1,28 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Browser integration functions for the About module."""
-
-from flask import render_template, url_for
-from flask.ext.babel import gettext
-
-import config
-
-def get_help_menu_items():
- """Return a (set) of dicts of help menu items, with name, priority, URL,
- target and onclick code."""
- return [{'name': 'mnu_about',
- 'label': gettext('About %(appname)s', appname=config.APP_NAME),
- 'priority': 999,
- 'url': "#",
- 'onclick': "about_show()"}]
-
-def get_scripts():
- """Return a list of script URLs to include in the rendered page header"""
- return [ url_for('about.script') ]
\ No newline at end of file
diff --git a/web/pgadmin/about/views.py b/web/pgadmin/about/views.py
deleted file mode 100644
index 0966a16e7..000000000
--- a/web/pgadmin/about/views.py
+++ /dev/null
@@ -1,48 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""A blueprint module implementing the about box."""
-MODULE_NAME = 'about'
-
-from flask import Blueprint, Response, current_app, render_template, __version__
-from flask.ext.babel import gettext
-from flask.ext.security import current_user, login_required
-
-import sys
-
-import config
-
-# Initialise the module
-blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static', static_url_path='', template_folder='templates', url_prefix='/' + MODULE_NAME)
-
-##########################################################################
-# A test page
-##########################################################################
-@blueprint.route("/")
-@login_required
-def index():
- """Render the about box."""
- info = { }
- info['python_version'] = sys.version
- info['flask_version'] = __version__
- if config.SERVER_MODE == True:
- info['app_mode'] = gettext('Server')
- else:
- info['app_mode'] = gettext('Desktop')
- info['current_user'] = current_user.email
-
- return render_template(MODULE_NAME + '/index.html', info=info)
-
-@blueprint.route("/about.js")
-@login_required
-def script():
- """Render the required Javascript"""
- return Response(response=render_template("about/about.js"),
- status=200,
- mimetype="application/javascript")
\ No newline at end of file
diff --git a/web/pgadmin/browser/templates/browser/index.html b/web/pgadmin/browser/templates/browser/index.html
index a3b63f67a..dd3a4b25a 100644
--- a/web/pgadmin/browser/templates/browser/index.html
+++ b/web/pgadmin/browser/templates/browser/index.html
@@ -31,39 +31,22 @@
{{ _('Drop object') }}
{{ _('Rename object') }}
- {% if file_items is defined and file_items|count > 0 %}{% for file_item in file_items %}
- {{ file_item.label }}{% endfor %}{% endif %}
+ {% for file_item in menu_items.file_items %}
+ {{ file_item.label }}{% endfor %}
-
- {% if edit_items is defined and edit_items|count > 0 %}
- {{ _('Edit') }}
-
- {% endif %}
-
- {% if tools_items is defined and tools_items|count > 0 %}
- {{ _('Tools') }}
-
- {% endif %}
-
- {% if management_items is defined and management_items|count > 0 %}
- {{ _('Management') }}
-
- {% endif %}
-
- {% if help_items is defined and help_items|count > 0 %}
- {{ _('Help') }}
-
- {% endif %}
-
+ {% for key in ('Edit', 'Tools', 'Management', 'Help') %}
+ {% if menu_items['%s_items' % key.lower()] %}
+
+ {{ _(key) }}
+
+ {%endif%}
+ {% endfor %}
{% if config.SERVER_MODE %}
diff --git a/web/pgadmin/browser/templates/browser/js/browser.js b/web/pgadmin/browser/templates/browser/js/browser.js
index f41eb62bb..e1aa05b5a 100644
--- a/web/pgadmin/browser/templates/browser/js/browser.js
+++ b/web/pgadmin/browser/templates/browser/js/browser.js
@@ -254,7 +254,7 @@ ALTER TABLE tickets_detail \n\
'Dependents pane
')
// Add hooked-in panels
- {% for panel_item in menu_items.panel_items %}{% if panel_item.isIframe %}
+ {% for panel_item in current_app.panels %}{% if panel_item.isIframe %}
buildIFramePanel(docker, '{{ panel_item.name }}', '{{ panel_item.title }}',
{{ panel_item.width }}, {{ panel_item.height }},
{{ panel_item.showTitle|lower }}, {{ panel_item.isCloseable|lower }},
diff --git a/web/pgadmin/help/__init__.py b/web/pgadmin/help/__init__.py
index e69de29bb..6d753f85e 100644
--- a/web/pgadmin/help/__init__.py
+++ b/web/pgadmin/help/__init__.py
@@ -0,0 +1,66 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2015, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""A blueprint module implementing the pgAdmin help system."""
+MODULE_NAME = 'help'
+
+from pgadmin.utils import PgAdminModule
+from pgadmin.utils.menu import MenuItem, Panel
+from flask.ext.babel import gettext
+from flask import url_for
+import config
+
+
+class HelpModule(PgAdminModule):
+
+ def get_own_menuitems(self):
+ """Return a (set) of dicts of help menu items, with name, priority, URL,
+ target and onclick code."""
+ return { 'help_items': [
+ MenuItem(name='mnu_online_help',
+ label=gettext('Online Help'),
+ priority=100,
+ target='_new',
+ url=url_for('help.static', filename='index.html')),
+
+ MenuItem(name='mnu_pgadmin_website',
+ label= gettext('pgAdmin Website'),
+ priority= 200,
+ target= '_new',
+ url= 'http://www.pgadmin.org/' ),
+
+ MenuItem(name= 'mnu_postgresql_website',
+ label= gettext('PostgreSQL Website'),
+ priority= 300,
+ target= '_new',
+ url= 'http://www.postgresql.org/' )]}
+
+ def get_panels(self):
+ return [
+ Panel(
+ name='pnl_online_help',
+ priority=100,
+ title=gettext('Online Help'),
+ content=url_for('help.static', filename='index.html')),
+
+ Panel(name='pnl_pgadmin_website',
+ priority=200,
+ title=gettext('pgAdmin Website'),
+ content='http://www.pgadmin.org/'),
+
+ Panel(name='pnl_postgresql_website',
+ priority=300,
+ title=gettext('PostgreSQL Website'),
+ content='http://www.postgresql.org/')]
+
+
+
+# Initialise the module
+blueprint = HelpModule(MODULE_NAME, __name__, static_url_path='/help',
+ static_folder=config.HELP_PATH)
diff --git a/web/pgadmin/help/hooks.py b/web/pgadmin/help/hooks.py
deleted file mode 100644
index 9fb5bc632..000000000
--- a/web/pgadmin/help/hooks.py
+++ /dev/null
@@ -1,73 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Browser integration functions for the Help module."""
-
-from flask import url_for
-from flask.ext.babel import gettext
-
-import config
-
-def get_help_menu_items():
- """Return a (set) of dicts of help menu items, with name, priority, URL,
- target and onclick code."""
- return [{'name': 'mnu_online_help',
- 'label': gettext('Online Help'),
- 'priority': 100,
- 'target': '_new',
- 'url': url_for('help.static', filename='index.html') },
-
- {'name': 'mnu_pgadmin_website',
- 'label': gettext('pgAdmin Website'),
- 'priority': 200,
- 'target': '_new',
- 'url': 'http://www.pgadmin.org/' },
-
- {'name': 'mnu_postgresql_website',
- 'label': gettext('PostgreSQL Website'),
- 'priority': 300,
- 'target': '_new',
- 'url': 'http://www.postgresql.org/' }]
-
-def get_panels():
- """Return a (set) of dicts describing panels to create in the browser. Fields
- are name, priority, title, width, height, isIframe, showTitle, isCloseable,
- isPrivate and content"""
- return [{'name': 'pnl_online_help',
- 'priority': 100,
- 'title': gettext('Online Help'),
- 'width': 500,
- 'height': 600,
- 'isIframe': True,
- 'showTitle': True,
- 'isCloseable': True,
- 'isPrivate': False,
- 'content': url_for('help.static', filename='index.html') },
-
- {'name': 'pnl_pgadmin_website',
- 'priority': 200,
- 'title': gettext('pgAdmin Website'),
- 'width': 500,
- 'height': 600,
- 'isIframe': True,
- 'showTitle': True,
- 'isCloseable': True,
- 'isPrivate': False,
- 'content': 'http://www.pgadmin.org/' },
-
- {'name': 'pnl_postgresql_website',
- 'priority': 300,
- 'title': gettext('PostgreSQL Website'),
- 'width': 500,
- 'height': 600,
- 'isIframe': True,
- 'showTitle': True,
- 'isCloseable': True,
- 'isPrivate': False,
- 'content': 'http://www.postgresql.org/' }]
\ No newline at end of file
diff --git a/web/pgadmin/help/views.py b/web/pgadmin/help/views.py
deleted file mode 100644
index 10ad91043..000000000
--- a/web/pgadmin/help/views.py
+++ /dev/null
@@ -1,18 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""A blueprint module implementing the pgAdmin help system."""
-MODULE_NAME = 'help'
-
-from flask import Blueprint
-
-import config
-
-# Initialise the module
-blueprint = Blueprint(MODULE_NAME, __name__, static_url_path='/help', static_folder=config.HELP_PATH)
diff --git a/web/pgadmin/templates/base.html b/web/pgadmin/templates/base.html
index b1ffed331..5a36182b5 100755
--- a/web/pgadmin/templates/base.html
+++ b/web/pgadmin/templates/base.html
@@ -21,7 +21,7 @@
{% if config.DEBUG %}{% else %}{% endif %}
- {% for stylesheet in current_blueprint.stylesheets %}
+ {% for stylesheet in current_app.stylesheets %}
{% endfor %}
@@ -32,7 +32,7 @@
- {% for script in current_blueprint.javascripts %}
+ {% for script in current_app.javascripts %}
{% endfor %}
diff --git a/web/pgadmin/test/__init__.py b/web/pgadmin/test/__init__.py
index e69de29bb..6ca55ef57 100644
--- a/web/pgadmin/test/__init__.py
+++ b/web/pgadmin/test/__init__.py
@@ -0,0 +1,70 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2015, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Browser integration functions for the Test module."""
+MODULE_NAME = 'test'
+from flask.ext.security import login_required
+from flask import render_template, url_for
+from flask.ext.babel import gettext
+from pgadmin.utils import PgAdminModule
+from pgadmin.utils.menu import MenuItem
+from time import time, ctime
+
+class TestModule(PgAdminModule):
+
+ def get_own_menuitems(self):
+ return {'file_items': [
+ MenuItem(name='mnu_generate_test_html',
+ label=gettext('Generated Test HTML'),
+ priority=100,
+ url=url_for('test.generated')),
+ MenuItem(name='mnu_test_alert',
+ label=gettext('Test Alert'),
+ priority=200,
+ url='#',
+ onclick='test_alert()'),
+ MenuItem(name='mnu_test_confirm',
+ label=gettext('Test Confirm'),
+ priority=300,
+ url='#',
+ onclick='test_confirm()'),
+ MenuItem(name='mnu_test_dialog',
+ label=gettext('Test Dialog'),
+ priority=400,
+ url='#',
+ onclick='test_dialog()'),
+ MenuItem(name='mnu_test_prompt',
+ label=gettext('Test Prompt'),
+ priority=500,
+ url='#',
+ onclick='test_prompt()'),
+ MenuItem(name='mnu_test_notifier',
+ label=gettext('Test Notifier'),
+ priority=600,
+ url='#',
+ onclick='test_notifier()')
+ ]}
+
+ def get_own_javascripts(self):
+ return [ url_for('test.static', filename='js/test.js') ]
+
+# Initialise the module
+blueprint = TestModule(MODULE_NAME, __name__)
+
+@blueprint.route("/generated")
+@login_required
+def generated():
+ """Generate a simple test page to demonstrate that output can be rendered."""
+ output = """
+Today is %s
+
+This is Flask-generated HTML.
+
+%s v%s""" % (ctime(time()), config.APP_NAME, config.APP_VERSION)
+ return output
diff --git a/web/pgadmin/test/hooks.py b/web/pgadmin/test/hooks.py
deleted file mode 100644
index ba8f9a8d1..000000000
--- a/web/pgadmin/test/hooks.py
+++ /dev/null
@@ -1,29 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Browser integration functions for the Test module."""
-
-from flask import render_template, url_for
-from flask.ext.babel import gettext
-
-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_generate_test_html', 'label': gettext('Generated Test HTML'), 'priority': 100, 'url': url_for('test.generated')},
- {'name': 'mnu_test_alert', 'label': gettext('Test Alert'), 'priority': 200, 'url': '#', 'onclick': 'test_alert()'},
- {'name': 'mnu_test_confirm', 'label': gettext('Test Confirm'), 'priority': 300, 'url': '#', 'onclick': 'test_confirm()'},
- {'name': 'mnu_test_dialog', 'label': gettext('Test Dialog'), 'priority': 400, 'url': '#', 'onclick': 'test_dialog()'},
- {'name': 'mnu_test_prompt', 'label': gettext('Test Prompt'), 'priority': 500, 'url': '#', 'onclick': 'test_prompt()'},
- {'name': 'mnu_test_notifier', 'label': gettext('Test Notifier'), 'priority': 600, 'url': '#', 'onclick': 'test_notifier()'},
- ]
-
-def get_scripts():
- """Return a list of script URLs to include in the rendered page header"""
- return [ url_for('test.static', filename='js/test.js') ]
\ No newline at end of file
diff --git a/web/pgadmin/test/views.py b/web/pgadmin/test/views.py
deleted file mode 100644
index 01088d50a..000000000
--- a/web/pgadmin/test/views.py
+++ /dev/null
@@ -1,35 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""A blueprint module providing utility functions for the application."""
-MODULE_NAME = 'test'
-
-import config
-from flask import Blueprint, render_template
-from flask.ext.security import login_required
-from time import time, ctime
-
-# Initialise the module
-blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static', template_folder='templates', url_prefix='/' + MODULE_NAME)
-
-##########################################################################
-# A test page
-##########################################################################
-@blueprint.route("/generated")
-@login_required
-def generated():
- """Generate a simple test page to demonstrate that output can be rendered."""
- output = """
-Today is %s
-
-This is Flask-generated HTML.
-
-%s v%s""" % (ctime(time()), config.APP_NAME, config.APP_VERSION)
-
- return output
diff --git a/web/pgadmin/utils/__init__.py b/web/pgadmin/utils/__init__.py
index b17742711..9370136fc 100644
--- a/web/pgadmin/utils/__init__.py
+++ b/web/pgadmin/utils/__init__.py
@@ -55,6 +55,13 @@ class PgAdminModule(Blueprint):
"""
return defaultdict(list)
+ def get_panels(self):
+ """
+ Returns:
+ list: a list of panel objects to add
+ """
+ return []
+
@property
def stylesheets(self):
stylesheets = self.get_own_stylesheets()
diff --git a/web/pgadmin/utils/menu.py b/web/pgadmin/utils/menu.py
index db50ed388..e8628ba46 100644
--- a/web/pgadmin/utils/menu.py
+++ b/web/pgadmin/utils/menu.py
@@ -1,6 +1,27 @@
from collections import namedtuple
+PRIORITY = 100
+
class MenuItem(object):
def __init__(self, **kwargs):
self.__dict__.update(**kwargs)
+
+class Panel(object):
+
+ def __init__(self, name, title, content, width=500, height=600, isIframe=True,
+ showTitle=True, isCloseable=True, isPrivate=False, priority=None):
+ self.name = name
+ self.title = title
+ self.content = content
+ self.width = width
+ self.height = height
+ self.isIfframe = isIframe
+ self.showTitle = showTitle
+ self.isCloseable = isCloseable
+ self.isPrivate = isPrivate
+ if priority is None:
+ global PRIORITY
+ PRIORITY += 100
+ priority = PRIORITY
+ self.priority = priority