mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
This is a big one campers; Add initial support for treeview nodes.
This commit adds the following: - Storage of server groups in the configuration database - Creation of a default server group on in the database - A mechanism for plugging in treeview node types - A node type for server groups with: - Treeview display - Custom per-node javascript implementing a menu option/dialogue to add new groups - Custom per-node CSS to style the treeview node - JSON formatted data in response to AJAX requests, including: - Success/failure indication - Error message - Extra info (e.g. stack trace) - The original request data - Additional return data, e.g. node ID and label etc.
This commit is contained in:
parent
e2832351ed
commit
89cc11fb80
@ -39,6 +39,10 @@ APP_VERSION = '%s.%s.%s-%s' % (APP_MAJOR, APP_MINOR, APP_REVISION, APP_SUFFIX)
|
||||
# List of modules to skip when dynamically loading
|
||||
MODULE_BLACKLIST = [ 'test' ]
|
||||
|
||||
# DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING!
|
||||
# List of treeview browser nodes to skip when dynamically loading
|
||||
NODE_BLACKLIST = [ ]
|
||||
|
||||
##########################################################################
|
||||
# Log settings
|
||||
##########################################################################
|
||||
|
@ -103,10 +103,10 @@ def create_app(app_name=config.APP_NAME):
|
||||
|
||||
# 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 'browser' module for
|
||||
# the browser integration hooks.
|
||||
# module here. Note that we also try to load the 'hooks' module for
|
||||
# the browser integration hooks and other similar functions.
|
||||
app.logger.info('Examining potential module: %s' % d)
|
||||
module = __import__(f, globals(), locals(), ['browser', 'views'], -1)
|
||||
module = __import__(f, globals(), locals(), ['hooks', 'views'], -1)
|
||||
|
||||
# Add the module to the global module list
|
||||
modules.append(module)
|
||||
@ -118,6 +118,11 @@ def create_app(app_name=config.APP_NAME):
|
||||
app.logger.debug(' - root_path: %s' % module.views.blueprint.root_path)
|
||||
app.logger.debug(' - static_folder: %s' % module.views.blueprint.static_folder)
|
||||
app.logger.debug(' - template_folder: %s' % module.views.blueprint.template_folder)
|
||||
|
||||
# Register any sub-modules
|
||||
if 'hooks' in dir(module) and 'register_submodules' in dir(module.hooks):
|
||||
app.logger.info('Registering sub-modules in %s' % f)
|
||||
module.hooks.register_submodules(app)
|
||||
|
||||
##########################################################################
|
||||
# Handle the desktop login
|
||||
|
@ -0,0 +1,11 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2014, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
# Define the global node list
|
||||
nodes = [ ]
|
51
web/pgadmin/browser/hooks.py
Normal file
51
web/pgadmin/browser/hooks.py
Normal file
@ -0,0 +1,51 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2014, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
"""Browser application hooks"""
|
||||
|
||||
import os, sys
|
||||
import config
|
||||
|
||||
from . import 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)
|
0
web/pgadmin/browser/nodes/__init__.py
Normal file
0
web/pgadmin/browser/nodes/__init__.py
Normal file
0
web/pgadmin/browser/nodes/server_groups/__init__.py
Normal file
0
web/pgadmin/browser/nodes/server_groups/__init__.py
Normal file
75
web/pgadmin/browser/nodes/server_groups/hooks.py
Normal file
75
web/pgadmin/browser/nodes/server_groups/hooks.py
Normal file
@ -0,0 +1,75 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2014, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
"""Integration hooks for server groups."""
|
||||
|
||||
from flask import url_for
|
||||
from flask.ext.security import current_user
|
||||
|
||||
from pgadmin.settings.settings_model import db, ServerGroup
|
||||
|
||||
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 = value[:-1]
|
||||
|
||||
return value
|
||||
|
||||
def get_file_menu_items():
|
||||
"""Return a (set) of dicts of file menu items, with name, priority and URL."""
|
||||
return [
|
||||
{'name': 'Add a server group...', 'priority': 10, 'url': '#', 'onclick': 'add_server_group()'}
|
||||
]
|
||||
|
||||
def get_script_snippets():
|
||||
"""Return the script snippets needed to handle treeview node operations."""
|
||||
script = """function add_server_group() {
|
||||
var alert = alertify.prompt(
|
||||
'Add a server group',
|
||||
'Enter a name for the new server group',
|
||||
'',
|
||||
function(evt, value) { $.post("%s", { 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-group'
|
||||
}
|
||||
|
||||
treeApi.append(null, {
|
||||
itemData: item
|
||||
});
|
||||
|
||||
}
|
||||
})
|
||||
},
|
||||
function(evt, value) { }
|
||||
);
|
||||
alert.show();
|
||||
}
|
||||
""" % url_for('NODE-server-group.add')
|
||||
return script
|
||||
|
||||
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 += "{"
|
||||
|
||||
return css
|
Binary file not shown.
After Width: | Height: | Size: 504 B |
64
web/pgadmin/browser/nodes/server_groups/views.py
Normal file
64
web/pgadmin/browser/nodes/server_groups/views.py
Normal file
@ -0,0 +1,64 @@
|
||||
##########################################################################
|
||||
#
|
||||
# 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 server groups"""
|
||||
|
||||
NODE_NAME = 'server-group'
|
||||
|
||||
NODE_PATH = '/browser/' + NODE_NAME
|
||||
|
||||
import traceback
|
||||
from flask import Blueprint, Response, current_app, request
|
||||
from flask.ext.security import current_user, login_required
|
||||
|
||||
from utils.ajax import make_json_result
|
||||
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.route('/add/', methods=['POST'])
|
||||
@login_required
|
||||
def add():
|
||||
"""Add a server group node to the settings database"""
|
||||
success = 1
|
||||
errormsg = ''
|
||||
data = { }
|
||||
|
||||
if request.form['name'] != '':
|
||||
servergroup = ServerGroup(user_id=current_user.id, name=request.form['name'])
|
||||
|
||||
try:
|
||||
db.session.add(servergroup)
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
success = 0
|
||||
errormsg = e.message
|
||||
|
||||
else:
|
||||
success = 0
|
||||
errormsg = "No server group name was specified"
|
||||
|
||||
if success == 1:
|
||||
data['id'] = servergroup.id
|
||||
data['name'] = servergroup.name
|
||||
|
||||
value = make_json_result(success=success,
|
||||
errormsg=errormsg,
|
||||
info=traceback.format_exc(),
|
||||
result=request.form,
|
||||
data=data)
|
||||
|
||||
resp = Response(response=value,
|
||||
status=200,
|
||||
mimetype="text/json")
|
||||
|
||||
return resp
|
||||
|
39
web/pgadmin/browser/static/js/utils.js
Normal file
39
web/pgadmin/browser/static/js/utils.js
Normal file
@ -0,0 +1,39 @@
|
||||
function report_error(message, info) {
|
||||
|
||||
text = '<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">\
|
||||
<div class="panel panel-default">\
|
||||
<div class="panel-heading" role="tab" id="headingOne">\
|
||||
<h4 class="panel-title">\
|
||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne">\
|
||||
Error message\
|
||||
</a>\
|
||||
</h4>\
|
||||
</div>\
|
||||
<div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">\
|
||||
<div class="panel-body" style="overflow: scroll;">' + message + '</div>\
|
||||
</div>\
|
||||
</div>'
|
||||
|
||||
if (info != '') {
|
||||
text += '<div class="panel panel-default">\
|
||||
<div class="panel-heading" role="tab" id="headingTwo">\
|
||||
<h4 class="panel-title">\
|
||||
<a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">\
|
||||
Additional info\
|
||||
</a>\
|
||||
</h4>\
|
||||
</div>\
|
||||
<div id="collapseTwo" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingTwo">\
|
||||
<div class="panel-body" style="overflow: scroll;">' + info + '</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>'
|
||||
}
|
||||
|
||||
text += '</div>'
|
||||
|
||||
alertify.alert(
|
||||
'An error has occurred',
|
||||
text
|
||||
)
|
||||
}
|
@ -153,17 +153,18 @@ $('#dependents a').click(function (e) {
|
||||
|
||||
// Syntax highlight the SQL Pane
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("sql-textarea"), {
|
||||
lineNumbers: true,
|
||||
mode: "text/x-sql",
|
||||
readOnly: true,
|
||||
lineNumbers: true,
|
||||
mode: "text/x-sql",
|
||||
readOnly: true,
|
||||
});
|
||||
|
||||
// Initialise the treeview
|
||||
$('#tree').aciTree({
|
||||
ajax: {
|
||||
url: '/static/tree.json'
|
||||
}
|
||||
ajax: {
|
||||
url: '{{ url_for('browser.get_nodes') }}'
|
||||
},
|
||||
});
|
||||
var treeApi = $('#tree').aciTree('api');
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -66,8 +66,4 @@
|
||||
{% include 'browser/body.html' %}
|
||||
{% include 'browser/messages.html' %}
|
||||
|
||||
<script>
|
||||
{{ js_code|safe }}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -10,12 +10,13 @@
|
||||
"""A blueprint module implementing the core pgAdmin browser."""
|
||||
MODULE_NAME = 'browser'
|
||||
|
||||
from flask import Blueprint, current_app, render_template, url_for
|
||||
from flask import Blueprint, Response, current_app, render_template, url_for
|
||||
from flaskext.gravatar import Gravatar
|
||||
from flask.ext.security import login_required
|
||||
from flask.ext.login import current_user
|
||||
from inspect import getmoduleinfo, getmembers
|
||||
|
||||
from . import nodes
|
||||
from pgadmin import modules
|
||||
from pgadmin.settings import get_setting
|
||||
|
||||
@ -24,9 +25,6 @@ import config
|
||||
# Initialise the module
|
||||
blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static', template_folder='templates', url_prefix='/' + MODULE_NAME)
|
||||
|
||||
##########################################################################
|
||||
# A test page
|
||||
##########################################################################
|
||||
@blueprint.route("/")
|
||||
@login_required
|
||||
def index():
|
||||
@ -47,42 +45,48 @@ def index():
|
||||
help_items = [ ]
|
||||
stylesheets = [ ]
|
||||
scripts = [ ]
|
||||
|
||||
modules_and_nodes = modules + nodes
|
||||
|
||||
# Add browser stylesheets
|
||||
stylesheets.append(url_for('static', filename='css/codemirror/codemirror.css'))
|
||||
stylesheets.append(url_for('browser.static', filename='css/browser.css'))
|
||||
stylesheets.append(url_for('browser.static', filename='css/aciTree/css/aciTree.css'))
|
||||
stylesheets.append(url_for('browser.browser_css'))
|
||||
|
||||
# Add browser scripts
|
||||
scripts.append(url_for('static', filename='js/codemirror/codemirror.js'))
|
||||
scripts.append(url_for('static', filename='js/codemirror/mode/sql.js'))
|
||||
scripts.append(url_for('browser.static', filename='js/utils.js'))
|
||||
scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciPlugin.min.js'))
|
||||
scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciTree.dom.js'))
|
||||
scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciTree.min.js'))
|
||||
scripts.append(url_for('browser.browser_js'))
|
||||
|
||||
for module in modules:
|
||||
for module in modules_and_nodes:
|
||||
# Get the edit menu items
|
||||
if 'browser' in dir(module) and 'get_file_menu_items' in dir(module.browser):
|
||||
file_items.extend(module.browser.get_file_menu_items())
|
||||
if 'hooks' in dir(module) and 'get_file_menu_items' in dir(module.hooks):
|
||||
file_items.extend(module.hooks.get_file_menu_items())
|
||||
|
||||
# Get the edit menu items
|
||||
if 'browser' in dir(module) and 'get_edit_menu_items' in dir(module.browser):
|
||||
edit_items.extend(module.browser.get_edit_menu_items())
|
||||
if 'hooks' in dir(module) and 'get_edit_menu_items' in dir(module.hooks):
|
||||
edit_items.extend(module.hooks.get_edit_menu_items())
|
||||
|
||||
# Get the tools menu items
|
||||
if 'browser' in dir(module) and 'get_tools_menu_items' in dir(module.browser):
|
||||
tools_items.extend(module.browser.get_tools_menu_items())
|
||||
if 'hooks' in dir(module) and 'get_tools_menu_items' in dir(module.hooks):
|
||||
tools_items.extend(module.hooks.get_tools_menu_items())
|
||||
|
||||
# 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())
|
||||
if 'hooks' in dir(module) and 'get_help_menu_items' in dir(module.hooks):
|
||||
help_items.extend(module.hooks.get_help_menu_items())
|
||||
|
||||
# Get any stylesheets
|
||||
if 'browser' in dir(module) and 'get_stylesheets' in dir(module.browser):
|
||||
stylesheets += module.browser.get_stylesheets()
|
||||
if 'hooks' in dir(module) and 'get_stylesheets' in dir(module.hooks):
|
||||
stylesheets += module.hooks.get_stylesheets()
|
||||
|
||||
# Get any scripts
|
||||
if 'browser' in dir(module) and 'get_scripts' in dir(module.browser):
|
||||
scripts += module.browser.get_scripts()
|
||||
if 'hooks' in dir(module) and 'get_scripts' in dir(module.hooks):
|
||||
scripts += module.hooks.get_scripts()
|
||||
|
||||
file_items = sorted(file_items, key=lambda k: k['priority'])
|
||||
edit_items = sorted(edit_items, key=lambda k: k['priority'])
|
||||
@ -105,3 +109,61 @@ def index():
|
||||
stylesheets = stylesheets,
|
||||
scripts = scripts,
|
||||
layout_settings = layout_settings)
|
||||
|
||||
@blueprint.route("/browser.js")
|
||||
@login_required
|
||||
def browser_js():
|
||||
"""Render and return JS snippets from the nodes and modules."""
|
||||
snippets = ''
|
||||
modules_and_nodes = modules + nodes
|
||||
|
||||
for module in modules_and_nodes:
|
||||
if 'hooks' in dir(module) and 'get_script_snippets' in dir(module.hooks):
|
||||
snippets += module.hooks.get_script_snippets()
|
||||
|
||||
resp = Response(response=snippets,
|
||||
status=200,
|
||||
mimetype="application/javascript")
|
||||
|
||||
return resp
|
||||
|
||||
@blueprint.route("/browser.css")
|
||||
@login_required
|
||||
def browser_css():
|
||||
"""Render and return CSS snippets from the nodes and modules."""
|
||||
snippets = ''
|
||||
modules_and_nodes = modules + nodes
|
||||
|
||||
for module in modules_and_nodes:
|
||||
if 'hooks' in dir(module) and 'get_css_snippets' in dir(module.hooks):
|
||||
snippets += module.hooks.get_css_snippets()
|
||||
|
||||
resp = Response(response=snippets,
|
||||
status=200,
|
||||
mimetype="text/css")
|
||||
|
||||
return resp
|
||||
|
||||
@blueprint.route("/root-nodes.json")
|
||||
@login_required
|
||||
def get_nodes():
|
||||
"""Build a list of treeview nodes from the child modules."""
|
||||
value = '['
|
||||
|
||||
for node in nodes:
|
||||
if 'hooks' in dir(node) and 'get_nodes' in dir(node.hooks):
|
||||
value += node.hooks.get_nodes() + ','
|
||||
|
||||
if value[-1:] == ',':
|
||||
value = value[:-1]
|
||||
|
||||
value += ']'
|
||||
|
||||
resp = Response(response=value,
|
||||
status=200,
|
||||
mimetype="text/json")
|
||||
|
||||
return resp
|
||||
|
||||
|
||||
|
@ -10,10 +10,12 @@
|
||||
"""Views for setting and storing configuration options."""
|
||||
MODULE_NAME = 'settings'
|
||||
|
||||
import config
|
||||
import traceback
|
||||
from flask import Blueprint, Response, abort, request, render_template
|
||||
from flask.ext.security import login_required
|
||||
|
||||
import config
|
||||
from utils.ajax import make_json_result
|
||||
from . import get_setting, store_setting
|
||||
|
||||
# Initialise the module
|
||||
@ -33,16 +35,30 @@ def script():
|
||||
def store(setting=None, value=None):
|
||||
"""Store a configuration setting, or if this is a POST request and a
|
||||
count value is present, store multiple settings at once."""
|
||||
if request.method == 'POST':
|
||||
if 'count' in request.form:
|
||||
for x in range(int(request.form['count'])):
|
||||
store_setting(request.form['setting%d' % (x+1)], request.form['value%d' % (x+1)])
|
||||
else:
|
||||
store_setting(request.form['setting'], request.form['value'])
|
||||
else:
|
||||
store_setting(setting, value)
|
||||
success = 1
|
||||
errorcode = 0
|
||||
errormsg = ''
|
||||
|
||||
return ''
|
||||
try:
|
||||
if request.method == 'POST':
|
||||
if 'count' in request.form:
|
||||
for x in range(int(request.form['count'])):
|
||||
store_setting(request.form['setting%d' % (x+1)], request.form['value%d' % (x+1)])
|
||||
else:
|
||||
store_setting(request.form['setting'], request.form['value'])
|
||||
else:
|
||||
store_setting(setting, value)
|
||||
except Exception as e:
|
||||
success = 0
|
||||
errormsg = e.message
|
||||
|
||||
value = make_json_result(success=success, errormsg=errormsg, info=traceback.format_exc(), result=request.form)
|
||||
|
||||
resp = Response(response=value,
|
||||
status=200,
|
||||
mimetype="text/json")
|
||||
|
||||
return resp
|
||||
|
||||
@blueprint.route("/get", methods=['POST'])
|
||||
@blueprint.route("/get/<setting>", methods=['GET'])
|
||||
@ -53,14 +69,21 @@ def get(setting=None, default=None):
|
||||
if request.method == 'POST':
|
||||
setting = request.form['setting']
|
||||
default = request.form['default']
|
||||
|
||||
|
||||
success = 1
|
||||
errorcode = 0
|
||||
errormsg = ''
|
||||
|
||||
try:
|
||||
value = get_setting(setting, default)
|
||||
except:
|
||||
return ''
|
||||
|
||||
except Exception as e:
|
||||
success = 0
|
||||
errormsg = e.message
|
||||
|
||||
value = make_json_result(success=success, errormsg=errormsg, info=traceback.format_exc(), result=request.form)
|
||||
|
||||
resp = Response(response=value,
|
||||
status=200,
|
||||
mimetype="text/plain")
|
||||
mimetype="text/json")
|
||||
|
||||
return resp
|
||||
|
@ -15,6 +15,11 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.alertify .ajs-content {
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
/* iFrames should have no border */
|
||||
iframe {
|
||||
border-width: 0;
|
||||
@ -30,6 +35,13 @@ iframe {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.icon-servers {
|
||||
background: url('/static/servers.png') 0 0 no-repeat !important;
|
||||
}
|
||||
/* Alert info panel */
|
||||
.alert-info-panel {
|
||||
border: 2px solid #a1a1a1;
|
||||
margin-top: 2em;
|
||||
padding: 5px 5px;
|
||||
background: #dddddd;
|
||||
border-radius: 5px;
|
||||
height: 8em;
|
||||
overflow: scroll;
|
||||
}
|
0
web/utils/__init__.py
Normal file
0
web/utils/__init__.py
Normal file
24
web/utils/ajax.py
Normal file
24
web/utils/ajax.py
Normal file
@ -0,0 +1,24 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
"""Utility functions for dealing with AJAX."""
|
||||
|
||||
import json
|
||||
|
||||
def make_json_result(success=1, errormsg='', info='', result={}, data={}):
|
||||
"""Create a JSON response document describing the results of a request and
|
||||
containing the data."""
|
||||
doc = { }
|
||||
doc['success'] = success
|
||||
doc['errormsg'] = errormsg
|
||||
doc['info'] = info
|
||||
doc['result'] = result
|
||||
doc['data'] = data
|
||||
|
||||
return json.dumps(doc)
|
Loading…
Reference in New Issue
Block a user