Add support for creating dialogs, and add an About dialog.

This adds bootstrap-dialog to help with creation of nice dialogs,
and adds the ability for modules to render Javascript into the
browser, and specify onclick handlers in the menu system.

Also add a basic About dialog, using the new infrastructure and
showing some useful info about the application.
This commit is contained in:
Dave Page 2015-01-27 16:54:39 +00:00
parent d86c90fa73
commit 53d649de70
15 changed files with 1457 additions and 14 deletions

View File

@ -28,6 +28,9 @@ APP_REVISION = 0
# for GA releases.
APP_SUFFIX = 'dev'
# Copyright string for display in the app
APP_COPYRIGHT = 'Copyright 2014 - 2015, The pgAdmin Development Team'
# DO NOT CHANGE!
# The application version string, constructed from the components
APP_VERSION = '%s.%s.%s-%s' % (APP_MAJOR, APP_MINOR, APP_REVISION, APP_SUFFIX)

View File

@ -9,10 +9,19 @@
"""Browser integration functions for the About module."""
from flask import url_for
from flask import render_template, url_for
import config
def get_help_menu_items():
"""Return a (set) of dicts of help menu items, with name, priority and URL."""
return [{'name': 'About %s' % (config.APP_NAME), 'priority': 999, 'url': url_for('about.index')}]
"""Return a (set) of dicts of help menu items, with name, priority, URL and
onclick code."""
return [{'name': 'About %s' % (config.APP_NAME),
'priority': 999,
'url': "#",
'onclick': "about_show()"}]
def get_javascript_code():
"""Render from the template and return any Javascript code snippets required
in the browser"""
return render_template("about/browser.js")

View File

@ -0,0 +1,16 @@
{#
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2014, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
#}
function about_show() {
BootstrapDialog.show({
title: 'About {{ config.APP_NAME }}',
message: $('<div></div>').load('{{ url_for('about.index') }}')});
}

View File

@ -1 +1,28 @@
About {{ config.APP_NAME }}
<div class="row">
<div class="col-sm-3"><b>Version</b></div>
<div class="col-sm-9">{{ config.APP_VERSION }}</div>
</div>
<div class="row">
<div class="col-sm-3"><b>Copyright</b></div>
<div class="col-sm-9">{{ config.APP_COPYRIGHT }}</div>
</div>
<div class="row">
<div class="col-sm-3"><b>Python Version</b></div>
<div class="col-sm-9">{{ info.python_version }}</div>
</div>
<div class="row">
<div class="col-sm-3"><b>Flask Version</b></div>
<div class="col-sm-9">{{ info.flask_version }}</div>
</div>
<div class="row">
<div class="col-sm-3"><b>Application Mode</b></div>
<div class="col-sm-9">{{ info.app_mode }}</div>
</div>
<div class="row">
<div class="col-sm-3"><b>Current User</b></div>
<div class="col-sm-9">{{ info.current_user }}</div>
</div>
<div class="row">
<div class="col-sm-3 pull-right"><img src="{{ url_for('static', filename='img/logo-right-128.png') }}" alt="{{ config.APP_NAME }}"></div>
</div>

View File

@ -10,9 +10,12 @@
"""A blueprint module implementing the about box."""
MODULE_NAME = 'about'
from flask import Blueprint, current_app, render_template, __version__
from flask.ext.security import current_user, login_required
import sys
import config
from flask import Blueprint, current_app, render_template
from flask.ext.security import login_required
# Initialise the module
blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static', static_url_path='', template_folder='templates', url_prefix='/' + MODULE_NAME)
@ -24,4 +27,13 @@ blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static', static_url
@login_required
def index():
"""Render the about box."""
return render_template(MODULE_NAME + '/index.html')
info = { }
info['python_version'] = sys.version
info['flask_version'] = __version__
if config.SERVER_MODE == True:
info['app_mode'] = 'Server'
else:
info['app_mode'] = 'Desktop'
info['current_user'] = current_user.email
return render_template(MODULE_NAME + '/index.html', info=info)

View File

@ -21,7 +21,7 @@
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">File <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
{% for file_item in file_items %}
<li><a href="{{ file_item.url }}">{{ file_item.name|safe }}</a></li>
<li><a href="{{ file_item.url }}" onclick="{{ file_item.onclick|safe }}">{{ file_item.name }}</a></li>
{% endfor %}
</ul>
</li>
@ -30,7 +30,7 @@
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Edit <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
{% for edit_item in edit_items %}
<li><a href="{{ edit_item.url }}">{{ edit_item.name|safe }}</a></li>
<li><a href="{{ edit_item.url }}" onclick="{{ edit_item.onclick|safe }}">{{ edit_item.name }}</a></li>
{% endfor %}
</ul>
</li>
@ -39,7 +39,7 @@
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Tools <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
{% for tools_item in tools_items %}
<li><a href="{{ tools_item.url }}">{{ tools_item.name|safe }}</a></li>
<li><a href="{{ tools_item.url }}" onclick="{{ tools_item.onclick|safe }}">{{ tools_item.name }}</a></li>
{% endfor %}
</ul>
</li>
@ -48,7 +48,7 @@
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Help <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
{% for help_item in help_items %}
<li><a href="{{ help_item.url }}">{{ help_item.name|safe }}</a></li>
<li><a href="{{ help_item.url }}" onclick="{{ help_item.onclick|safe }}">{{ help_item.name }}</a></li>
{% endfor %}
</ul>
</li>
@ -70,6 +70,12 @@
</div>
</nav>
{% include 'browser/body.html' %}
{% include 'browser/messages.html' %}
<script language="javascript">
{{ js_code|safe }}
</script>
{% endblock %}

View File

@ -39,11 +39,12 @@ def index():
use_ssl=False,
base_url=None)
# Get the menu items from the module
# Get the plugin elements from the module
file_items = [ ]
edit_items = [ ]
tools_items = [ ]
help_items = [ ]
js_code = ''
for module in modules:
# Get the edit menu items
@ -61,15 +62,21 @@ def index():
# Get the help menu items
if 'browser' in dir(module) and 'get_help_menu_items' in dir(module.browser):
help_items.extend(module.browser.get_help_menu_items())
# Get any Javascript code
if 'browser' in dir(module) and 'get_javascript_code' in dir(module.browser):
js_code += (module.browser.get_javascript_code())
file_items = sorted(file_items, key=lambda k: k['priority'])
edit_items = sorted(edit_items, key=lambda k: k['priority'])
tools_items = sorted(tools_items, key=lambda k: k['priority'])
help_items = sorted(help_items, key=lambda k: k['priority'])
# Get any Javascript snippets
return render_template(MODULE_NAME + '/index.html',
username=current_user.email,
file_items=file_items,
edit_items=edit_items,
tools_items=tools_items,
help_items=help_items)
help_items=help_items,
js_code = js_code)

120
web/pgadmin/static/css/bootstrap-dialog.css vendored Executable file
View File

@ -0,0 +1,120 @@
.bootstrap-dialog {
}
.bootstrap-dialog .modal-header {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.bootstrap-dialog .bootstrap-dialog-title {
color: #fff;
display: inline-block;
}
.bootstrap-dialog.type-default .bootstrap-dialog-title {
color: #333;
}
.bootstrap-dialog .bootstrap-dialog-title {
font-size: 16px;
}
.bootstrap-dialog.size-large .bootstrap-dialog-title {
font-size: 24px;
}
.bootstrap-dialog .bootstrap-dialog-close-button {
float: right;
filter:alpha(opacity=90);
-moz-opacity:0.9;
-khtml-opacity: 0.9;
opacity: 0.9;
}
.bootstrap-dialog .bootstrap-dialog-close-button {
font-size: 20px;
}
.bootstrap-dialog.size-large .bootstrap-dialog-close-button {
font-size: 30px;
}
.bootstrap-dialog .bootstrap-dialog-close-button:hover {
cursor: pointer;
filter: alpha(opacity=100);
-moz-opacity: 1;
-khtml-opacity: 1;
opacity: 1;
}
.bootstrap-dialog .bootstrap-dialog-message {
font-size: 14px;
}
.bootstrap-dialog.size-large .bootstrap-dialog-message {
font-size: 18px;
}
.bootstrap-dialog.type-default .modal-header {
background-color: #fff;
}
.bootstrap-dialog.type-info .modal-header {
background-color: #5bc0de;
}
.bootstrap-dialog.type-primary .modal-header {
background-color: #428bca;
}
.bootstrap-dialog.type-success .modal-header {
background-color: #5cb85c;
}
.bootstrap-dialog.type-warning .modal-header {
background-color: #f0ad4e;
}
.bootstrap-dialog.type-danger .modal-header {
background-color: #d9534f;
}
.bootstrap-dialog .bootstrap-dialog-button-icon {
margin-right: 3px;
}
/**
* Icon animation
* Copied from font-awesome: http://fontawesome.io/
**/
.icon-spin {
display: inline-block;
-moz-animation: spin 2s infinite linear;
-o-animation: spin 2s infinite linear;
-webkit-animation: spin 2s infinite linear;
animation: spin 2s infinite linear;
}
@-moz-keyframes spin {
0% {
-moz-transform: rotate(0deg);
}
100% {
-moz-transform: rotate(359deg);
}
}
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
}
}
@-o-keyframes spin {
0% {
-o-transform: rotate(0deg);
}
100% {
-o-transform: rotate(359deg);
}
}
@-ms-keyframes spin {
0% {
-ms-transform: rotate(0deg);
}
100% {
-ms-transform: rotate(359deg);
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
/** End of icon animation **/

View File

@ -0,0 +1 @@
.bootstrap-dialog .modal-header{border-top-left-radius:4px;border-top-right-radius:4px}.bootstrap-dialog .bootstrap-dialog-title{color:#fff;display:inline-block}.bootstrap-dialog.type-default .bootstrap-dialog-title{color:#333}.bootstrap-dialog .bootstrap-dialog-title{font-size:16px}.bootstrap-dialog.size-large .bootstrap-dialog-title{font-size:24px}.bootstrap-dialog .bootstrap-dialog-close-button{float:right;filter:alpha(opacity=90);-moz-opacity:.9;-khtml-opacity:.9;opacity:.9}.bootstrap-dialog .bootstrap-dialog-close-button{font-size:20px}.bootstrap-dialog.size-large .bootstrap-dialog-close-button{font-size:30px}.bootstrap-dialog .bootstrap-dialog-close-button:hover{cursor:pointer;filter:alpha(opacity=100);-moz-opacity:1;-khtml-opacity:1;opacity:1}.bootstrap-dialog .bootstrap-dialog-message{font-size:14px}.bootstrap-dialog.size-large .bootstrap-dialog-message{font-size:18px}.bootstrap-dialog.type-default .modal-header{background-color:#fff}.bootstrap-dialog.type-info .modal-header{background-color:#5bc0de}.bootstrap-dialog.type-primary .modal-header{background-color:#428bca}.bootstrap-dialog.type-success .modal-header{background-color:#5cb85c}.bootstrap-dialog.type-warning .modal-header{background-color:#f0ad4e}.bootstrap-dialog.type-danger .modal-header{background-color:#d9534f}.bootstrap-dialog .bootstrap-dialog-button-icon{margin-right:3px}.icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0{-moz-transform:rotate(0)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0{-o-transform:rotate(0)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0{-ms-transform:rotate(0)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0{transform:rotate(0)}100%{transform:rotate(359deg)}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

1239
web/pgadmin/static/js/vendor/bootstrap-dialog.js vendored Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -15,6 +15,7 @@
<meta name="dcterms.dateCopyrighted" content="2014 - 2015">
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-dialog.min.css') }}">
<style>
body {
padding-top: 50px;
@ -36,6 +37,7 @@
<script src="{{ url_for('static', filename='js/vendor/jquery-1.11.1.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/vendor/bootstrap.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/vendor/bootstrap-dialog.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
</body>
</html>

View File

@ -1,5 +1,5 @@
{% block watermark %}
<div style="position: fixed; bottom: 0; right: 0;">
<img src="img/logo-right-256.png" alt="pgAdmin 4">
<img src="{{ url_for('static', filename='img/logo-right-256.png') }}" alt="pgAdmin 4">
</div>
{% endblock %}