From d56ddb9fa4ad0976333763369726de522f24cfb4 Mon Sep 17 00:00:00 2001 From: Murtuza Zabuawala Date: Sat, 26 Dec 2015 16:15:12 +0530 Subject: [PATCH] Adding the SQL tab for the nodes, with 'hasSQL' property set to true, in create/edit mode. It will fetch the modified sql using the 'msql' url specific to that node. Also, modified by Ashesh before committing it. i.e. Added code comments, cleanup code for the control, etc. --- .../browser/templates/browser/js/browser.js | 4 +- .../browser/templates/browser/js/node.js | 2 +- web/pgadmin/static/js/backform.pgadmin.js | 163 +++++++++++++++--- 3 files changed, 146 insertions(+), 23 deletions(-) diff --git a/web/pgadmin/browser/templates/browser/js/browser.js b/web/pgadmin/browser/templates/browser/js/browser.js index f44b7db96..08ee23946 100644 --- a/web/pgadmin/browser/templates/browser/js/browser.js +++ b/web/pgadmin/browser/templates/browser/js/browser.js @@ -649,7 +649,9 @@ OWNER TO helpdesk;\n'; messages: { 'server_lost': '{{ _('Connection to the server has been lost!') }}', 'click_for_detailed_msg': '{{ _('%s

click here for details!') }}', - 'general_cateogty': '{{ _('General') }}' + 'general_cateogty': '{{ _('General') }}', + 'SQL_TAB': '{{ _('SQL') }}', + 'SQL_NO_CHANGE': '\n -- ' + '{{ _('Nothing changed') }}' } }); diff --git a/web/pgadmin/browser/templates/browser/js/node.js b/web/pgadmin/browser/templates/browser/js/node.js index 798af106d..8b64f33e3 100644 --- a/web/pgadmin/browser/templates/browser/js/node.js +++ b/web/pgadmin/browser/templates/browser/js/node.js @@ -115,7 +115,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) { onChangeCallback: callback }), info = this.getTreeNodeHierarchy.apply(this, [item]), - groups = Backform.generateViewSchema(info, newModel, type); + groups = Backform.generateViewSchema(info, newModel, type, this, node); // 'schema' has the information about how to generate the form. if (groups) { diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js index f8e3ca160..40001c18f 100644 --- a/web/pgadmin/static/js/backform.pgadmin.js +++ b/web/pgadmin/static/js/backform.pgadmin.js @@ -10,11 +10,11 @@ // Set up Backform appropriately for the environment. Start with AMD. if (typeof define === 'function' && define.amd) { - define(['underscore', 'jquery', 'backbone', 'backform', 'backgrid', 'pgadmin.backgrid'], - function(_, $, Backbone, Backform, Backgrid) { + define(['underscore', 'jquery', 'backbone', 'backform', 'backgrid', 'codemirror', 'pgadmin.backgrid', 'codemirror.sql'], + function(_, $, Backbone, Backform, Backgrid, CodeMirror) { // Export global even in AMD case in case this script is loaded with // others that may still expect a global Backform. - return factory(root, _, $, Backbone, Backform, Backgrid); + return factory(root, _, $, Backbone, Backform, Backgrid, CodeMirror); }); // Next for Node.js or CommonJS. jQuery may not be needed as a module. @@ -24,14 +24,15 @@ Backbone = require('backbone') || root.Backbone, Backform = require('backform') || root.Backform, Backgrid = require('backgrid') || root.Backgrid; + CodeMirror = require('codemirror') || root.CodeMirror; pgAdminBackgrid = require('pgadmin.backgrid'); - factory(root, _, $, Backbone, Backform, Backgrid); + factory(root, _, $, Backbone, Backform, Backgrid, CodeMirror); // Finally, as a browser global. } else { - factory(root, root._, (root.jQuery || root.Zepto || root.ender || root.$), root.Backbone, root.Backform, root.Backgrid); + factory(root, root._, (root.jQuery || root.Zepto || root.ender || root.$), root.Backbone, root.Backform, root.Backgrid, root.CodeMirror); } -}(this, function(root, _, $, Backbone, Backform, Backgrid) { +}(this, function(root, _, $, Backbone, Backform, Backgrid, CodeMirror) { var pgAdmin = (window.pgAdmin = window.pgAdmin || {}); @@ -312,7 +313,7 @@ .appendTo(this.$el); _.each(this.schema, function(o) { - var el = $((tmpls['panel'])(_.extend(o, {'tabIndex': idx++}))) + var el = $((tmpls['panel'])(_.extend(o, {'tabIndex': idx}))) .appendTo(tabContent) .removeClass('collapse').addClass('collapse'), h = $((tmpls['header'])(o)).appendTo(tabHead); @@ -320,22 +321,27 @@ o.fields.each(function(f) { var cntr = new (f.get("control")) ({ field: f, - model: m + model: m, + dialog: self, + tabIndex: idx }); el.append(cntr.render().$el); controls.push(cntr); }); - tabHead.find('a[data-toggle="tab"]').on('hidden.bs.tab', function() { - self.hidden_tab = $(this).data('tabIndex'); - }); - tabHead.find('a[data-toggle="tab"]').on('shown.bs.tab', function() { - self.shown_tab = $(this).data('tabIndex'); - m.trigger('pg-property-tab-changed', { - 'collection': m.collection, 'model': m, - 'index': m.collection && m.collection.models ? _.indexOf(m.collection.models, m) : 0, - 'shown': self.shown_tab, 'hidden': self.hidden_tab - }); - }); + idx++; + tabHead.find('a[data-toggle="tab"]').off( + 'shown.bs.tab' + ).off('hidden.bs.tab').on( + 'hidden.bs.tab', function() { + self.hidden_tab = $(this).data('tabIndex'); + }).on('shown.bs.tab', function() { + var that = this; + self.shown_tab = $(that).data('tabIndex'); + m.trigger('pg-property-tab-changed', { + 'model': m, 'shown': self.shown_tab, 'hidden': self.hidden_tab, + 'tab': that + }); + }); }); var makeActive = tabHead.find('[id="' + c + '"]').first(); @@ -826,12 +832,111 @@ } }); + /* + * SQL Tab Control for showing the modified SQL for the node with the + * property 'hasSQL' is set to true. + * + * When the user clicks on the SQL tab, we will send the modified data to the + * server and fetch the SQL for it. + */ + var SqlTabControl = Backform.SqlTabControl = Backform.Control.extend({ + defaults: { + label: "", + controlsClassName: "pgadmin-controls col-sm-12", + extraClasses: [], + helpMessage: null + }, + template: _.template([ + '
', + ' ', + ' <% if (helpMessage && helpMessage.length) { %>', + ' <%=helpMessage%>', + ' <% } %>', + '
' + ].join("\n")), + /* + * Initialize the SQL Tab control properly + */ + initialize: function(o) { + Backform.Control.prototype.initialize.apply(this, arguments); + + // Save the required information for using it later. + this.dialog = o.dialog; + this.tabIndex = o.tabIndex; + + /* + * We will listen to the tab change event to check, if the SQL tab has + * been clicked or, not. + */ + this.model.on('pg-property-tab-changed', this.onTabChange, this); + }, + getValueFromDOM: function() { + return this.formatter.toRaw(this.$el.find("textarea").val(), this.model); + }, + render: function() { + // Use the Backform Control's render function + Backform.Control.prototype.render.apply(this, arguments); + + var sqlTab = CodeMirror.fromTextArea( + (this.$el.find("textarea")[0]), { + lineNumbers: true, + mode: "text/x-sql", + readOnly: true + }); + this.sqlTab = sqlTab; + return this; + }, + onTabChange: function() { + + // Fetch the information only if the SQL tab is visible at the moment. + if (this.dialog && this.dialog.shown_tab == this.tabIndex) { + + // We will send request to sever only if something is changed in model + if(_.size(this.model.sessAttrs)) { + + var self = this, + node = self.field.get('schema_node'), + msql_url = node.generate_url.apply( + node, [ + null, 'msql', this.field.get('node_data'), true, + this.field.get('node_info') + ]); + + + // Fetching the modified SQL + self.model.trigger('pgadmin-view:msql:fetching', self.method, node); + + $.ajax({ + url: msql_url, + type: 'GET', + cache: false, + data: self.model.toJSON(true) + }).done(function(res) { + self.sqlTab.clearHistory(); + self.sqlTab.setValue(res.data); + }).fail(function() { + self.model.trigger('pgadmin-view:msql:error', self.method, node, arguments); + }).always(function() { + self.model.trigger('pgadmin-view:msql:fetched', self.method, node, arguments); + }); + } else { + this.sqlTab.clearHistory(); + this.sqlTab.setValue(window.pgAdmin.Browser.messages.SQL_NO_CHANGE); + } + } + }, + remove: function() { + this.model.off('pg-property-tab-changed', this.onTabChange, this); + Backform.Control.__super__.remove.apply(this, arguments); + } +}); + /////// // Generate a schema (as group members) based on the model's schema // // It will be used by the grid, properties, and dialog view generation // functions. - var generateViewSchema = Backform.generateViewSchema = function(node_info, Model, mode) { + var generateViewSchema = Backform.generateViewSchema = function(node_info, Model, mode, node, treeData) { var proto = (Model && Model.prototype) || Model, schema = (proto && proto.schema), groups, pgBrowser = window.pgAdmin.Browser; @@ -870,7 +975,9 @@ (server_info.version >= s.min_version)) && (_.isUndefined(s.max_version) ? true : (server_info.version <= s.max_version)))), - disabled = ((mode == 'properties') || !ver_in_limit); + disabled = ((mode == 'properties') || !ver_in_limit), + schema_node = (s.node && _.isString(s.node) && + s.node in pgBrowser.Nodes && pgBrowser.Nodes[s.node]) || node; var o = _.extend(_.clone(s), { name: s.id, @@ -889,6 +996,7 @@ control: control, cell: cell, node_info: node_info, + schema_node: schema_node, visible: (mode == 'properties'? (ver_in_limit ? (s.version || true) : false) : s.version || true) @@ -906,6 +1014,19 @@ if (_.isEmpty(groups)) { return null; } + if (node && node.hasSQL && (mode == 'create' || mode == 'edit')) { + groups[pgBrowser.messages.SQL_TAB] = [{ + name: 'sql', + visible: true, + disabled: false, + type: 'text', + control: 'sql-tab', + node_info: node_info, + schema_node: node, + node_data: treeData + }]; + } + } return groups; }