mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Changed the logic to identify the PostgreSQL server variant, when we
connect to the database server. Also, added modified the way, we do check the node is supported by the server. Instead of creating separate blueprint for the server types, they will be independently works. In order to add different variant of the PostgreSQL, we need to extend the ServerType class, and override the 'instanceOf' function for identification using version string. Please take a look at the ppas.py for the example. During checking the back-end support for the node, we will also check the server type (variant) along with the version within the range of maximum and minimum version for the node. And, the same support added for the schema attributes in front-end (JavaScript). Really thankful to Khushboo Vashi for her initial work in front-end. I took it further from there.
This commit is contained in:
parent
3323543b5a
commit
77834ccdda
@ -180,7 +180,7 @@ class BrowserPluginModule(PgAdminModule):
|
||||
return scripts
|
||||
|
||||
def generate_browser_node(
|
||||
self, node_id, parent_id, label, icon, inode, node_type, **kwargs
|
||||
self, node_id, label, icon, inode, node_type, **kwargs
|
||||
):
|
||||
obj = {
|
||||
"id": "%s/%s" % (node_type, node_id),
|
||||
@ -189,7 +189,6 @@ class BrowserPluginModule(PgAdminModule):
|
||||
"inode": inode,
|
||||
"_type": node_type,
|
||||
"_id": node_id,
|
||||
"refid": parent_id,
|
||||
"module": 'pgadmin.node.%s' % node_type
|
||||
}
|
||||
for key in kwargs:
|
||||
|
@ -13,7 +13,7 @@ from flask import url_for, render_template
|
||||
from flask.ext.babel import gettext
|
||||
from pgadmin.browser.utils import PgAdminModule, PGChildModule
|
||||
from pgadmin.browser import BrowserPluginModule
|
||||
from pgadmin.browser.utils import NodeView, PGChildNodeView
|
||||
from pgadmin.browser.utils import NodeView, PGChildNode, PGChildNodeView
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class CollectionNodeModule(PgAdminModule, PGChildModule):
|
||||
@ -53,7 +53,7 @@ class CollectionNodeModule(PgAdminModule, PGChildModule):
|
||||
return scripts
|
||||
|
||||
def generate_browser_node(
|
||||
self, node_id, parents, label, icon, **kwargs
|
||||
self, node_id, label, icon, **kwargs
|
||||
):
|
||||
obj = {
|
||||
"id": "%s/%s" % (self.node_type, node_id),
|
||||
@ -62,14 +62,13 @@ class CollectionNodeModule(PgAdminModule, PGChildModule):
|
||||
"inode": self.node_inode,
|
||||
"_type": self.node_type,
|
||||
"_id": node_id,
|
||||
"refid": parents,
|
||||
"module": 'pgadmin.node.%s' % self.node_type
|
||||
}
|
||||
for key in kwargs:
|
||||
obj.setdefault(key, kwargs[key])
|
||||
return obj
|
||||
|
||||
def generate_browser_collection_node(self, sid, parents, **kwargs):
|
||||
def generate_browser_collection_node(self, sid, **kwargs):
|
||||
obj = {
|
||||
"id": "coll-%s/%d" % (self.node_type, sid),
|
||||
"label": self.collection_label,
|
||||
@ -77,7 +76,6 @@ class CollectionNodeModule(PgAdminModule, PGChildModule):
|
||||
"inode": True,
|
||||
"_type": 'coll-%s' % (self.node_type),
|
||||
"_id": sid,
|
||||
"refid": parents,
|
||||
"module": 'pgadmin.node.%s' % self.node_type
|
||||
}
|
||||
|
||||
@ -173,7 +171,7 @@ class CollectionNodeModule(PgAdminModule, PGChildModule):
|
||||
return []
|
||||
|
||||
|
||||
class CollectionNodeView(NodeView, PGChildNodeView):
|
||||
class CollectionNodeView(NodeView, PGChildNode):
|
||||
"""
|
||||
A PostgreSQL Collection node has specific functions needs to address
|
||||
i.e.
|
||||
|
@ -33,7 +33,6 @@ class ServerGroupModule(BrowserPluginModule):
|
||||
for group in groups:
|
||||
yield self.generate_browser_node(
|
||||
"%d" % (group.id),
|
||||
None,
|
||||
group.name,
|
||||
"icon-%s" % self.node_type,
|
||||
True,
|
||||
@ -179,7 +178,6 @@ class ServerGroupView(NodeView):
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
"%d" % (sg.id),
|
||||
None,
|
||||
sg.name,
|
||||
"icon-%s" % self.node_type,
|
||||
True,
|
||||
|
@ -1,44 +0,0 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
from pgadmin.browser.server_groups.servers import ServerTypeModule
|
||||
from pgadmin.browser.utils import PGChildModule
|
||||
from flask.ext.babel import gettext
|
||||
|
||||
|
||||
class PPASServer(ServerTypeModule, PGChildModule):
|
||||
NODE_TYPE = "ppas"
|
||||
|
||||
@property
|
||||
def node_type(self):
|
||||
return self.NODE_TYPE
|
||||
|
||||
@property
|
||||
def jssnippets(self):
|
||||
return []
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return "PPAS"
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return "Postgres Plus Advanced Server"
|
||||
|
||||
@property
|
||||
def driver(self):
|
||||
return "psycopg2"
|
||||
|
||||
@property
|
||||
def priority(self):
|
||||
return 1
|
||||
|
||||
def instanceOf(self, ver):
|
||||
return ver.startswith("EnterpriseDB")
|
||||
|
||||
blueprint = PPASServer(__name__, static_url_path='/static')
|
@ -1,43 +0,0 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
from pgadmin.browser.server_groups.servers import ServerTypeModule
|
||||
from pgadmin.browser.utils import PGChildModule
|
||||
|
||||
|
||||
class PGServer(ServerTypeModule, PGChildModule):
|
||||
NODE_TYPE = "pg"
|
||||
|
||||
@property
|
||||
def node_type(self):
|
||||
return self.NODE_TYPE
|
||||
|
||||
@property
|
||||
def jssnippets(self):
|
||||
return []
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return "PG"
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return "PostgreSQL"
|
||||
|
||||
@property
|
||||
def driver(self):
|
||||
return "psycopg2"
|
||||
|
||||
@property
|
||||
def priority(self):
|
||||
return 10
|
||||
|
||||
def instanceOf(self, ver):
|
||||
return True
|
||||
|
||||
blueprint = PGServer(__name__, static_url_path='/static')
|
@ -15,7 +15,7 @@ from pgadmin.utils.menu import MenuItem
|
||||
from pgadmin.utils.ajax import make_json_response, \
|
||||
make_response as ajax_response, internal_server_error, success_return, \
|
||||
unauthorized, bad_request, precondition_required, forbidden
|
||||
from pgadmin.browser.utils import NodeView
|
||||
from pgadmin.browser.utils import PGChildNodeView
|
||||
import traceback
|
||||
from flask.ext.babel import gettext
|
||||
import pgadmin.browser.server_groups as sg
|
||||
@ -23,6 +23,7 @@ from pgadmin.utils.crypto import encrypt, decrypt
|
||||
from pgadmin.browser import BrowserPluginModule
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
import six
|
||||
from pgadmin.browser.server_groups.servers.types import ServerType
|
||||
|
||||
class ServerModule(sg.ServerGroupPluginModule):
|
||||
NODE_TYPE = "server"
|
||||
@ -50,19 +51,18 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
for server in servers:
|
||||
manager = driver.connection_manager(server.id)
|
||||
conn = manager.connection()
|
||||
module = getattr(manager, "module", None)
|
||||
connected = conn.connected()
|
||||
|
||||
yield self.generate_browser_node(
|
||||
"%d" % (server.id),
|
||||
"%d" % gid,
|
||||
server.name,
|
||||
"icon-server-not-connected" if not connected else
|
||||
"icon-{0}".format(module.NODE_TYPE),
|
||||
"icon-{0}".format(manager.server_type),
|
||||
True,
|
||||
self.NODE_TYPE,
|
||||
connected=connected,
|
||||
server_type=module.type if module is not None else "PG"
|
||||
server_type=manager.server_type if connected else "pg",
|
||||
server_version=manager.sversion if connected else 0
|
||||
)
|
||||
|
||||
@property
|
||||
@ -79,6 +79,9 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
for submodule in self.submodules:
|
||||
snippets.extend(submodule.csssnippets)
|
||||
|
||||
for st in ServerType.types():
|
||||
snippets.extend(st.csssnippets)
|
||||
|
||||
return snippets
|
||||
|
||||
|
||||
@ -90,81 +93,7 @@ class ServerMenuItem(MenuItem):
|
||||
|
||||
blueprint = ServerModule(__name__)
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class ServerTypeModule(BrowserPluginModule):
|
||||
"""
|
||||
Base class for different server types.
|
||||
"""
|
||||
|
||||
|
||||
@abstractproperty
|
||||
def type(self):
|
||||
pass
|
||||
|
||||
@abstractproperty
|
||||
def description(self):
|
||||
pass
|
||||
|
||||
@abstractproperty
|
||||
def priority(self):
|
||||
pass
|
||||
|
||||
def get_nodes(self, manager=None, sid=None):
|
||||
assert(sid is not None)
|
||||
|
||||
nodes = []
|
||||
|
||||
for module in self.submodules:
|
||||
if isinstance(module, PGChildModule):
|
||||
if manager and module.BackendSupported(manager):
|
||||
nodes.extend(module.get_nodes(sid=sid, manager=manager))
|
||||
else:
|
||||
nodes.extend(module.get_nodes(sid=sid))
|
||||
|
||||
return nodes
|
||||
|
||||
@abstractmethod
|
||||
def instanceOf(self, version):
|
||||
pass
|
||||
|
||||
def __str__(self):
|
||||
return "Type: {0},Description:{1}".format(self.type, self.description)
|
||||
|
||||
@property
|
||||
def csssnippets(self):
|
||||
"""
|
||||
Returns a snippet of css to include in the page
|
||||
"""
|
||||
snippets = [
|
||||
render_template(
|
||||
"css/node.css",
|
||||
node_type=self.node_type
|
||||
)
|
||||
]
|
||||
|
||||
for submodule in self.submodules:
|
||||
snippets.extend(submodule.csssnippets)
|
||||
|
||||
return snippets
|
||||
|
||||
def get_own_javascripts(self):
|
||||
scripts = []
|
||||
|
||||
for module in self.submodules:
|
||||
scripts.extend(module.get_own_javascripts())
|
||||
|
||||
return scripts
|
||||
|
||||
@property
|
||||
def script_load(self):
|
||||
"""
|
||||
Load the module script for all server types, when a server node is
|
||||
initialized.
|
||||
"""
|
||||
return ServerTypeModule.NODE_TYPE
|
||||
|
||||
|
||||
class ServerNode(NodeView):
|
||||
class ServerNode(PGChildNodeView):
|
||||
node_type = ServerModule.NODE_TYPE
|
||||
|
||||
parent_ids = [{'type': 'int', 'id': 'gid'}]
|
||||
@ -196,20 +125,19 @@ class ServerNode(NodeView):
|
||||
for server in servers:
|
||||
manager = driver.connection_manager(server.id)
|
||||
conn = manager.connection()
|
||||
module = getattr(manager, "module", None)
|
||||
|
||||
connected = conn.connected()
|
||||
|
||||
res.append(
|
||||
self.blueprint.generate_browser_node(
|
||||
"%d" % (server.id),
|
||||
"%d" % gid,
|
||||
server.name,
|
||||
"icon-server-not-connected" if not connected else
|
||||
"icon-{0}".format(module.NODE_TYPE),
|
||||
"icon-{0}".format(manager.server_type),
|
||||
True,
|
||||
self.node_type,
|
||||
connected=connected,
|
||||
server_type=module.type if module is not None else 'PG'
|
||||
server_type=manager.server_type if connected else 'PG',
|
||||
version=manager.sversion
|
||||
)
|
||||
)
|
||||
return make_json_response(result=res)
|
||||
@ -353,7 +281,6 @@ class ServerNode(NodeView):
|
||||
manager = driver.connection_manager(sid)
|
||||
conn = manager.connection()
|
||||
connected = conn.connected()
|
||||
module = getattr(manager, 'module', None)
|
||||
|
||||
return ajax_response(
|
||||
response={
|
||||
@ -368,8 +295,8 @@ class ServerNode(NodeView):
|
||||
'comment': server.comment,
|
||||
'role': server.role,
|
||||
'connected': connected,
|
||||
'version': manager.ver,
|
||||
'server_type': module.type if module is not None else 'PG'
|
||||
'version': manager.sversion,
|
||||
'server_type': manager.server_type if connected else 'PG'
|
||||
}
|
||||
)
|
||||
|
||||
@ -416,7 +343,6 @@ class ServerNode(NodeView):
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
"%d" % (server.id),
|
||||
"%d" % gid,
|
||||
server.name,
|
||||
"icon-server-not-connected",
|
||||
True,
|
||||
@ -433,31 +359,6 @@ class ServerNode(NodeView):
|
||||
errormsg=e.message
|
||||
)
|
||||
|
||||
def nodes(self, gid, sid):
|
||||
"""Build a list of treeview nodes from the child nodes."""
|
||||
from pgadmin.utils.driver import get_driver
|
||||
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||
conn = manager.connection()
|
||||
|
||||
if not conn.connected():
|
||||
return precondition_required(
|
||||
gettext(
|
||||
"Please make a connection to the server first!"
|
||||
)
|
||||
)
|
||||
|
||||
nodes = []
|
||||
|
||||
# We will rely on individual server type modules to generate nodes for
|
||||
# them selves.
|
||||
module = getattr(manager, 'module', None)
|
||||
|
||||
if module:
|
||||
nodes.extend(module.get_nodes(sid=sid, manager=manager))
|
||||
|
||||
return make_json_response(data=nodes)
|
||||
|
||||
def sql(self, gid, sid):
|
||||
return make_json_response(data='')
|
||||
|
||||
@ -481,13 +382,7 @@ class ServerNode(NodeView):
|
||||
return make_response(
|
||||
render_template(
|
||||
"servers/servers.js",
|
||||
server_types=sorted(
|
||||
[
|
||||
m for m in self.blueprint.submodules
|
||||
if isinstance(m, ServerTypeModule)
|
||||
],
|
||||
key=lambda x: x.priority
|
||||
),
|
||||
server_types=ServerType.types(),
|
||||
_=gettext
|
||||
),
|
||||
200, {'Content-Type': 'application/x-javascript'}
|
||||
@ -572,10 +467,7 @@ class ServerNode(NodeView):
|
||||
try:
|
||||
status, errmsg = conn.connect(
|
||||
password=password,
|
||||
modules=[
|
||||
m for m in self.blueprint.submodules
|
||||
if isinstance(m, ServerTypeModule)
|
||||
]
|
||||
server_types=ServerType.types()
|
||||
)
|
||||
except Exception as e:
|
||||
# TODO::
|
||||
@ -626,9 +518,11 @@ class ServerNode(NodeView):
|
||||
info=gettext("Server Connected."),
|
||||
data={
|
||||
'icon': 'icon-{0}'.format(
|
||||
manager.module.NODE_TYPE
|
||||
manager.server_type
|
||||
),
|
||||
'connected': True
|
||||
'connected': True,
|
||||
'type': manager.server_type,
|
||||
'version': manager.sversion
|
||||
}
|
||||
)
|
||||
|
||||
|
19
web/pgadmin/browser/server_groups/servers/ppas.py
Normal file
19
web/pgadmin/browser/server_groups/servers/ppas.py
Normal file
@ -0,0 +1,19 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
from flask.ext.babel import gettext
|
||||
from pgadmin.browser.server_groups.servers.types import ServerType
|
||||
|
||||
|
||||
class PPAS(ServerType):
|
||||
|
||||
def instanceOf(self, ver):
|
||||
return ver.startswith("EnterpriseDB")
|
||||
|
||||
# Default Server Type
|
||||
PPAS('ppas', gettext("Postgres Plus Advanced Server"), 2)
|
Before Width: | Height: | Size: 850 B After Width: | Height: | Size: 850 B |
Before Width: | Height: | Size: 676 B After Width: | Height: | Size: 676 B |
@ -1,7 +0,0 @@
|
||||
.icon-{{node_type}} {
|
||||
background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/%s.png' % node_type )}}') !important;
|
||||
background-repeat: no-repeat;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
.icon-{{ server_type }} {
|
||||
background-image: url('{{ url_for('NODE-server.static', filename='img/%s.png' % server_type)}}') !important;
|
||||
background-repeat: no-repeat;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
@ -69,7 +69,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
|
||||
var input = args || {};
|
||||
obj = this,
|
||||
t = pgBrowser.tree,
|
||||
i = input.item || t.selected(),
|
||||
i = 'item' in input ? input.item : t.selected(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined;
|
||||
|
||||
if (!d)
|
||||
@ -80,17 +80,21 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
|
||||
S('{{ _('Are you sure you want to disconnect the server - %%s ?') }}').sprintf(d.label).value(),
|
||||
function(evt) {
|
||||
$.ajax({
|
||||
url: obj.generate_url('connect', d, true),
|
||||
url: obj.generate_url(i, 'connect', d, true),
|
||||
type:'DELETE',
|
||||
success: function(res) {
|
||||
if (res.success == 1) {
|
||||
alertify.success("{{ _('" + res.info + "') }}");
|
||||
d = t.itemData(i);
|
||||
t.removeIcon(i);
|
||||
d.connected = false;
|
||||
d.icon = 'icon-server-not-connected';
|
||||
t.addIcon(i, {icon: d.icon});
|
||||
t.unload(i);
|
||||
t.setInode(i);
|
||||
if (pgBrowser.serverInfo && d._id in pgBrowser.serverInfo) {
|
||||
delete pgBrowser.serverInfo[d._id]
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
@ -112,17 +116,21 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
|
||||
return false;
|
||||
},
|
||||
/* Connect the server (if not connected), before opening this node */
|
||||
beforeopen: function(item, data, browser) {
|
||||
beforeopen: function(item, data) {
|
||||
if(!data || data._type != 'server') {
|
||||
return false;
|
||||
}
|
||||
|
||||
browser.tree.addIcon(item, {icon: data.icon});
|
||||
pgBrowser.tree.addIcon(item, {icon: data.icon});
|
||||
if (!data.connected) {
|
||||
connect_to_server(this, data, browser.tree, item);
|
||||
connect_to_server(this, data, pgBrowser.tree, item);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
opened: function(item, data) {
|
||||
pgBrowser.serverInfo = pgBrowser.serverInfo || {};
|
||||
pgBrowser.serverInfo[data._id] = _.extend({}, data);
|
||||
}
|
||||
},
|
||||
model: pgAdmin.Browser.Node.Model.extend({
|
||||
@ -218,18 +226,16 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
|
||||
tree.setInode(item);
|
||||
|
||||
if (res && res.data) {
|
||||
if(typeof res.data.connected == 'boolean') {
|
||||
data.connected = res.data.connected;
|
||||
}
|
||||
|
||||
if (typeof res.data.icon == 'string') {
|
||||
tree.removeIcon(item);
|
||||
data.icon = res.data.icon;
|
||||
tree.addIcon(item, {icon: data.icon});
|
||||
}
|
||||
_.extend(data, res.data);
|
||||
|
||||
alertify.success(res.info);
|
||||
setTimeout(function() {tree.select(item);}, 10);
|
||||
setTimeout(function() {tree.open(item);}, 100);
|
||||
setTimeout(function() { tree.select(item); tree.open(item); }, 10);
|
||||
}
|
||||
};
|
||||
|
||||
@ -273,7 +279,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
|
||||
|
||||
if (closeEvent.button.text == "{{ _('OK') }}") {
|
||||
|
||||
var _url = _model.generate_url('connect', _sdata, true);
|
||||
var _url = _model.generate_url(_item, 'connect', _sdata, true);
|
||||
|
||||
_tree.setLeaf(_item);
|
||||
_tree.removeIcon(_item);
|
||||
@ -309,7 +315,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
|
||||
'{{ _('Connect to server') }}',
|
||||
'{{ _('Do you want to connect the server?') }}',
|
||||
function(evt) {
|
||||
url = obj.generate_url("connect", data, true);
|
||||
url = obj.generate_url(item, "connect", data, true);
|
||||
$.post(url)
|
||||
.done(
|
||||
function(res) {
|
||||
|
75
web/pgadmin/browser/server_groups/servers/types.py
Normal file
75
web/pgadmin/browser/server_groups/servers/types.py
Normal file
@ -0,0 +1,75 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
import six
|
||||
from abc import ABCMeta, abstractmethod, abstractproperty
|
||||
from flask import render_template
|
||||
from flask.ext.babel import gettext
|
||||
|
||||
|
||||
class ServerType:
|
||||
"""
|
||||
Server Type
|
||||
|
||||
Create an instance of this class to define new type of the server support,
|
||||
In order to define new type of instance, you may want to override this
|
||||
class with overriden function - instanceOf for type checking for
|
||||
identification based on the version.
|
||||
"""
|
||||
registry = dict()
|
||||
|
||||
def __init__(self, server_type, description, priority):
|
||||
self.stype = server_type
|
||||
self.description = description
|
||||
self.priority = priority
|
||||
|
||||
assert(server_type not in ServerType.registry)
|
||||
ServerType.registry[server_type] = self
|
||||
|
||||
@property
|
||||
def server_type(self):
|
||||
return self.stype
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return self.description
|
||||
|
||||
@property
|
||||
def priority(self):
|
||||
return self.priority
|
||||
|
||||
def __str__(self):
|
||||
return "Type: {0}, Description:{1}, Priority: {2}".format(
|
||||
self.stype, self.description, self.priority
|
||||
)
|
||||
|
||||
def instanceOf(self, version):
|
||||
return True
|
||||
|
||||
@property
|
||||
def csssnippets(self):
|
||||
"""
|
||||
Returns a snippet of css to include in the page
|
||||
"""
|
||||
return [
|
||||
render_template(
|
||||
"css/server_type.css",
|
||||
server_type=self.stype
|
||||
)
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def types(cls):
|
||||
return sorted(
|
||||
ServerType.registry.values(),
|
||||
key=lambda x: x.priority,
|
||||
reverse=True
|
||||
)
|
||||
|
||||
# Default Server Type
|
||||
ServerType('pg', gettext("PostgreSQL"), -1)
|
@ -358,7 +358,7 @@ OWNER TO helpdesk;\n';
|
||||
var d = this.itemData(item);
|
||||
n = obj.Nodes[d._type];
|
||||
if (n)
|
||||
settings.url = n.generate_url('nodes', d, true);
|
||||
settings.url = n.generate_url(item, 'nodes', d, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -33,6 +33,7 @@ function($, _, S, pgAdmin, Backbone, Alertify, Backform) {
|
||||
icon: 'fa fa-refresh'
|
||||
}]);
|
||||
},
|
||||
hasId: false,
|
||||
showProperties: function(item, data, panel) {
|
||||
var that = this,
|
||||
j = panel.$container.find('.obj_properties').first(),
|
||||
@ -41,13 +42,14 @@ function($, _, S, pgAdmin, Backbone, Alertify, Backform) {
|
||||
.addClass('pg-prop-content col-xs-12'),
|
||||
node = pgBrowser.Nodes[that.node],
|
||||
// This will be the URL, used for object manipulation.
|
||||
urlBase = this.generate_url('properties', data),
|
||||
urlBase = this.generate_url(item, 'properties', data),
|
||||
collections = new (node.Collection.extend({
|
||||
url: urlBase,
|
||||
model: node.model
|
||||
}))(),
|
||||
info = this.getTreeNodeHierarchy.apply(this, [item]),
|
||||
gridSchema = Backform.generateGridColumnsFromModel(
|
||||
node.model, 'prorperties', that.columns
|
||||
info, node.model, 'prorperties', that.columns
|
||||
),
|
||||
// Initialize a new Grid instance
|
||||
grid = new Backgrid.Grid({
|
||||
@ -86,28 +88,36 @@ function($, _, S, pgAdmin, Backbone, Alertify, Backform) {
|
||||
// Fetch Data
|
||||
collections.fetch({reset: true});
|
||||
},
|
||||
generate_url: function(type, d) {
|
||||
generate_url: function(item, type, d) {
|
||||
var url = pgAdmin.Browser.URL + '{TYPE}/{REDIRECT}{REF}',
|
||||
ref = S('/%s/').sprintf(d._id).value(),
|
||||
/*
|
||||
* Using list, and collections functions of a node to get the nodes
|
||||
* under the collection, and properties of the collection respectively.
|
||||
*/
|
||||
opURL = {
|
||||
'nodes': 'obj', 'properties': 'coll'
|
||||
};
|
||||
if (d._type == this.type) {
|
||||
if (d.refid)
|
||||
ref = S('/%s/').sprintf(d.refid).value();
|
||||
}
|
||||
},
|
||||
ref = '', self = this;
|
||||
|
||||
var TYPE = d.module.split(".");
|
||||
var args = {'TYPE': TYPE[TYPE.length-1], 'REDIRECT': '', 'REF': ref};
|
||||
if (type in opURL) {
|
||||
args.REDIRECT = opURL[type];
|
||||
} else {
|
||||
args.REDIRECT = type;
|
||||
}
|
||||
_.each(
|
||||
_.sortBy(
|
||||
_.values(
|
||||
_.pick(
|
||||
this.getTreeNodeHierarchy(item), function(v, k, o) {
|
||||
return (k != self.type);
|
||||
})
|
||||
),
|
||||
function(o) { return o.priority; }
|
||||
),
|
||||
function(o) {
|
||||
ref = S('%s/%s').sprintf(ref, o.id).value();
|
||||
});
|
||||
|
||||
var args = {
|
||||
'TYPE': self.type,
|
||||
'REDIRECT': (type in opURL ? opURL[type] : type),
|
||||
'REF': S('%s/').sprintf(ref).value()
|
||||
};
|
||||
|
||||
return url.replace(/{(\w+)}/g, function(match, arg) {
|
||||
return args[arg];
|
||||
|
@ -54,6 +54,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
title: function(d) {
|
||||
return d ? d.label : '';
|
||||
},
|
||||
hasId: true,
|
||||
///////
|
||||
// Initialization function
|
||||
// Generally - used to register the menus for this type of node.
|
||||
@ -83,7 +84,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
//
|
||||
// Used to generate view for the particular node properties, edit,
|
||||
// creation.
|
||||
getView: function(type, el, node, formType, callback, data) {
|
||||
getView: function(item, type, el, node, formType, callback, data) {
|
||||
|
||||
if (!this.type || this.type == '')
|
||||
// We have no information, how to generate view for this type.
|
||||
@ -92,7 +93,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
if (this.model) {
|
||||
// This will be the URL, used for object manipulation.
|
||||
// i.e. Create, Update in these cases
|
||||
var urlBase = this.generate_url(type, node);
|
||||
var urlBase = this.generate_url(item, type, node, false);
|
||||
|
||||
if (!urlBase)
|
||||
// Ashamed of myself, I don't know how to manipulate this
|
||||
@ -112,7 +113,8 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
onChangeData: data,
|
||||
onChangeCallback: callback
|
||||
}),
|
||||
groups = Backform.generateViewSchema(newModel, type);
|
||||
info = this.getTreeNodeHierarchy.apply(this, [item]),
|
||||
groups = Backform.generateViewSchema(info, newModel, type);
|
||||
|
||||
// 'schema' has the information about how to generate the form.
|
||||
if (groups) {
|
||||
@ -366,7 +368,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
.sprintf(obj.label, d.label).value(),
|
||||
function() {
|
||||
$.ajax({
|
||||
url: obj.generate_url('drop', d, true),
|
||||
url: obj.generate_url(i, 'drop', d, true),
|
||||
type:'DELETE',
|
||||
success: function(res) {
|
||||
if (res.success == 0) {
|
||||
@ -534,7 +536,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
// Make sure the HTML element is empty.
|
||||
j.empty();
|
||||
// Create a view to show the properties in fieldsets
|
||||
view = that.getView('properties', content, data, 'fieldset');
|
||||
view = that.getView(item, 'properties', content, data, 'fieldset');
|
||||
if (view) {
|
||||
// Save it for release it later
|
||||
j.data('obj-view', view);
|
||||
@ -592,7 +594,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
};
|
||||
|
||||
// Create a view to edit/create the properties in fieldsets
|
||||
view = that.getView(action, content, data, 'dialog', modelChanged, j);
|
||||
view = that.getView(item, action, content, data, 'dialog', modelChanged, j);
|
||||
if (view) {
|
||||
// Save it to release it later
|
||||
j.data('obj-view', view);
|
||||
@ -797,32 +799,38 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
* Supports url generation for create, drop, edit, properties, sql,
|
||||
* depends, statistics
|
||||
*/
|
||||
generate_url: function(type, d, with_id) {
|
||||
generate_url: function(item, type, d, with_id) {
|
||||
var url = pgAdmin.Browser.URL + '{TYPE}/{REDIRECT}{REF}',
|
||||
ref = S('/%s/').sprintf(d._id).value(),
|
||||
opURL = {
|
||||
'create': 'obj', 'drop': 'obj', 'edit': 'obj',
|
||||
'properties': 'obj', 'depends': 'deps',
|
||||
'statistics': 'stats', 'nodes': 'nodes'
|
||||
};
|
||||
if (d._type == this.type) {
|
||||
ref = '';
|
||||
if (d.refid)
|
||||
ref = S('/%s').sprintf(d.refid).value();
|
||||
if (with_id)
|
||||
ref = S('%s/%s').sprintf(ref, d._id).value();
|
||||
}
|
||||
},
|
||||
ref = '', self = this;
|
||||
|
||||
var args = { 'TYPE': this.type, 'REDIRECT': '', 'REF': ref };
|
||||
_.each(
|
||||
_.sortBy(
|
||||
_.values(
|
||||
_.pick(
|
||||
this.getTreeNodeHierarchy(item), function(v, k, o) {
|
||||
return (k != self.type);
|
||||
})
|
||||
),
|
||||
function(o) { return o.priority; }
|
||||
),
|
||||
function(o) {
|
||||
ref = S('%s/%s').sprintf(ref, o.id).value();
|
||||
});
|
||||
|
||||
if (type in opURL) {
|
||||
args.REDIRECT = opURL[type];
|
||||
if (type == 'create' && !this.parent_type) {
|
||||
args.REF = '/';
|
||||
}
|
||||
} else {
|
||||
args.REDIRECT = type;
|
||||
}
|
||||
ref = S('%s/%s').sprintf(
|
||||
ref, with_id && d._type == self.type ? d._id : ''
|
||||
).value();
|
||||
|
||||
var args = {
|
||||
'TYPE': self.type,
|
||||
'REDIRECT': (type in opURL ? opURL[type] : type),
|
||||
'REF': ref
|
||||
};
|
||||
|
||||
return url.replace(/{(\w+)}/g, function(match, arg) {
|
||||
return args[arg];
|
||||
@ -1337,7 +1345,25 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
})
|
||||
}),
|
||||
getTreeNodeHierarchy: function(i) {
|
||||
var idx = 0,
|
||||
res = {},
|
||||
t = pgBrowser.tree;
|
||||
do {
|
||||
d = t.itemData(i);
|
||||
if (d._type in pgBrowser.Nodes && pgBrowser.Nodes[d._type].hasId) {
|
||||
res[d._type] = {
|
||||
'id': d._id,
|
||||
'priority': idx
|
||||
};
|
||||
idx += 1;
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
} while (i);
|
||||
|
||||
return res;
|
||||
}
|
||||
});
|
||||
|
||||
return pgAdmin.Browser.Node;
|
||||
|
@ -34,9 +34,9 @@ class NodeAttr(object):
|
||||
pass
|
||||
|
||||
|
||||
class PGChildModule(object):
|
||||
class PGChildModule:
|
||||
"""
|
||||
class PGChildModule(ServerChildModule)
|
||||
class PGChildModule
|
||||
|
||||
This is a base class for children/grand-children of PostgreSQL, and
|
||||
all Postgres Plus version (i.e. Postgres Plus Advanced Server, Green Plum,
|
||||
@ -71,10 +71,12 @@ class PGChildModule(object):
|
||||
|
||||
assert(self.max_ver is None or isinstance(self.max_ver, int))
|
||||
assert(self.min_ver is None or isinstance(self.min_ver, int))
|
||||
assert(self.server_type is None or isinstance(self.server_type, list))
|
||||
|
||||
if self.min_ver is None or self.min_ver <= sversion:
|
||||
if self.max_ver is None or self.max_ver >= sversion:
|
||||
return True
|
||||
if self.server_type is None or manager.server_type in self.server_type:
|
||||
if self.min_ver is None or self.min_ver <= sversion:
|
||||
if self.max_ver is None or self.max_ver >= sversion:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@ -319,17 +321,32 @@ class NodeView(with_metaclass(MethodViewType, View)):
|
||||
return make_json_response(data=nodes)
|
||||
|
||||
|
||||
class PGChildNodeView(object):
|
||||
class PGChildNode(object):
|
||||
|
||||
def nodes(self, sid, **kwargs):
|
||||
"""Build a list of treeview nodes from the child nodes."""
|
||||
|
||||
from pgadmin.utils.driver import get_driver
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
|
||||
sid=sid
|
||||
)
|
||||
|
||||
did = None
|
||||
if 'did' in kwargs:
|
||||
did = kwargs['did']
|
||||
|
||||
conn = manager.connection(did=did)
|
||||
|
||||
if not conn.connected():
|
||||
return precondition_required(
|
||||
gettext(
|
||||
"Please make a connection to the server first!"
|
||||
)
|
||||
)
|
||||
|
||||
nodes = []
|
||||
for module in self.blueprint.submodules:
|
||||
if isinstance(module, ServerChildModule):
|
||||
if isinstance(module, PGChildModule):
|
||||
if sid is not None and manager is not None and \
|
||||
module.BackendSupported(manager):
|
||||
nodes.extend(module.get_nodes(sid=sid, **kwargs))
|
||||
@ -337,3 +354,8 @@ class PGChildNodeView(object):
|
||||
nodes.extend(module.get_nodes(sid=sid, **kwargs))
|
||||
|
||||
return make_json_response(data=nodes)
|
||||
|
||||
|
||||
class PGChildNodeView(NodeView, PGChildNode):
|
||||
|
||||
pass
|
||||
|
@ -229,7 +229,7 @@
|
||||
self.shown_tab = $(this).data('tabIndex');
|
||||
m.trigger('pg-property-tab-changed', {
|
||||
'collection': m.collection, 'model': m,
|
||||
'index': _.indexOf(m.collection.models, m),
|
||||
'index': m.collection && m.collection.models ? _.indexOf(m.collection.models, m) : 0,
|
||||
'shown': self.shown_tab, 'hidden': self.hidden_tab
|
||||
});
|
||||
});
|
||||
@ -296,32 +296,33 @@
|
||||
events: {}
|
||||
});
|
||||
|
||||
var generateGridColumnsFromModel = Backform.generateGridColumnsFromModel = function(m, type, cols) {
|
||||
var groups = Backform.generateViewSchema(m, type),
|
||||
schema = [],
|
||||
columns = [],
|
||||
addAll = _.isUndefined(cols) || _.isNull(cols);
|
||||
var generateGridColumnsFromModel = Backform.generateGridColumnsFromModel =
|
||||
function(node_info, m, type, cols) {
|
||||
var groups = Backform.generateViewSchema(node_info, m, type),
|
||||
schema = [],
|
||||
columns = [],
|
||||
addAll = _.isUndefined(cols) || _.isNull(cols);
|
||||
|
||||
// Prepare columns for backgrid
|
||||
_.each(groups, function(fields, key) {
|
||||
_.each(fields, function(f) {
|
||||
if (!f.control && !f.cell) {
|
||||
return;
|
||||
}
|
||||
f.cell_priority = _.indexOf(cols, f.name);
|
||||
if (addAll || f.cell_priority != -1) {
|
||||
columns.push(f);
|
||||
}
|
||||
// Prepare columns for backgrid
|
||||
_.each(groups, function(fields, key) {
|
||||
_.each(fields, function(f) {
|
||||
if (!f.control && !f.cell) {
|
||||
return;
|
||||
}
|
||||
f.cell_priority = _.indexOf(cols, f.name);
|
||||
if (addAll || f.cell_priority != -1) {
|
||||
columns.push(f);
|
||||
}
|
||||
});
|
||||
schema.push({label: key, fields: fields});
|
||||
});
|
||||
schema.push({label: key, fields: fields});
|
||||
});
|
||||
return {
|
||||
'columns': _.sortBy(columns, function(c) {
|
||||
return c.cell_priority;
|
||||
}),
|
||||
'schema': schema
|
||||
return {
|
||||
'columns': _.sortBy(columns, function(c) {
|
||||
return c.cell_priority;
|
||||
}),
|
||||
'schema': schema
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
var SubNodeCollectionControl = Backform.SubNodeCollectionControl = Backform.Control.extend({
|
||||
render: function() {
|
||||
@ -367,7 +368,7 @@
|
||||
|
||||
var subnode = data.subnode.schema ? data.subnode : data.subnode.prototype,
|
||||
gridSchema = Backform.generateGridColumnsFromModel(
|
||||
subnode, this.field.get('mode'), data.columns
|
||||
data.node_info, subnode, this.field.get('mode'), data.columns
|
||||
);
|
||||
|
||||
// Set visibility of Add button
|
||||
@ -435,7 +436,7 @@
|
||||
//
|
||||
// It will be used by the grid, properties, and dialog view generation
|
||||
// functions.
|
||||
var generateViewSchema = Backform.generateViewSchema = function(Model, mode) {
|
||||
var generateViewSchema = Backform.generateViewSchema = function(node_info, Model, mode) {
|
||||
var proto = (Model && Model.prototype) || Model,
|
||||
schema = (proto && proto.schema),
|
||||
groups, pgBrowser = window.pgAdmin.Browser;
|
||||
@ -446,7 +447,9 @@
|
||||
return ((prop && proto[prop] &&
|
||||
typeof proto[prop] == "function") ? proto[prop] : prop);
|
||||
};
|
||||
groups = {};
|
||||
groups = {},
|
||||
server_info = node_info && ('server' in node_info) &&
|
||||
pgBrowser.serverInfo && pgBrowser.serverInfo[node_info.server.id];
|
||||
|
||||
_.each(schema, function(s) {
|
||||
// Do we understand - what control, we're creating
|
||||
@ -465,22 +468,30 @@
|
||||
|
||||
// Generate the empty group list (if not exists)
|
||||
groups[group] = (groups[group] || []);
|
||||
var disabled = ((mode == 'properties') ||
|
||||
(server_info &&
|
||||
(s.server_type && _.indexOf(server_info.type in s.server_type) == -1) ||
|
||||
(s.min_version && s.min_version < server_info.version) ||
|
||||
(s.max_version && s.max_version > server_info.version)
|
||||
));
|
||||
|
||||
var o = _.extend(_.clone(s), {
|
||||
name: s.id,
|
||||
// Do we need to show this control in this mode?
|
||||
visible: evalASFunc(s.show),
|
||||
// This can be disabled in some cases (if not hidden)
|
||||
disabled: (mode == 'properties' ? true : evalASFunc(s.disabled)),
|
||||
editable: (mode == 'properties' ? false : pgAdmin.editableCell),
|
||||
subnode: (_.isString(s.model) && s.model in pgBrowser.Nodes) ?
|
||||
pgBrowser.Nodes[s.model].model : s.model,
|
||||
canAdd: (mode == 'properties' ? false : evalASFunc(s.canAdd)),
|
||||
canEdit: (mode == 'properties' ? false : evalASFunc(s.canEdit)),
|
||||
canDelete: (mode == 'properties' ? false : evalASFunc(s.canDelete)),
|
||||
|
||||
disabled: (disabled ? true : evalASFunc(s.disabled)),
|
||||
editable: (disabled ? false : pgAdmin.editableCell),
|
||||
subnode: ((_.isString(s.model) && s.model in pgBrowser.Nodes) ?
|
||||
pgBrowser.Nodes[s.model].model : s.model),
|
||||
canAdd: (disabled ? false : evalASFunc(s.canAdd)),
|
||||
canEdit: (disabled ? false : evalASFunc(s.canEdit)),
|
||||
canDelete: (disabled ? false : evalASFunc(s.canDelete)),
|
||||
mode: mode,
|
||||
control: control,
|
||||
cell: cell
|
||||
cell: cell,
|
||||
node_info: node_info,
|
||||
});
|
||||
delete o.id;
|
||||
|
||||
|
@ -155,7 +155,7 @@ SET bytea_output=escape;
|
||||
|
||||
if status:
|
||||
mgr.ver = res
|
||||
mgr.sversion = int(pg_conn.server_version)
|
||||
mgr.sversion = pg_conn.server_version
|
||||
else:
|
||||
self.conn.close()
|
||||
self.conn = None
|
||||
@ -178,13 +178,10 @@ WHERE db.datname = current_database()""")
|
||||
if 'password' in kwargs:
|
||||
mgr.password = kwargs['password']
|
||||
|
||||
if 'modules' in kwargs and isinstance(kwargs['modules'], list):
|
||||
for m in sorted(
|
||||
kwargs['modules'], key=lambda module: module.priority
|
||||
):
|
||||
if m.instanceOf(mgr.ver):
|
||||
mgr.server_type = m.type
|
||||
mgr.module = m
|
||||
if 'server_types' in kwargs and isinstance(kwargs['server_types'], list):
|
||||
for st in kwargs['server_types']:
|
||||
if st.instanceOf(mgr.ver):
|
||||
mgr.server_type = st.stype
|
||||
break
|
||||
|
||||
return True, None
|
||||
@ -380,9 +377,6 @@ class ServerManager(object):
|
||||
And, acts as connection manager for that particular session.
|
||||
"""
|
||||
def __init__(self, server):
|
||||
self.module = None
|
||||
self.ver = None
|
||||
self.sversion = None
|
||||
self.connections = dict()
|
||||
|
||||
self.update(server)
|
||||
@ -394,10 +388,10 @@ class ServerManager(object):
|
||||
self.module = None
|
||||
self.ver = None
|
||||
self.sversion = None
|
||||
self.server_type = None
|
||||
self.password = None
|
||||
|
||||
self.sid = server.id
|
||||
self.stype = None
|
||||
self.host = server.host
|
||||
self.port = server.port
|
||||
self.db = server.maintenance_db
|
||||
|
Loading…
Reference in New Issue
Block a user