From 234efc3be7cbe3ef787d2aafe372149f51e99c59 Mon Sep 17 00:00:00 2001 From: Aditya Toshniwal Date: Fri, 23 Aug 2019 12:14:20 +0100 Subject: [PATCH] Don't wait for the database connection before rendering the Query Tool UI, for improved UX. Fixes #4453 In addition, unescape HTML entities in database names in the Query Tool title bar. Fixes #4584 --- docs/en_US/release_notes_4_13.rst | 2 + web/pgadmin/browser/utils.py | 24 ++++ web/pgadmin/static/js/sqleditor_utils.js | 19 +-- web/pgadmin/static/js/utils.js | 6 + web/pgadmin/tools/datagrid/__init__.py | 116 +++++----------- .../tools/datagrid/static/js/datagrid.js | 114 +++++---------- .../static/js/datagrid_panel_title.js | 2 +- .../tools/datagrid/static/js/show_data.js | 53 +++---- .../datagrid/static/js/show_query_tool.js | 28 ++-- .../datagrid/templates/datagrid/index.html | 29 ++-- .../tools/sqleditor/static/css/sqleditor.css | 4 + .../tools/sqleditor/static/img/loading.gif | Bin 0 -> 1728 bytes .../tools/sqleditor/static/js/sqleditor.js | 131 ++++++++++++------ .../tests/test_download_csv_query_tool.py | 11 +- .../sqleditor/tests/test_editor_history.py | 9 +- .../sqleditor/tests/test_encoding_charset.py | 10 +- .../sqleditor/tests/test_explain_plan.py | 9 +- .../sqleditor/tests/test_poll_query_tool.py | 9 +- .../tests/test_transaction_status.py | 8 +- .../tools/sqleditor/tests/test_view_data.py | 9 +- .../test_is_query_resultset_updatable.py | 8 +- .../utils/tests/test_save_changed_data.py | 8 +- .../javascript/datagrid/show_data_spec.js | 64 ++++----- .../datagrid/show_query_tool_spec.js | 41 +++--- web/regression/javascript/fake_endpoints.js | 1 + .../javascript/pgadmin_utils_spec.js | 9 +- .../javascript/sqleditor_utils_spec.js | 56 -------- web/yarn.lock | 6 +- 28 files changed, 337 insertions(+), 449 deletions(-) create mode 100644 web/pgadmin/tools/sqleditor/static/img/loading.gif diff --git a/docs/en_US/release_notes_4_13.rst b/docs/en_US/release_notes_4_13.rst index d06c4f263..4ac661577 100644 --- a/docs/en_US/release_notes_4_13.rst +++ b/docs/en_US/release_notes_4_13.rst @@ -9,6 +9,7 @@ This release contains a number of bug fixes and new features since the release o New features ************ +| `Issue #4453 `_ - Don't wait for the database connection before rendering the Query Tool UI, for improved UX. | `Issue #4651 `_ - Allow configuration options to be set from the environment in the container distribution. Housekeeping @@ -22,6 +23,7 @@ Bug fixes | `Issue #2706 `_ - Added ProjectSet icon for explain module. | `Issue #2828 `_ - Added Gather Merge, Named Tuple Store Scan and Table Function Scan icon for explain module. | `Issue #4419 `_ - Fix a debugger error when using Python 2.7. +| `Issue #4584 `_ - Unescape HTML entities in database names in the Query Tool title bar. | `Issue #4643 `_ - Fix Truncate option deselect issue for compound triggers. | `Issue #4644 `_ - Fix length and precision enable/disable issue when changing the data type for Domain node. | `Issue #4650 `_ - Fix SQL tab issue for Views. It's a regression of compound triggers. diff --git a/web/pgadmin/browser/utils.py b/web/pgadmin/browser/utils.py index 4c049bedb..2a17b3a2d 100644 --- a/web/pgadmin/browser/utils.py +++ b/web/pgadmin/browser/utils.py @@ -47,6 +47,30 @@ def underscore_escape(text): return text +def underscore_unescape(text): + """ + This function mimics the behaviour of underscore js unescape function + The html unescape by jinja is not compatible for underscore escape + function + :param text: input html text + :return: unescaped text + """ + html_map = { + "&": '&', + "<": '<', + ">": '>', + """: '"', + "`": '`', + "'": "'" + } + + # always replace & first + for c, r in html_map.items(): + text = text.replace(c, r) + + return text + + def is_version_in_range(sversion, min_ver, max_ver): assert (max_ver is None or isinstance(max_ver, int)) assert (min_ver is None or isinstance(min_ver, int)) diff --git a/web/pgadmin/static/js/sqleditor_utils.js b/web/pgadmin/static/js/sqleditor_utils.js index 9d14ac467..bd4356c02 100644 --- a/web/pgadmin/static/js/sqleditor_utils.js +++ b/web/pgadmin/static/js/sqleditor_utils.js @@ -73,6 +73,9 @@ define(['jquery', 'sources/gettext', 'sources/url_for'], return; } + if($status_el.hasClass('obtaining-conn')){ + return; + } let sqleditor_obj = target; // Start polling.. @@ -195,22 +198,6 @@ define(['jquery', 'sources/gettext', 'sources/url_for'], } return '1em'; }, - - removeSlashInTheString: (value) => { - let locationList = []; - let idx = 0; - while (value && value.indexOf('/') !== -1) { - locationList.push(value.indexOf('/') + idx); - value = value.replace('/', ''); - // No of slashes already removed, so we need to increment the - // index accordingly when adding into location list - idx++; - } - return { - 'slashLocations': locationList.join(','), - 'title': encodeURIComponent(value), - }; - }, }; return sqlEditorUtils; }); diff --git a/web/pgadmin/static/js/utils.js b/web/pgadmin/static/js/utils.js index fe9fd8ed6..1f15858d8 100644 --- a/web/pgadmin/static/js/utils.js +++ b/web/pgadmin/static/js/utils.js @@ -199,3 +199,9 @@ export function fully_qualify(pgBrowser, data, item) { return quote_ident(data._label); } } + +export function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +} diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py index e8779351d..f4597fc47 100644 --- a/web/pgadmin/tools/datagrid/__init__.py +++ b/web/pgadmin/tools/datagrid/__init__.py @@ -30,7 +30,7 @@ from pgadmin.utils.driver import get_driver from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost from pgadmin.utils.preferences import Preferences from pgadmin.settings import get_setting -from pgadmin.browser.utils import underscore_escape +from pgadmin.browser.utils import underscore_unescape query_tool_close_session_lock = Lock() @@ -114,13 +114,13 @@ def show_filter(): @blueprint.route( - '/initialize/datagrid/////' - '/', + '/initialize/datagrid////' + '///', methods=["PUT", "POST"], endpoint="initialize_datagrid" ) @login_required -def initialize_datagrid(cmd_type, obj_type, sgid, sid, did, obj_id): +def initialize_datagrid(trans_id, cmd_type, obj_type, sgid, sid, did, obj_id): """ This method is responsible for creating an asynchronous connection. After creating the connection it will instantiate and initialize @@ -183,9 +183,6 @@ def initialize_datagrid(cmd_type, obj_type, sgid, sid, did, obj_id): app.logger.error(e) return internal_server_error(errormsg=str(e)) - # Create a unique id for the transaction - trans_id = str(random.randint(1, 9999999)) - if 'gridData' not in session: sql_grid_data = dict() else: @@ -193,7 +190,7 @@ def initialize_datagrid(cmd_type, obj_type, sgid, sid, did, obj_id): # Use pickle to store the command object which will be used later by the # sql grid module. - sql_grid_data[trans_id] = { + sql_grid_data[str(trans_id)] = { # -1 specify the highest protocol version available 'command_obj': pickle.dumps(command_obj, -1) } @@ -203,51 +200,34 @@ def initialize_datagrid(cmd_type, obj_type, sgid, sid, did, obj_id): return make_json_response( data={ - 'gridTransId': trans_id + 'conn_id': conn_id } ) @blueprint.route( - '/panel///', - methods=["GET"], + '/panel/', + methods=["POST"], endpoint='panel' ) -def panel(trans_id, is_query_tool, editor_title): +def panel(trans_id): """ This method calls index.html to render the data grid. Args: trans_id: unique transaction id - is_query_tool: True if panel calls when query tool menu is clicked. - editor_title: Title of the editor """ - # Let's fetch Script type URL from request - if request.args and request.args['query_url'] != '': - sURL = request.args['query_url'] - else: - sURL = None - # Fetch server type from request - if request.args and request.args['server_type'] != '': - server_type = request.args['server_type'] - else: - server_type = None + url_params = None + if request.args: + url_params = {k: v for k, v in request.args.items()} - if request.args and 'server_ver' in request.args: - server_ver = request.args['server_ver'] - else: - server_ver = 0 - - # If title has slash(es) in it then replace it - if request.args and request.args['fslashes'] != '': - try: - fslashesList = request.args['fslashes'].split(',') - for idx in fslashesList: - idx = int(idx) - editor_title = editor_title[:idx] + '/' + editor_title[idx:] - except IndexError as e: - app.logger.exception(e) + if request.form: + url_params['title'] = request.form['title'] + if 'sql_filter' in request.form: + url_params['sql_filter'] = request.form['sql_filter'] + if 'query_url' in request.form: + url_params['query_url'] = request.form['query_url'] # We need client OS information to render correct Keyboard shortcuts user_agent = UserAgent(request.headers.get('User-Agent')) @@ -277,64 +257,43 @@ def panel(trans_id, is_query_tool, editor_title): # Fetch the server details bgcolor = None fgcolor = None - if 'gridData' in session and str(trans_id) in session['gridData']: - # Fetch the object for the specified transaction id. - # Use pickle.loads function to get the command object - session_obj = session['gridData'][str(trans_id)] - trans_obj = pickle.loads(session_obj['command_obj']) - s = Server.query.filter_by(id=trans_obj.sid).first() - if s and s.bgcolor: - # If background is set to white means we do not have to change - # the title background else change it as per user specified - # background - if s.bgcolor != '#ffffff': - bgcolor = s.bgcolor - fgcolor = s.fgcolor or 'black' + + s = Server.query.filter_by(id=url_params['sid']).first() + if s and s.bgcolor: + # If background is set to white means we do not have to change + # the title background else change it as per user specified + # background + if s.bgcolor != '#ffffff': + bgcolor = s.bgcolor + fgcolor = s.fgcolor or 'black' layout = get_setting('SQLEditor/Layout') - url_params = dict() - if is_query_tool == 'true': - url_params['sgid'] = trans_obj.sgid - url_params['sid'] = trans_obj.sid - url_params['did'] = trans_obj.did - else: - url_params['cmd_type'] = trans_obj.cmd_type - url_params['obj_type'] = trans_obj.object_type - url_params['sgid'] = trans_obj.sgid - url_params['sid'] = trans_obj.sid - url_params['did'] = trans_obj.did - url_params['obj_id'] = trans_obj.obj_id - return render_template( "datagrid/index.html", _=gettext, uniqueId=trans_id, - is_query_tool=is_query_tool, - editor_title=underscore_escape(editor_title), - script_type_url=sURL, is_desktop_mode=app.PGADMIN_RUNTIME, is_linux=is_linux_platform, - server_type=server_type, - server_ver=server_ver, + title=underscore_unescape(url_params['title']), + url_params=json.dumps(url_params), client_platform=user_agent.platform, bgcolor=bgcolor, fgcolor=fgcolor, - url_params=json.dumps(url_params), layout=layout, ) @blueprint.route( - '/initialize/query_tool///', + '/initialize/query_tool////', methods=["POST"], endpoint='initialize_query_tool_with_did' ) @blueprint.route( - '/initialize/query_tool//', + '/initialize/query_tool///', methods=["POST"], endpoint='initialize_query_tool' ) @login_required -def initialize_query_tool(sgid, sid, did=None): +def initialize_query_tool(trans_id, sgid, sid, did=None): """ This method is responsible for instantiating and initializing the query tool object. It will also create a unique @@ -346,16 +305,16 @@ def initialize_query_tool(sgid, sid, did=None): did: Database Id """ connect = True - reqArgs = None # Read the data if present. Skipping read may cause connection # reset error if data is sent from the client if request.data: - reqArgs = request.data + _ = request.data reqArgs = request.args if ('recreate' in reqArgs and reqArgs['recreate'] == '1'): connect = False + # Create asynchronous connection using random connection id. conn_id = str(random.randint(1, 9999999)) @@ -389,9 +348,6 @@ def initialize_query_tool(sgid, sid, did=None): app.logger.error(e) return internal_server_error(errormsg=str(e)) - # Create a unique id for the transaction - trans_id = str(random.randint(1, 9999999)) - if 'gridData' not in session: sql_grid_data = dict() else: @@ -404,7 +360,7 @@ def initialize_query_tool(sgid, sid, did=None): # Use pickle to store the command object which will be used # later by the sql grid module. - sql_grid_data[trans_id] = { + sql_grid_data[str(trans_id)] = { # -1 specify the highest protocol version available 'command_obj': pickle.dumps(command_obj, -1) } @@ -414,7 +370,7 @@ def initialize_query_tool(sgid, sid, did=None): return make_json_response( data={ - 'gridTransId': trans_id, + 'connId': str(conn_id), 'serverVersion': manager.version, } ) diff --git a/web/pgadmin/tools/datagrid/static/js/datagrid.js b/web/pgadmin/tools/datagrid/static/js/datagrid.js index a405b7de9..f12ab7a79 100644 --- a/web/pgadmin/tools/datagrid/static/js/datagrid.js +++ b/web/pgadmin/tools/datagrid/static/js/datagrid.js @@ -13,10 +13,10 @@ define('pgadmin.datagrid', [ 'sources/sqleditor_utils', 'backbone', 'tools/datagrid/static/js/show_data', 'tools/datagrid/static/js/show_query_tool', 'pgadmin.browser.toolbar', - 'tools/datagrid/static/js/datagrid_panel_title', 'wcdocker', + 'tools/datagrid/static/js/datagrid_panel_title', 'sources/utils', 'wcdocker', ], function( gettext, url_for, $, _, alertify, pgAdmin, codemirror, sqlEditorUtils, - Backbone, showData, showQueryTool, toolBar, panelTitleFunc + Backbone, showData, showQueryTool, toolBar, panelTitleFunc, commonUtils ) { // Some scripts do export their object in the window only. // Generally the one, which do no have AMD support. @@ -52,7 +52,6 @@ define('pgadmin.datagrid', [ self.preferences = pgBrowser.get_preferences_for_module('sqleditor'); }); - // Define list of nodes on which view data option appears var supported_nodes = [ 'table', 'view', 'mview', @@ -195,97 +194,48 @@ define('pgadmin.datagrid', [ // This is a callback function to show data when user click on menu item. show_data_grid: function(data, i) { - showData.showDataGrid(this, pgBrowser, alertify, data, i); + const transId = commonUtils.getRandomInt(1, 9999999); + showData.showDataGrid(this, pgBrowser, alertify, data, i, transId); }, // This is a callback function to show filtered data when user click on menu item. show_filtered_row: function(data, i) { - showData.showDataGrid(this, pgBrowser, alertify, data, i, true, this.preferences); + const transId = commonUtils.getRandomInt(1, 9999999); + showData.showDataGrid(this, pgBrowser, alertify, data, i, transId, true, this.preferences); }, // This is a callback function to show query tool when user click on menu item. show_query_tool: function(url, aciTreeIdentifier) { - showQueryTool.showQueryTool(this, pgBrowser, alertify, url, aciTreeIdentifier); + const transId = commonUtils.getRandomInt(1, 9999999); + showQueryTool.showQueryTool(this, pgBrowser, alertify, url, aciTreeIdentifier, transId); }, - create_transaction: function(baseUrl, target, is_query_tool, server_type, sURL, panel_title, sql_filter, recreate) { + launch_grid: function(trans_id, panel_url, is_query_tool, panel_title, sURL=null, sql_filter=null) { var self = this; - target = target || self; - if (recreate) { - baseUrl += '?recreate=1'; + + let queryToolForm = ` +
+ `; + + if(sURL){ + queryToolForm +=``; + } + if(sql_filter) { + queryToolForm +=``; } - /* Send the data only if required. Sending non required data may - * cause connection reset error if data is not read by flask server - */ - let reqData = null; - if(sql_filter != '') { - reqData = JSON.stringify(sql_filter); - } - - $.ajax({ - url: baseUrl, - method: 'POST', - dataType: 'json', - data: reqData, - contentType: 'application/json', - }) - .done(function(res) { - res.data.is_query_tool = is_query_tool; - res.data.server_type = server_type; - res.data.sURL = sURL; - res.data.panel_title = panel_title; - target.trigger('pgadmin-datagrid:transaction:created', res.data); - }) - .fail(function(xhr) { - if (target !== self) { - if(xhr.status == 503 && xhr.responseJSON.info != undefined && - xhr.responseJSON.info == 'CONNECTION_LOST') { - setTimeout(function() { - target.handle_connection_lost(true, xhr); - }); - return; - } - } - - try { - var err = JSON.parse(xhr.responseText); - alertify.alert(gettext('Query Tool initialization error'), - err.errormsg - ); - } catch (e) { - alertify.alert(gettext('Query Tool initialization error'), - e.statusText - ); - } - }); - }, - launch_grid: function(trans_obj) { - var self = this, - panel_title = trans_obj.panel_title, - grid_title = trans_obj.panel_title; - - // Open the panel if frame is initialized - let titileForURLObj = sqlEditorUtils.removeSlashInTheString(grid_title); - var url_params = { - 'trans_id': trans_obj.gridTransId, - 'is_query_tool': trans_obj.is_query_tool, - 'editor_title': titileForURLObj.title, - }, - baseUrl = url_for('datagrid.panel', url_params) + - '?' + 'query_url=' + encodeURI(trans_obj.sURL) + - '&server_type=' + encodeURIComponent(trans_obj.server_type) + - '&server_ver=' + trans_obj.serverVersion+ - '&fslashes=' + titileForURLObj.slashLocations; + queryToolForm +=` +
+ + `; if (self.preferences.new_browser_tab) { - var newWin = window.open(baseUrl, '_blank'); - - // add a load listener to the window so that the title gets changed on page load - newWin.addEventListener('load', function() { - newWin.document.title = panel_title; - }); - + var newWin = window.open('', '_blank'); + newWin.document.write(queryToolForm); + newWin.document.title = panel_title; } else { /* On successfully initialization find the dashboard panel, * create new panel and add it to the dashboard panel. @@ -294,13 +244,13 @@ define('pgadmin.datagrid', [ var queryToolPanel = pgBrowser.docker.addPanel('frm_datagrid', wcDocker.DOCK.STACKED, propertiesPanel[0]); // Set panel title and icon - panelTitleFunc.setQueryToolDockerTitle(queryToolPanel, trans_obj.is_query_tool, panel_title); + panelTitleFunc.setQueryToolDockerTitle(queryToolPanel, is_query_tool, panel_title); queryToolPanel.focus(); // Listen on the panel closed event. queryToolPanel.on(wcDocker.EVENT.CLOSED, function() { $.ajax({ - url: url_for('datagrid.close', {'trans_id': trans_obj.gridTransId}), + url: url_for('datagrid.close', {'trans_id': trans_id}), method: 'DELETE', }); }); @@ -325,7 +275,7 @@ define('pgadmin.datagrid', [ frame.onLoaded(()=>{ $spinner_el.remove(); }); - frame.openURL(baseUrl); + frame.openHTML(queryToolForm); } } }, 100); diff --git a/web/pgadmin/tools/datagrid/static/js/datagrid_panel_title.js b/web/pgadmin/tools/datagrid/static/js/datagrid_panel_title.js index ec3a23068..8c9b999c4 100644 --- a/web/pgadmin/tools/datagrid/static/js/datagrid_panel_title.js +++ b/web/pgadmin/tools/datagrid/static/js/datagrid_panel_title.js @@ -52,6 +52,6 @@ export function setQueryToolDockerTitle(panel, is_query_tool, panel_title, is_fi panel_icon = 'fa fa-bolt'; } - panel.title(''+_.escape(panel_title)+''); + panel.title(''+ panel_title +''); panel.icon(panel_icon); } diff --git a/web/pgadmin/tools/datagrid/static/js/show_data.js b/web/pgadmin/tools/datagrid/static/js/show_data.js index 547daf77b..c2fbc7bee 100644 --- a/web/pgadmin/tools/datagrid/static/js/show_data.js +++ b/web/pgadmin/tools/datagrid/static/js/show_data.js @@ -20,6 +20,7 @@ export function showDataGrid( alertify, connectionData, aciTreeIdentifier, + transId, filter=false, preferences=null ) { @@ -42,43 +43,25 @@ export function showDataGrid( return; } - const baseUrl = generateUrl(connectionData, node.getData(), parentData); - const grid_title = generateDatagridTitle(pgBrowser, aciTreeIdentifier); - + const gridUrl = generateUrl(transId, connectionData, node.getData(), parentData); + const queryToolTitle = generateDatagridTitle(pgBrowser, aciTreeIdentifier); if(filter) { initFilterDialog(alertify, pgBrowser, preferences); const validateUrl = generateFilterValidateUrl(node.getData(), parentData); let okCallback = function(sql) { - datagrid.create_transaction( - baseUrl, - null, - 'false', - parentData.server.server_type, - '', - grid_title, - sql, - false - ); + datagrid.launch_grid(transId, gridUrl, false, queryToolTitle, null, sql); }; $.get(url_for('datagrid.filter'), function(data) { - alertify.filterDialog(`Data Filter - ${grid_title}`, data, validateUrl, preferences, okCallback) + alertify.filterDialog(`Data Filter - ${queryToolTitle}`, data, validateUrl, preferences, okCallback) .resizeTo(pgBrowser.stdW.sm,pgBrowser.stdH.sm); } ); } else { - datagrid.create_transaction( - baseUrl, - null, - 'false', - parentData.server.server_type, - '', - grid_title, - '' - ); + datagrid.launch_grid(transId, gridUrl, false, queryToolTitle); } } @@ -96,17 +79,21 @@ export function retrieveNameSpaceName(parentData) { return ''; } -function generateUrl(connectionData, nodeData, parentData) { - const url_params = { - 'cmd_type': connectionData.mnuid, - 'obj_type': nodeData._type, - 'sgid': parentData.server_group._id, - 'sid': parentData.server._id, - 'did': parentData.database._id, - 'obj_id': nodeData._id, - }; +function generateUrl(trans_id, connectionData, nodeData, parentData) { + let url_endpoint = url_for('datagrid.panel', { + 'trans_id': trans_id, + }); - return url_for('datagrid.initialize_datagrid', url_params); + url_endpoint += `?is_query_tool=${false}` + +`&cmd_type=${connectionData.mnuid}` + +`&obj_type=${nodeData._type}` + +`&obj_id=${nodeData._id}` + +`&sgid=${parentData.server_group._id}` + +`&sid=${parentData.server._id}` + +`&did=${parentData.database._id}` + +`&server_type=${parentData.server.server_type}`; + + return url_endpoint; } function generateFilterValidateUrl(nodeData, parentData) { diff --git a/web/pgadmin/tools/datagrid/static/js/show_query_tool.js b/web/pgadmin/tools/datagrid/static/js/show_query_tool.js index 4b42c7a67..b7a8d0338 100644 --- a/web/pgadmin/tools/datagrid/static/js/show_query_tool.js +++ b/web/pgadmin/tools/datagrid/static/js/show_query_tool.js @@ -16,19 +16,21 @@ function hasDatabaseInformation(parentData) { return parentData.database; } -function generateUrl(parentData) { - let url_endpoint = 'datagrid.initialize_query_tool'; - let url_params = { - 'sgid': parentData.server_group._id, - 'sid': parentData.server._id, - }; +function generateUrl(trans_id, title, parentData) { + let url_endpoint = url_for('datagrid.panel', { + 'trans_id': trans_id, + }); + + url_endpoint += `?is_query_tool=${true}` + +`&sgid=${parentData.server_group._id}` + +`&sid=${parentData.server._id}` + +`&server_type=${parentData.server.server_type}`; if (hasDatabaseInformation(parentData)) { - url_params['did'] = parentData.database._id; - url_endpoint = 'datagrid.initialize_query_tool_with_did'; + url_endpoint += `&did=${parentData.database._id}`; } - return url_for(url_endpoint, url_params); + return url_endpoint; } function hasServerInformations(parentData) { @@ -40,7 +42,7 @@ function generateTitle(pgBrowser, aciTreeIdentifier) { return baseTitle; } -export function showQueryTool(datagrid, pgBrowser, alertify, url, aciTreeIdentifier) { +export function showQueryTool(datagrid, pgBrowser, alertify, url, aciTreeIdentifier, transId) { const sURL = url || ''; const queryToolTitle = generateTitle(pgBrowser, aciTreeIdentifier); @@ -60,9 +62,7 @@ export function showQueryTool(datagrid, pgBrowser, alertify, url, aciTreeIdentif return; } - const baseUrl = generateUrl(parentData); + const gridUrl = generateUrl(transId, queryToolTitle, parentData); - datagrid.create_transaction( - baseUrl, null, 'true', - parentData.server.server_type, sURL, queryToolTitle, '', false); + datagrid.launch_grid(transId, gridUrl, true, queryToolTitle, sURL); } diff --git a/web/pgadmin/tools/datagrid/templates/datagrid/index.html b/web/pgadmin/tools/datagrid/templates/datagrid/index.html index b1be514d7..3b3e3508d 100644 --- a/web/pgadmin/tools/datagrid/templates/datagrid/index.html +++ b/web/pgadmin/tools/datagrid/templates/datagrid/index.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% block title %}{{ config.APP_NAME }} - Datagrid{% endblock %} +{% block title %}{{title}}{% endblock %} {% block body %}