Hi Dave/Ronan, On Mon, Apr 20, 2015 at 4:10 PM, Dave Page <dp...@pgadmin.org> wrote:
> On Mon, Apr 20, 2015 at 10:52 AM, Ronan Dunklau > <ronan.dunk...@dalibo.com> wrote: > >> Ronan; can you update the test, help and about modules as well please? > > > > Done, please find attached a new patch for that. Ashesh, once you're > done with > > what you are doing now, feel free to ask me for any help needed to > integrate > > this after the fact. > > Thanks. > Thanks - It looks good to me. (And, attached patch is based on that.) > > >> > snippets of javsacript generated by the server. I feel like this > apporach > >> > is extremely fragile. Even before the patch, most of the tree actions > >> > were not working properly. > >> > >> That's odd - they all worked for me > > > > Adding a server is not functional, as well as adding a server group. > > Server groups should be fully functional. Adding a server isn't - > that's what Ashesh is investigating backbone.js for. > It is now fully functional as it was earlier with the attached patch. I am still working on the backbone.js. I am trying to make it general, so that - we can fit it in both properties pane, and dialog both together. In order to achieve, I have made a class NodeView (inherited from flask's view), just like the MethodView. Flask's MethodView is good to achieve CRUD functionality. Browser Tree Node (PostgreSQL object) requires more than just CRUD. i.e. - CRUD (Create, Read, Update & Delete) - Reversed Engineered SQL for the object - Modified Query in edit mode i.e. ALTER TABLE ... - Statistics - List of dependents - List of dependencies - Children node list This class can be inherited to achieve the different routes for each of the object types/collections. OPERATION | URL | Method ---------------+------------------------+-------- List | /obj/[Parent URL]/ | GET Properties | /obj/[Parent URL]/id | GET Create | /obj/[Parent URL]/ | POST Delete | /obj/[Parent URL]/id | DELETE Update | /obj/[Parent URL]/id | PUT SQL (Reversed | /sql/[Parent URL]/id | GET Engineering) | SQL (Modified | /sql/[Parent URL]/id | POST Properties) | Statistics | /stats/[Parent URL]/id | GET Dependencies | /deps/[Parent URL]/id | GET Dependents | /deps/[Parent URL]/id | POST Children Nodes | /nodes/[Parent URL]/id | GET NOTE: Parent URL can be seen as the path to identify the particular node. i.e. In order to identify the TABLE object, we requires information about the server -> database -> schema objects. Hence, the Parent URL for the TABLE object will be something like this as below: <int:sid>/<str:database>/<str:schema> I already did that for ServerGroup, and Server nodes. Attached patch is still in work in progress, and based on Ranon's latest patch. (So - in order to apply my patch, you should apply Ronan's latest patch first, and then mine.) -- Thanks & Regards, Ashesh Vashi EnterpriseDB INDIA: Enterprise PostgreSQL Company <http://www.enterprisedb.com> *http://www.linkedin.com/in/asheshvashi* <http://www.linkedin.com/in/asheshvashi> > >> > noticed) feel once again not really robust. All this widget assembly > is > >> > done "ad-hoc". > >> > >> How would you expect it to be done? > > > > In my opinion, it should either be done by using a set of widgets already > > designed to work together (think of wxwidgets, but for the web), using > one of > > the frameworks I mentioned before. Or alternatively, by developing the > glue > > between those widgets ourselves, using something like Backbone to wrap > those > > libraries into nice views able to play together. > > The problem is that I haven't found any OSS frameworks that provide > anything like the capabilities we have by using ad-hoc components. > There is nothing at all that comes close to the functionality (and > look/feel) of wcDocker, CodeMirror, AlertifyJS and aciTree that I've > found, let alone in a single framework. I've spent a *lot* of time > researching that, and trying to find components that give us what > we're going to need. > > > +1 for that. As for the extensibility, how is it expected for someone to > > provide a plugin ? Should he write a module that is supposed to be > installed > > in the pgadmin directory directly ? Using the modular approach proposed > by > > distutils/setuptools ? Plugins seems to be installed into the pgadmin > package > > directly, which is maybe not the most convenient way to manage > third-party > > modules. > > The current plugin mechanism is documented, but the basic premise is > that you can add a new module or node by dropping a Python package in > the right directory, without having to edit any configuration or code. > That is particularly important for tree nodes where the directory > structure is used to define the tree structure, to avoid having parent > nodes needing to have any pre-knowledge of what their children will > be. > > If you have better ideas of how to do that, I'm happy to hear them. I > do need to avoid long, drawn out discussions and rewrites though; I > can only justify putting significant EDB resources into the project if > we continue to move forwards at a reasonable speed. > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company >
diff --git a/web/pgAdmin4.py b/web/pgAdmin4.py index 9d2cff2..237cb32 100644 --- a/web/pgAdmin4.py +++ b/web/pgAdmin4.py @@ -50,8 +50,8 @@ if not os.path.isfile(config.SQLITE_PATH): # Create the app! app = create_app() -#if config.DEBUG: -# app.debug = True +if config.DEBUG: + app.debug = True # Start the web server. The port number should have already been set by the # runtime if we're running in desktop mode, otherwise we'll just use the diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py index e340c83..ae42104 100644 --- a/web/pgadmin/browser/__init__.py +++ b/web/pgadmin/browser/__init__.py @@ -21,25 +21,23 @@ MODULE_NAME = 'browser' class BrowserModule(PgAdminModule): - def get_own_stylesheets(self): stylesheets = [] # Add browser stylesheets for (endpoint, filename) in [ ('static', 'css/codemirror/codemirror.css'), - ('static', 'css/wcDocker/theme.css'), ('static', 'css/jQuery-contextMenu/jquery.contextMenu.css'), - ('browser.static', 'css/browser.css'), - ('browser.static', 'css/aciTree/css/aciTree.css') + ('static', 'css/wcDocker/wcDockerSkeleton.css' if \ + current_app.debug else \ + 'css/wcDocker/wcDockerSkeleton.min.css'), + ('static', 'css/wcDocker/theme.css'), + ('browser.static', 'css/aciTree/css/aciTree.css'), ]: stylesheets.append(url_for(endpoint, filename=filename)) stylesheets.append(url_for('browser.browser_css')) - if current_app.debug: - stylesheets.append(url_for('static', filename='css/wcDocker/wcDockerSkeleton.css')) - else: - stylesheets.append(url_for('static', filename='css/wcDocker/wcDockerSkeleton.min.css')) return stylesheets + def get_own_javascripts(self): scripts = [] for (endpoint, filename) in [ @@ -74,7 +72,7 @@ class BrowserPluginModule(PgAdminModule): def __init__(self, import_name, **kwargs): kwargs.setdefault("url_prefix", self.node_path) - kwargs.setdefault("static_url_path", '') + kwargs.setdefault("static_url_path", 'static') super(BrowserPluginModule, self).__init__("NODE-%s" % self.node_type, import_name, **kwargs) @@ -95,8 +93,8 @@ class BrowserPluginModule(PgAdminModule): Returns a snippet of css to include in the page """ # TODO: move those methods to BrowserModule subclass ? - return render_template("browser/css/node.css", - node_type=self.node_type) + return [render_template("browser/css/node.css", + node_type=self.node_type)] @abstractmethod def get_nodes(self): @@ -137,11 +135,12 @@ def browser_js(): snippets = [] for submodule in current_blueprint.submodules: snippets.extend(submodule.jssnippets) - return make_response(render_template( - 'browser/js/browser.js', - layout=layout, - jssnippets=snippets), - 200, {'Content-Type': 'application/x-javascript'}) + return make_response( + render_template( + 'browser/js/browser.js', + layout=layout, + jssnippets=snippets), + 200, {'Content-Type': 'application/x-javascript'}) @blueprint.route("/browser.css") @login_required @@ -150,9 +149,9 @@ def browser_css(): snippets = [] for submodule in current_blueprint.submodules: snippets.extend(submodule.csssnippets) - return make_response(render_template('browser/css/browser.css', - snippets=snippets), - 200, {'Content-Type': 'text/css'}) + return make_response( + render_template('browser/css/browser.css', snippets=snippets), + 200, {'Content-Type': 'text/css'}) @blueprint.route("/nodes/") diff --git a/web/pgadmin/browser/server_groups/__init__.py b/web/pgadmin/browser/server_groups/__init__.py index bfcc7f3..b5a4167 100644 --- a/web/pgadmin/browser/server_groups/__init__.py +++ b/web/pgadmin/browser/server_groups/__init__.py @@ -18,10 +18,10 @@ from pgadmin.utils.ajax import make_json_response from pgadmin.browser import BrowserPluginModule from pgadmin.utils.menu import MenuItem from pgadmin.settings.settings_model import db, ServerGroup +from pgadmin.browser.utils import generate_browser_node import config - class ServerGroupModule(BrowserPluginModule): NODE_TYPE = "server-group" @@ -65,18 +65,20 @@ class ServerGroupModule(BrowserPluginModule): # TODO: Move this JSON generation to a Server method # this code is duplicated somewhere else for group in groups: - yield { - "id": "%s/%d" % (self.node_type, group.id), - "label": group.name, - "icon": "icon-%s" % self.node_type, - "inode": True, - "_type": self.node_type - } + yield generate_browser_node( + "%d" % (group.id), + group.name, + "icon-%s" % self.node_type, + True, + self.node_type) @property def node_type(self): return self.NODE_TYPE + @property + def node_path(self): + return '/browser/' + self.node_type class ServerGroupMenuItem(MenuItem): @@ -99,109 +101,142 @@ class ServerGroupPluginModule(BrowserPluginModule): pass -# Initialise the module + @property + def node_path(self): + return '/browser/' + self.node_type + + blueprint = ServerGroupModule( __name__, static_url_path='') -@blueprint.route("/<server_group>") -@login_required -def get_nodes(server_group): - """Build a list of treeview nodes from the child nodes.""" - nodes = [] - for module in current_blueprint.submodules: - nodes.extend(module.get_nodes(server_group=server_group)) - return make_json_response(data=nodes) - - -@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 = gettext('No server group name was specified') - - if success == 1: - data['id'] = servergroup.id - data['name'] = servergroup.name - - return make_json_response(success=success, - errormsg=errormsg, - info=traceback.format_exc(), - result=request.form, - data=data) - -@blueprint.route('/delete/', methods=['POST']) -@login_required -def delete(): - """Delete a server group node in the settings database""" - success = 1 - errormsg = '' - - if request.form['id'] != '': +# Initialise the module +from pgadmin.browser.utils import NodeView + + +class ServerGroupView(NodeView): + + node_type = ServerGroupModule.NODE_TYPE + parent_ids = [] + ids = [{'type':'int', 'id':'gid'}] + + + def list(self): + res = [] + for g in blueprint.get_nodes(): + res.append(g) + return make_json_response(result=res) + + + def delete(self, gid): + """Delete a server group node in the settings database""" + # There can be only one record at most - servergroup = ServerGroup.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first() + servergroup = ServerGroup.query.filter_by( + user_id=current_user.id, + id=gid) if servergroup is None: - success = 0 - errormsg = gettext('The specified server group could not be found.') + return make_json_response( + success=0, + errormsg=gettext('The specified server group could not be found.')) else: try: db.session.delete(servergroup) db.session.commit() except Exception as e: - success = 0 - errormsg = e.message + return make_json_response(success=0, errormsg=e.message) - else: - success = 0 - errormsg = gettext('No server group was specified.') + return make_json_response(result=request.form) - return make_json_response(success=success, - errormsg=errormsg, - info=traceback.format_exc(), - result=request.form) -@blueprint.route('/rename/', methods=['POST']) -@login_required -def rename(): - """Rename a server group node in the settings database""" - success = 1 - errormsg = '' + def update(self, gid): + """Update the server-group properties""" - if request.form['id'] != '': # There can be only one record at most - servergroup = ServerGroup.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first() + servergroup = ServerGroup.query.filter_by( + user_id=current_user.id, + id=gid).first() if servergroup is None: - success = 0 - errormsg = gettext('The specified server group could not be found.') + return make_json_response( + success=0, + errormsg=gettext('The specified server group could not be found.')) else: try: - servergroup.name = request.form['name'] + if 'name' in request.form: + servergroup.name = request.form['name'] db.session.commit() except Exception as e: - success = 0 - errormsg = e.message + return make_json_response(success=0, errormsg=e.message) - else: - success = 0 - errormsg = gettext('No server group was specified.') + return make_json_response(result=request.form) - return make_json_response(success=success, - errormsg=errormsg, - info=traceback.format_exc(), - result=request.form) + + def properties(self, gid): + """Update the server-group properties""" + + # There can be only one record at most + sg = ServerGroup.query.filter_by( + user_id=current_user.id, + id=gid).first() + data = {} + + if sg is None: + return make_json_response( + success=0, + errormsg=gettext('The specified server group could not be found.')) + else: + return make_json_response(data={'id': sg.id, 'name': sg.name}) + + + def create(self): + data = [] + if request.form['name'] != '': + servergroup = ServerGroup( + user_id=current_user.id, + name=request.form['name']) + try: + db.session.add(servergroup) + db.session.commit() + + data['id'] = servergroup.id + data['name'] = servergroup.name + except Exception as e: + return make_json_response(success=0, errormsg=e.message) + + else: + return make_json_response( + success=0, + errormsg=gettext('No server group name was specified')) + + return make_json_response(data=data) + + + def nodes(self, gid): + """Build a list of treeview nodes from the child nodes.""" + nodes = [] + for module in blueprint.submodules: + nodes.extend(module.get_nodes(server_group=gid)) + return make_json_response(data=nodes) + + + def sql(self, gid): + return make_json_response(data='') + + + def modified_sql(self, gid): + return make_json_response(data='') + + + def statistics(self, gid): + return make_json_response(data='') + + + def dependencies(self, gid): + return make_json_response(data='') + + + def dependents(self, gid): + return make_json_response(data='') + + +ServerGroupView.register_node_view(blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py index 855bb19..68e501c 100644 --- a/web/pgadmin/browser/server_groups/servers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/__init__.py @@ -9,9 +9,10 @@ from flask import render_template, request from pgadmin.browser.server_groups import ServerGroupPluginModule from flask.ext.security import login_required, current_user -from pgadmin.settings.settings_model import db, Server +from pgadmin.settings.settings_model import db, Server, ServerGroup from pgadmin.utils.menu import MenuItem from pgadmin.utils.ajax import make_json_response +from pgadmin.browser.utils import generate_browser_node, NodeView import traceback from flask.ext.babel import gettext @@ -30,13 +31,13 @@ class ServerModule(ServerGroupPluginModule): # TODO: Move this JSON generation to a Server method for server in servers: - yield { - "id": "%s/%d" % (NODE_TYPE, server.id), - "label": server.name, - "icon": "icon-%s" % NODE_TYPE, - "inode": True, - "_type": NODE_TYPE - } + yield generate_browser_node( + "%d" % server.id, + server.name, + "icon-%s" % self.NODE_TYPE, + True, + self.NODE_TYPE + ) def get_own_menuitems(self): return { @@ -49,13 +50,13 @@ class ServerModule(ServerGroupPluginModule): name="create_server", label=gettext('Server...'), priority=50, - function='create_server') + function='create_server(item)') ], 'context_items': [ ServerMenuItem(name='delete_server', label=gettext('Delete server'), priority=50, - onclick='drop_server'), + onclick='drop_server(item)'), ServerMenuItem(name='rename_server', label=gettext('Rename server...'), priority=60, @@ -75,98 +76,224 @@ class ServerMenuItem(MenuItem): kwargs.setdefault("type", ServerModule.NODE_TYPE) super(ServerMenuItem, self).__init__(**kwargs) + blueprint = ServerModule(__name__) -@blueprint.route('/add/', methods=['POST']) -@login_required -def add(): - """Add a server node to the settings database""" - success = 1 - errormsg = '' - data = {} - - success = False - errormsg = '' - if request.form['name'] != '': - server = Server(user_id=current_user.id, name=request.form['name']) - try: - db.session.add(server) - db.session.commit() - success = True - except Exception as e: - errormsg = e.message - else: - errormsg = gettext('No server name was specified') - - if success: - data['id'] = server.id - data['name'] = server.name - - return make_json_response(success=success, - errormsg=errormsg, - info=traceback.format_exc(), - result=request.form, - data=data) - -@blueprint.route('/delete/', methods=['POST']) -@login_required -def delete(): - """Delete a server node in the settings database""" - success = 1 - errormsg = '' - - if request.form['id'] != '': - # There can be only one record at most - servergroup = Server.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first() +class ServerNode(NodeView): + + node_type = ServerModule.NODE_TYPE + parent_ids = [{'type':'int', 'id':'gid'}] + ids = [{'type':'int', 'id':'sid'}] + + + def list(self, gid): + res = [] + """Return a JSON document listing the server groups for the user""" + servers = Server.query.filter_by(user_id=current_user.id, + servergroup_id=gid) + + for server in servers: + res.append( + generate_browser_node( + "%d/%d" % (gid, server.id), + server.name, + "icon-%s" % NODE_TYPE, + True, + NODE_TYPE + ) + ) + return make_json_response(result=res) + + + def delete(self, gid, sid): + """Delete a server node in the settings database""" + server = Server.query.filter_by(user_id=current_user.id, id=sid) + + # TODO:: A server, which is connected, can not be deleted if server is None: - success = 0 - errormsg = gettext('The specified server could not be found.') + return make_json_response( + success=0, + errormsg=gettext( + 'The specified server could not be found.\n' + 'Does the user have permission to access the ' + 'server?' + ) + ) else: try: db.session.delete(server) db.session.commit() except Exception as e: - success = 0 - errormsg = e.message + return make_json_response( + success=0, + errormsg=e.message) - else: - success = 0 - errormsg = gettext('No server was specified.') + return make_json_response(success=success, + errormsg=errormsg, + info=traceback.format_exc()) - return make_json_response(success=success, - errormsg=errormsg, - info=traceback.format_exc(), - result=request.form) -@blueprint.route('/rename/', methods=['POST']) -@login_required -def rename(): - """Rename a server node in the settings database""" - success = 1 - errormsg = '' + def update(self, gid, sid): + """Update the server settings""" + server = Server.query.filter_by(user_id=current_user.id, id=sid).first() - if request.form['id'] != '': - # There can be only one record at most - servergroup = Server.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first() + if server is None: + return make_json_response( + success=0, + errormsg=gettext("Couldn't find the given server.") + ) + + # TODO:: + # Not all parameters can be modified, while the server is connected + possible_args = { + 'name': 'name', + 'host': 'host', + 'port': 'port', + 'db': 'maintenance_db', + 'username': 'username', + 'sslmode': 'sslmode', + 'gid': 'servergroup_id' + } + + idx = 0 + for arg in possible_args: + if arg in request.form: + server[possible_args[arg]] = request.form[arg] + idx += 1 + + if idx == 0: + return make_json_response( + success=0, + errormsg=gettext('No parameters were chagned!') + ) + + try: + db.session.commit() + except Exception as e: + return make_json_response( + success=0, + errormsg=e.message + ) + + return make_json_response( + success=1, + data={ + 'id': server.id, + 'gid': server.servergroup_id + } + ) + + + def properties(self, gid, sid): + """Return list of attributes of a server""" + server = Server.query.filter_by( + user_id=current_user.id, + id=sid).first() if server is None: - success = 0 - errormsg = gettext('The specified server could not be found.') - else: - try: - server.name = request.form['name'] - db.session.commit() - except Exception as e: - success = 0 - errormsg = e.message - - else: - success = 0 - errormsg = gettext('No server was specified.') - - return make_json_response(success=success, - errormsg=errormsg, - info=traceback.format_exc(), - result=request.form) + return make_json_response( + success=0, + errormsg=gettext("Couldn't find the given server") + ) + + sg = ServerGroup.query.filter_by( + user_id=current_user.id, + id=server.servergroup_id + ).first() + + return make_json_response( + success=1, + data={ + 'id':server.id, + 'name':server.name, + 'host':server.host, + 'port':server.port, + 'db':server.maintenance_db, + 'username':server.username, + 'gid':server.servergroup_id, + 'group-name':sg.name + } + ) + + + def create(self, gid): + """Add a server node to the settings database""" + required_args = [ + 'name', + 'host', + 'port', + 'db', + 'username', + 'sslmode' + ] + + for arg in required_args: + if arg not in request.form: + return make_json_response( + success=0, + errormsg=gettext( + "Couldn't find the required parameter (%s)." % arg + ) + ) + + server = Server( + user_id=current_user.id, + servergroup_id=gid, + name=request.form['name'], + host=request.form['host'], + port=request.form['port'], + maintenance_db=request.form['db'], + username=request.form['username'], + sslmode=request.form['username'] + ) + + try: + db.session.add(server) + db.session.commit() + except Exception as e: + return make_json_response( + success=0, + errormsg=e.message + ) + + return make_json_response(success=1, + data={ + 'id': server.id, + 'name': server.name, + 'gid': gid + }) + + + def nodes(self, gid, sid): + """Build a list of treeview nodes from the child nodes.""" + nodes = [] + # TODO:: + # We can have nodes for the server object, only when + # the server is connected at the moment. + for module in blueprint.submodules: + nodes.extend(module.get_nodes(server=sid)) + return make_json_response(data=nodes) + + + def sql(self, gid, sid): + return make_json_response(data='') + + + def modified_sql(self, gid, sid): + return make_json_response(data='') + + + def statistics(self, gid, sid): + return make_json_response(data='') + + + def dependencies(self, gid, sid): + return make_json_response(data='') + + + def dependents(self, gid, sid): + return make_json_response(data='') + +ServerNode.register_node_view(blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js b/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js index 822441d..5361229 100644 --- a/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js +++ b/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js @@ -1,11 +1,18 @@ // Add a server -function create_server() { +function create_server(item) { var alert = alertify.prompt( '{{ _('Create a server') }}', '{{ _('Enter a name for the new server') }}', '', function(evt, value) { - $.post("{{ url_for('NODE-server.add') }}", { name: value }) + var d = tree.itemData(item); + if (d._type != 'server-group') { + d = tree.itemData(tree.parent(item)); + } + $.post( + "{{ url_for('browser.index') }}server/obj/" + d.refid + '/', + { name: value } + ) .done(function(data) { if (data.success == 0) { report_error(data.errormsg, data.info); @@ -38,8 +45,10 @@ function drop_server(item) { '{{ _('Are you sure you wish to drop the server "{0}"?') }}'.replace('{0}', tree.getLabel(item)), function() { var id = tree.getId(item).split('/').pop() - $.post("{{ url_for('NODE-server.delete') }}", { id: id }) - .done(function(data) { + $.ajax({ + url:"{{ url_for('browser.index') }}" + d._type + "/obj/" + d.refid, + type:'DELETE', + success: function(data) { if (data.success == 0) { report_error(data.errormsg, data.info); } else { @@ -53,7 +62,7 @@ function drop_server(item) { } } } - ) + }) }, null ) @@ -66,17 +75,20 @@ function rename_server(item) { '{{ _('Enter a new name for the server') }}', tree.getLabel(item), function(evt, value) { - var id = tree.getId(item).split('/').pop() - $.post("{{ url_for('NODE-server.rename') }}", { id: id, name: value }) - .done(function(data) { + var d = tree.itemData(item); + $.ajax({ + url:"{{ url_for('browser.index') }}" + d._type + "/obj/" + d.refid, + type:'PUT', + params: {name: value}, + success: function(data) { if (data.success == 0) { report_error(data.errormsg, data.info); } else { tree.setLabel(item, { label: value }); } } - ) + }) }, null ) -} \ No newline at end of file +} diff --git a/web/pgadmin/browser/server_groups/templates/server_groups/server_groups.js b/web/pgadmin/browser/server_groups/templates/server_groups/server_groups.js index f1fa85d..a154012 100644 --- a/web/pgadmin/browser/server_groups/templates/server_groups/server_groups.js +++ b/web/pgadmin/browser/server_groups/templates/server_groups/server_groups.js @@ -5,7 +5,7 @@ function create_server_group() { '{{ _('Enter a name for the new server group') }}', '', function(evt, value) { - $.post("{{ url_for('NODE-server-group.add') }}", { name: value }) + $.post("{{ url_for('browser.index') }}server-group/obj/", { name: value }) .done(function(data) { if (data.success == 0) { report_error(data.errormsg, data.info); @@ -37,9 +37,11 @@ function drop_server_group(item) { '{{ _('Delete server group?') }}', '{{ _('Are you sure you wish to delete the server group "{0}"?') }}'.replace('{0}', tree.getLabel(item)), function() { - var id = tree.getId(item).split('/').pop() - $.post("{{ url_for('NODE-server-group.delete') }}", { id: id }) - .done(function(data) { + var d = tree.itemData(item); + $.ajax({ + url:"{{ url_for('browser.index') }}" + d._type + "/obj/" + d.refid, + type:'DELETE', + success: function(data) { if (data.success == 0) { report_error(data.errormsg, data.info); } else { @@ -53,7 +55,7 @@ function drop_server_group(item) { } } } - ) + }) }, null ) @@ -66,16 +68,19 @@ function rename_server_group(item) { '{{ _('Enter a new name for the server group') }}', tree.getLabel(item), function(evt, value) { - var id = tree.getId(item).split('/').pop() - $.post("{{ url_for('NODE-server-group.rename') }}", { id: id, name: value }) - .done(function(data) { + var d = tree.itemData(item); + $.ajax({ + url:"{{ url_for('browser.index') }}" + d._type + "/obj/" + d.refid, + type:'PUT', + params: { name: value }, + success: function(data) { if (data.success == 0) { report_error(data.errormsg, data.info); } else { tree.setLabel(item, { label: value }); } } - ) + }) }, null ) diff --git a/web/pgadmin/browser/templates/browser/css/node.css b/web/pgadmin/browser/templates/browser/css/node.css index 3fea074..da56d69 100644 --- a/web/pgadmin/browser/templates/browser/css/node.css +++ b/web/pgadmin/browser/templates/browser/css/node.css @@ -1,3 +1,3 @@ .icon-{{node_type}} { - background: url('{{ url_for('NODE-%s.static' % node_type, filename='img/%s.png' % node_type )}}') 0 0 no-repeat; + background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/%s.png' % node_type )}}') !important; } diff --git a/web/pgadmin/browser/templates/browser/js/browser.js b/web/pgadmin/browser/templates/browser/js/browser.js index e1aa05b..dbdf034 100644 --- a/web/pgadmin/browser/templates/browser/js/browser.js +++ b/web/pgadmin/browser/templates/browser/js/browser.js @@ -298,6 +298,12 @@ ALTER TABLE tickets_detail \n\ return $.parseJSON(payload).data; } } + }, + ajaxHook: function(item, settings) { + if (item != null) { + var d = this.itemData(item); + settings.url = '{{ url_for('browser.index') }}' + d._type + '/nodes/' + d.refid + } } }); tree = $('#tree').aciTree('api'); diff --git a/web/pgadmin/settings/settings_model.py b/web/pgadmin/settings/settings_model.py index 731137b..dcd6fb6 100644 --- a/web/pgadmin/settings/settings_model.py +++ b/web/pgadmin/settings/settings_model.py @@ -72,13 +72,28 @@ class Server(db.Model): """Define a registered Postgres server""" __tablename__ = 'server' id = db.Column(db.Integer, primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) - servergroup_id = db.Column(db.Integer, db.ForeignKey('servergroup.id'), nullable=False) + user_id = db.Column( + db.Integer, + db.ForeignKey('user.id'), + nullable=False + ) + servergroup_id = db.Column( + db.Integer, + db.ForeignKey('servergroup.id'), + nullable=False + ) name = db.Column(db.String(128), nullable=False) host = db.Column(db.String(128), nullable=False) - port = db.Column(db.Integer(), db.CheckConstraint('port >= 1024 AND port <= 65534'), nullable=False) + port = db.Column( + db.Integer(), + db.CheckConstraint('port >= 1024 AND port <= 65534'), + nullable=False) maintenance_db = db.Column(db.String(64), nullable=False) username = db.Column(db.String(64), nullable=False) - ssl_mode = db.Column(db.String(16), nullable=False) - - + ssl_mode = db.Column( + db.String(16), + db.CheckConstraint( + "ssl_mode IN ('allow', 'prefer', 'require', 'disable', 'verify-ca', 'verify-full')" + ), + nullable=False, + ) diff --git a/web/pgadmin/templates/base.html b/web/pgadmin/templates/base.html index 5a36182..300e888 100755 --- a/web/pgadmin/templates/base.html +++ b/web/pgadmin/templates/base.html @@ -15,25 +15,25 @@ <meta name="dcterms.dateCopyrighted" content="2014 - 2015"> <!-- Base template stylesheets --> - {% if config.DEBUG %}<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.css') }}" />{% else %}<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" />{% endif %} - {% if config.DEBUG %}<link rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/alertify.css') }}" />{% else %}<link rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/alertify.min.css') }}" />{% endif %} - {% if config.DEBUG %}<link rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/themes/bootstrap.css') }}" />{% else %}<link rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/themes/bootstrap.min.css') }}" />{% endif %} - {% if config.DEBUG %}<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-theme.min.css') }}">{% else %}<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-theme.min.css') }}">{% endif %} - <link rel="stylesheet" href="{{ url_for('static', filename='css/overrides.css') }}"> + <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.css' if config.DEBUG else 'css/bootstrap.min.css')}}"/> + <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/alertify.css' if config.DEBUG else 'css/alertifyjs/alertify.min.css') }}" /> + <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/themes/bootstrap.css' if config.DEBUG else 'css/alertifyjs/themes/bootstrap.min.css') }}" /> + <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-theme.min.css' if config.DEBUG else 'css/bootstrap-theme.css') }}"> + <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/overrides.css') }}"> <!-- View specified stylesheets --> {% for stylesheet in current_app.stylesheets %} - <link rel="stylesheet" href="{{ stylesheet }}"> + <link type="text/css" rel="stylesheet" href="{{ stylesheet }}"> {% endfor %} <!-- Base template scripts --> - <script src="{{ url_for('static', filename='js/modernizr-2.6.2-respond-1.1.0.min.js') }}"></script> - {% if config.DEBUG %}<script src="{{ url_for('static', filename='js/jquery-1.11.2.js') }}">{% else %}<script src="{{ url_for('static', filename='js/jquery-1.11.2.min.js') }}">{% endif %}</script> - {% if config.DEBUG %}<script src="{{ url_for('static', filename='js/bootstrap.js') }}">{% else %}<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}">{% endif %}</script> - {% if config.DEBUG %}<script src="{{ url_for('static', filename='js/alertifyjs/alertify.js') }}">{% else %}<script src="{{ url_for('static', filename='js/alertifyjs/alertify.min.js') }}">{% endif %}</script> - <script src="{{ url_for('static', filename='js/alertifyjs/pgadmin.defaults.js') }}"></script> + <script type="text/javascript" src="{{ url_for('static', filename='js/modernizr-2.6.2-respond-1.1.0.min.js') }}"></script> + <script type="text/javascript" src="{{ url_for('static', filename='js/jquery-1.11.2.js' if config.DEBUG else 'js/jquery-1.11.2.min.js') }}"></script> + <script type="text/javascript" src="{{ url_for('static', filename='js/bootstrap.js' if config.DEBUG else 'js/bootstrap.min.js') }}"></script> + <script type="text/javascript" src="{{ url_for('static', filename='js/alertifyjs/alertify.js' if config.DEBUG else 'js/alertifyjs/alertify.min.js') }}"></script> + <script type="text/javascript" src="{{ url_for('static', filename='js/alertifyjs/pgadmin.defaults.js') }}"></script> <!-- View specified scripts --> {% for script in current_app.javascripts %} - <script src="{{ script }}"></script> + <script type="text/javascript" src="{{ script }}"></script> {% endfor %} </head> <body> diff --git a/web/pgadmin/utils/ajax.py b/web/pgadmin/utils/ajax.py index 367c356..b5f938c 100644 --- a/web/pgadmin/utils/ajax.py +++ b/web/pgadmin/utils/ajax.py @@ -25,4 +25,4 @@ def make_json_response(success=1, errormsg='', info='', result={}, data={}): response = Response(response=json.dumps(doc), status=200, mimetype="text/json") - return response \ No newline at end of file + return response diff --git a/web/setup.py b/web/setup.py index c7398f5..22fbf24 100644 --- a/web/setup.py +++ b/web/setup.py @@ -66,6 +66,19 @@ def do_setup(): server_group = ServerGroup(user_id=user.id, name="Servers") db.session.merge(server_group) + # TODO:: Remove this server later + # It is here to demo the server listing is workig in + # browser tree. + server_group = ServerGroup.query.filter_by(name='Servers').first() + + server = Server( + user_id=user.id, servergroup_id=server_group.id, + name='PostgreSQL 9.3', host='localhost', port=3930, + maintenance_db='postgres', username='asheshvashi', + ssl_mode='prefer' + ) + db.session.merge(server) + # Set the schema version version = Version(name='ConfigDB', value=config.SETTINGS_SCHEMA_VERSION) db.session.merge(version) @@ -138,4 +151,4 @@ if os.path.isfile(config.SQLITE_PATH): do_upgrade() else: print "The configuration database %s does not exist.\nEntering initial setup mode...\n" % config.SQLITE_PATH - do_setup() \ No newline at end of file + do_setup()
-- Sent via pgadmin-hackers mailing list (pgadmin-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers