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
This commit is contained in:
Aditya Toshniwal 2019-08-23 12:14:20 +01:00 committed by Dave Page
parent 25f85fe123
commit 234efc3be7
28 changed files with 337 additions and 449 deletions

View File

@ -9,6 +9,7 @@ This release contains a number of bug fixes and new features since the release o
New features
************
| `Issue #4453 <https://redmine.postgresql.org/issues/4453>`_ - Don't wait for the database connection before rendering the Query Tool UI, for improved UX.
| `Issue #4651 <https://redmine.postgresql.org/issues/4651>`_ - Allow configuration options to be set from the environment in the container distribution.
Housekeeping
@ -22,6 +23,7 @@ Bug fixes
| `Issue #2706 <https://redmine.postgresql.org/issues/2706>`_ - Added ProjectSet icon for explain module.
| `Issue #2828 <https://redmine.postgresql.org/issues/2828>`_ - Added Gather Merge, Named Tuple Store Scan and Table Function Scan icon for explain module.
| `Issue #4419 <https://redmine.postgresql.org/issues/4419>`_ - Fix a debugger error when using Python 2.7.
| `Issue #4584 <https://redmine.postgresql.org/issues/4584>`_ - Unescape HTML entities in database names in the Query Tool title bar.
| `Issue #4643 <https://redmine.postgresql.org/issues/4643>`_ - Fix Truncate option deselect issue for compound triggers.
| `Issue #4644 <https://redmine.postgresql.org/issues/4644>`_ - Fix length and precision enable/disable issue when changing the data type for Domain node.
| `Issue #4650 <https://redmine.postgresql.org/issues/4650>`_ - Fix SQL tab issue for Views. It's a regression of compound triggers.

View File

@ -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 = {
"&amp;": '&',
"&lt;": '<',
"&gt;": '>',
"&quot;": '"',
"&#96;": '`',
"&#x27;": "'"
}
# 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))

View File

@ -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;
});

View File

@ -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;
}

View File

@ -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/<int:cmd_type>/<obj_type>/<int:sgid>/<int:sid>/'
'<int:did>/<int:obj_id>',
'/initialize/datagrid/<int:trans_id>/<int:cmd_type>/<obj_type>/'
'<int:sgid>/<int:sid>/<int:did>/<int:obj_id>',
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/<int:trans_id>/<is_query_tool>/<path:editor_title>',
methods=["GET"],
'/panel/<int:trans_id>',
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/<int:sgid>/<int:sid>/<int:did>',
'/initialize/query_tool/<int:trans_id>/<int:sgid>/<int:sid>/<int:did>',
methods=["POST"], endpoint='initialize_query_tool_with_did'
)
@blueprint.route(
'/initialize/query_tool/<int:sgid>/<int:sid>',
'/initialize/query_tool/<int:trans_id>/<int:sgid>/<int:sid>',
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,
}
)

View File

@ -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 = `
<form id="queryToolForm" action="${panel_url}" method="post">
<input id="title" name="title" hidden />`;
if(sURL){
queryToolForm +=`<input name="query_url" value="${sURL}" hidden />`;
}
if(sql_filter) {
queryToolForm +=`<textarea name="sql_filter" hidden>${sql_filter}</textarea>`;
}
/* 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 +=`
</form>
<script>
document.getElementById("title").value = "${panel_title}";
document.getElementById("queryToolForm").submit();
</script>
`;
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);

View File

@ -52,6 +52,6 @@ export function setQueryToolDockerTitle(panel, is_query_tool, panel_title, is_fi
panel_icon = 'fa fa-bolt';
}
panel.title('<span title="'+_.escape(panel_tooltip)+'">'+_.escape(panel_title)+'</span>');
panel.title('<span title="'+ panel_tooltip +'">'+ panel_title +'</span>');
panel.icon(panel_icon);
}

View File

@ -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) {

View File

@ -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);
}

View File

@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}{{ config.APP_NAME }} - Datagrid{% endblock %}
{% block title %}{{title}}{% endblock %}
{% block body %}
<style>
body {padding: 0px;}
@ -228,7 +228,7 @@
</button>
<button id="btn-flash" data-test-selector="execute-refresh-button" type="button" class="btn btn-sm btn-secondary" style="width: 32px;"
title=""
tabindex="0">
tabindex="0" disabled>
<i class="fa fa-bolt sql-icon-lg" aria-hidden="true"></i>
</button>
<button id="btn-query-dropdown" type="button" class="btn btn-sm btn-secondary dropdown-toggle dropdown-toggle-split"
@ -256,12 +256,12 @@
<button id="btn-explain" type="button" class="btn btn-sm btn-secondary"
title=""
accesskey=""
tabindex="0">
tabindex="0" disabled>
<i class="fa fa-hand-pointer-o sql-icon-lg" aria-hidden="true"></i>
</button>
<button id="btn-explain-analyze" type="button" class="btn btn-sm btn-secondary"
title=""
accesskey="">
accesskey="" disabled>
<i class="fa fa-list-alt sql-icon-lg" aria-hidden="true"></i>
</button>
<button id="btn-explain-options-dropdown" type="button" class="btn btn-sm btn-secondary dropdown-toggle dropdown-toggle-split"
@ -358,20 +358,20 @@
data-panel-visible="visible"
accesskey=""
tabindex="0">
<i class="fa-custom fa-query-tool-disconnected" aria-hidden="true"
<i class="fa-custom fa-query-tool-disconnected obtaining-conn" aria-hidden="true"
title="">
</i>
</div>
<div class="editor-title"
style="background-color: {% if fgcolor %}{{ bgcolor or '#FFFFFF' }}{% endif %}; color: {% if fgcolor %}{{ fgcolor }}{% endif %};"></div>
style="background-color: {% if fgcolor %}{{ bgcolor or '#FFFFFF' }}{% endif %}; color: {% if fgcolor %}{{ fgcolor }}{% endif %};">&nbsp;</div>
</div>
<div id="editor-panel" tabindex="0">
<div id="fetching_data" class="pg-sp-container sql-editor-busy-fetching d-none">
<div id="fetching_data" class="pg-sp-container sql-editor-busy-fetching">
<div class="pg-sp-content">
<div class="row">
<div class="col-12 pg-sp-icon sql-editor-busy-icon"></div>
</div>
<div class="row"><div class="col-12 pg-sp-text sql-editor-busy-text">{{ _('Loading {0} v{1}...').format(config.APP_NAME, config.APP_VERSION) }}</div></div>
<div class="row"><div class="col-12 pg-sp-text sql-editor-busy-text">{{ _('Loading...') }}</div></div>
</div>
</div>
</div>
@ -412,13 +412,13 @@
// Listen on events to show/hide loading-icon and change messages.
sqlEditorController.on('pgadmin-sqleditor:loading-icon:message', function(msg) {
msgDiv.text(msg);
msgDiv.text(msg);
}).on('pgadmin-sqleditor:loading-icon:show', function(msg) {
loadingDiv.removeClass('d-none');
msgDiv.text(msg);
}).on('pgadmin-sqleditor:loading-icon:hide', function() {
loadingDiv.addClass('d-none');
});
}).on('pgadmin-sqleditor:loading-icon:hide', function() {
loadingDiv.addClass('d-none');
});
{% if script_type_url %}
var script_type_url = '{{ script_type_url }}';
{% else %}
@ -427,13 +427,8 @@
// Start the query tool.
sqlEditorController.start(
{{ uniqueId }},
{{ is_query_tool }},
"{{ editor_title }}",
script_type_url,
"{{ server_type }}",
{{ url_params|safe}},
'{{ layout|safe }}',
{{ server_ver }}
);
});
{% endblock %}

View File

@ -291,6 +291,10 @@ input.editor-checkbox:focus {
background-image: url('../img/disconnect.svg');
}
.connection_status .obtaining-conn {
background-image: url('../img/loading.gif') !important;
}
.icon-commit, .icon-rollback, .icon-save-data-changes, .icon-view-data {
display: inline-block;
align-content: center;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -83,7 +83,6 @@ define('tools.querytool', [
this.handler.preferences = this.preferences;
this.connIntervalId = null;
this.layout = opts.layout;
this.set_server_version(opts.server_ver);
},
// Bind all the events
@ -188,12 +187,14 @@ define('tools.querytool', [
});
},
set_editor_title: function(title) {
this.$el.find('.editor-title').text(title);
},
// This function is used to render the template.
render: function() {
var self = this;
$('.editor-title').text(_.unescape(self.editor_title));
// Updates connection status flag
self.gain_focus = function() {
setTimeout(function() {
@ -207,7 +208,6 @@ define('tools.querytool', [
}, 100);
};
// Create main wcDocker instance
self.docker = new wcDocker(
'#editor-panel', {
@ -338,6 +338,10 @@ define('tools.querytool', [
});
self.render_history_grid();
pgBrowser.Events.on('pgadmin:query_tool:connected:'+self.handler.transId, ()=>{
self.fetch_query_history();
});
queryToolNotifications.renderNotificationsGrid(self.notifications_panel);
var text_container = $('<textarea id="sql_query_tool" tabindex="-1"></textarea>');
@ -1327,6 +1331,24 @@ define('tools.querytool', [
}
},
fetch_query_history: function() {
let self = this;
$.ajax({
url: url_for('sqleditor.get_query_history', {
'trans_id': self.handler.transId,
}),
method: 'GET',
contentType: 'application/json',
}).done(function(res) {
res.data.result.map((entry) => {
let newEntry = JSON.parse(entry);
newEntry.start_time = new Date(newEntry.start_time);
self.history_collection.add(newEntry);
});
}).fail(function() {
/* history fetch fail should not affect query tool */
});
},
/* This function is responsible to create and render the
* new backgrid for the history tab.
*/
@ -1363,25 +1385,6 @@ define('tools.querytool', [
});
}
// Make ajax call to get history data
$.ajax({
url: url_for('sqleditor.get_query_history', {
'trans_id': self.handler.transId,
}),
method: 'GET',
contentType: 'application/json',
})
.done(function(res) {
res.data.result.map((entry) => {
let newEntry = JSON.parse(entry);
newEntry.start_time = new Date(newEntry.start_time);
self.history_collection.add(newEntry);
});
})
.fail(function() {
/* history fetch fail should not affect query tool */
});
if(!self.handler.is_query_tool) {
self.historyComponent.setEditorPref({'copy_to_editor':false});
}
@ -2016,13 +2019,13 @@ define('tools.querytool', [
},
initTransaction: function() {
var url_endpoint;
if (this.is_query_tool) {
var self = this, url_endpoint;
if (self.is_query_tool) {
url_endpoint = 'datagrid.initialize_query_tool';
// If database not present then use Maintenance database
// We will handle this at server side
if (this.url_params.did) {
if (self.url_params.did) {
url_endpoint = 'datagrid.initialize_query_tool_with_did';
}
@ -2030,10 +2033,25 @@ define('tools.querytool', [
url_endpoint = 'datagrid.initialize_datagrid';
}
var baseUrl = url_for(url_endpoint, this.url_params);
var baseUrl = url_for(url_endpoint, {
...self.url_params,
'trans_id': self.transId,
});
Datagrid.create_transaction(baseUrl, this, this.is_query_tool,
this.server_type, '', '', '', true);
$.ajax({
url: baseUrl,
type: 'POST',
data: self.is_query_tool?null:JSON.stringify(self.url_params.sql_filter),
contentType: 'application/json',
}).done((res)=>{
pgBrowser.Events.trigger(
'pgadmin:query_tool:connected:' + self.transId, res.data
);
}).fail((xhr, status, error)=>{
pgBrowser.Events.trigger(
'pgadmin:query_tool:connected_fail:' + self.transId, xhr, error
);
});
},
handle_connection_lost: function(create_transaction, xhr) {
@ -2138,12 +2156,10 @@ define('tools.querytool', [
* call the render method of the grid view to render the backgrid
* header and loading icon and start execution of the sql query.
*/
start: function(transId, is_query_tool, editor_title, script_type_url,
server_type, url_params, layout, server_ver
) {
start: function(transId, url_params, layout) {
var self = this;
self.is_query_tool = is_query_tool;
self.is_query_tool = url_params.is_query_tool==='true'?true:false;
self.rows_affected = 0;
self.marked_line_no = 0;
self.has_more_rows = false;
@ -2151,9 +2167,8 @@ define('tools.querytool', [
self.close_on_save = false;
self.close_on_idle_transaction = false;
self.last_transaction_status = -1;
self.server_type = server_type;
self.server_type = url_params.server_type;
self.url_params = url_params;
self.script_type_url = script_type_url;
self.is_transaction_buttons_disabled = true;
// We do not allow to call the start multiple times.
@ -2164,16 +2179,48 @@ define('tools.querytool', [
el: self.container,
handler: self,
layout: layout,
server_ver: server_ver,
});
self.transId = self.gridView.transId = transId;
self.gridView.editor_title = _.unescape(editor_title);
self.gridView.current_file = undefined;
// Render the header
self.gridView.render();
self.trigger('pgadmin-sqleditor:loading-icon:hide');
self.gridView.set_editor_title(`(${gettext('Obtaining connection...')} ${_.unescape(url_params.title)}`);
let afterConn = function() {
let enableBtns = [];
if(self.is_query_tool){
enableBtns = ['#btn-flash', '#btn-explain', '#btn-explain-analyze'];
} else {
enableBtns = ['#btn-flash'];
}
enableBtns.forEach((selector)=>{
$(selector).prop('disabled', false);
});
$('#btn-conn-status i').removeClass('obtaining-conn');
self.gridView.set_editor_title(_.unescape(url_params.title));
};
pgBrowser.Events.on('pgadmin:query_tool:connected:' + transId, afterConn);
pgBrowser.Events.on('pgadmin:query_tool:connected_fail:' + transId, afterConn);
pgBrowser.Events.on('pgadmin:query_tool:connected:' + transId, (res_data)=>{
self.gridView.set_server_version(res_data.serverVersion);
});
pgBrowser.Events.on('pgadmin:query_tool:connected_fail:' + transId, (xhr, error)=>{
alertify.pgRespErrorNotify(xhr, error);
});
self.initTransaction();
/* wcDocker focuses on window always, and all our shortcuts are
* bind to editor-panel. So when we use wcDocker focus, editor-panel
* loses focus and events don't work.
@ -2187,9 +2234,9 @@ define('tools.querytool', [
if (self.is_query_tool) {
// Fetch the SQL for Scripts (eg: CREATE/UPDATE/DELETE/SELECT)
// Call AJAX only if script type url is present
if (script_type_url) {
if (url_params.query_url) {
$.ajax({
url: script_type_url,
url: url_params.query_url,
type:'GET',
})
.done(function(res) {
@ -2224,7 +2271,9 @@ define('tools.querytool', [
cm.className += ' bg-gray-lighter opacity-5 hide-cursor-workaround';
}
self.disable_tool_buttons(true);
self.execute_data_query();
pgBrowser.Events.on('pgadmin:query_tool:connected:'+ transId,()=>{
self.execute_data_query();
});
}
},
@ -3334,7 +3383,7 @@ define('tools.querytool', [
// Find the title of the visible panel
_.each(window.top.pgAdmin.Browser.docker.findPanels('frm_datagrid'), function(p) {
if (p.isVisible()) {
self.gridView.panel_title = $(p._title).text();
self.gridView.panel_title = $(p._title).html();
}
});

View File

@ -27,7 +27,7 @@ class TestDownloadCSV(BaseTestGenerator):
'Download csv URL with valid query',
dict(
sql='SELECT 1 as "A",2 as "B",3 as "C"',
init_url='/datagrid/initialize/query_tool/{0}/{1}/{2}',
init_url='/datagrid/initialize/query_tool/{0}/{1}/{2}/{3}',
donwload_url="/sqleditor/query_tool/download/{0}",
output_columns='"A","B","C"',
output_values='1,2,3',
@ -39,7 +39,7 @@ class TestDownloadCSV(BaseTestGenerator):
'Download csv URL with wrong TX id',
dict(
sql='SELECT 1 as "A",2 as "B",3 as "C"',
init_url='/datagrid/initialize/query_tool/{0}/{1}/{2}',
init_url='/datagrid/initialize/query_tool/{0}/{1}/{2}/{3}',
donwload_url="/sqleditor/query_tool/download/{0}",
output_columns=None,
output_values=None,
@ -51,7 +51,7 @@ class TestDownloadCSV(BaseTestGenerator):
'Download csv URL with wrong query',
dict(
sql='SELECT * FROM this_table_does_not_exist',
init_url='/datagrid/initialize/query_tool/{0}/{1}/{2}',
init_url='/datagrid/initialize/query_tool/{0}/{1}/{2}/{3}',
donwload_url="/sqleditor/query_tool/download/{0}",
output_columns=None,
output_values=None,
@ -81,13 +81,12 @@ class TestDownloadCSV(BaseTestGenerator):
raise Exception("Could not connect to the database.")
# Initialize query tool
self.trans_id = str(random.randint(1, 9999999))
url = self.init_url.format(
test_utils.SERVER_GROUP, self._sid, self._did)
self.trans_id, test_utils.SERVER_GROUP, self._sid, self._did)
response = self.tester.post(url)
self.assertEquals(response.status_code, 200)
response_data = json.loads(response.data.decode('utf-8'))
self.trans_id = response_data['data']['gridTransId']
# If invalid tx test then make the Tx id invalid so that tests fails
if not self.is_valid_tx:
self.trans_id = self.trans_id + '007'

View File

@ -14,6 +14,7 @@ from pgadmin.browser.server_groups.servers.databases.tests import utils as \
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
import random
class TestEditorHistory(BaseTestGenerator):
@ -68,14 +69,12 @@ class TestEditorHistory(BaseTestGenerator):
raise Exception("Could not connect to the database.")
# Initialize query tool
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}'.format(
utils.SERVER_GROUP, self.server_id, self.db_id)
self.trans_id = str(random.randint(1, 9999999))
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}/{3}'.format(
self.trans_id, utils.SERVER_GROUP, self.server_id, self.db_id)
response = self.tester.post(url)
self.assertEquals(response.status_code, 200)
response_data = json.loads(response.data.decode('utf-8'))
self.trans_id = response_data['data']['gridTransId']
def runTest(self):
url = '/sqleditor/query_history/{0}'.format(self.trans_id)

View File

@ -11,7 +11,6 @@
from pgadmin.utils.route import BaseTestGenerator
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from regression import parent_node_dict
from regression.python_test_utils import test_utils
import json
from pgadmin.utils import server_utils, IS_PY2
@ -256,14 +255,13 @@ class TestEncodingCharset(BaseTestGenerator):
raise Exception("Could not connect to the database.")
# Initialize query tool
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}'.format(
test_utils.SERVER_GROUP, self.encode_sid, self.encode_did)
self.trans_id = str(random.randint(1, 9999999))
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}/{3}'\
.format(self.trans_id, test_utils.SERVER_GROUP, self.encode_sid,
self.encode_did)
response = self.tester.post(url)
self.assertEquals(response.status_code, 200)
response_data = json.loads(response.data.decode('utf-8'))
self.trans_id = response_data['data']['gridTransId']
# Check character
url = "/sqleditor/query_tool/start/{0}".format(self.trans_id)
sql = "select E'{0}';".format(self.test_str)

View File

@ -8,6 +8,7 @@
##########################################################################
import json
import random
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
@ -32,14 +33,12 @@ class TestExplainPlan(BaseTestGenerator):
raise Exception("Could not connect to the database.")
# Initialize query tool
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}'.format(
utils.SERVER_GROUP, self.server_id, self.db_id)
self.trans_id = str(random.randint(1, 9999999))
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}/{3}'.format(
self.trans_id, utils.SERVER_GROUP, self.server_id, self.db_id)
response = self.tester.post(url)
self.assertEquals(response.status_code, 200)
response_data = json.loads(response.data.decode('utf-8'))
self.trans_id = response_data['data']['gridTransId']
# Start query tool transaction
url = '/sqleditor/query_tool/start/{0}'.format(self.trans_id)
response = self.tester.post(

View File

@ -14,6 +14,7 @@ from pgadmin.browser.server_groups.servers.databases.tests import utils as \
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
import random
class TestPollQueryTool(BaseTestGenerator):
@ -75,14 +76,12 @@ NOTICE: Hello, world!
raise Exception("Could not connect to the database.")
# Initialize query tool
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}'.format(
utils.SERVER_GROUP, self.server_id, self.db_id)
self.trans_id = str(random.randint(1, 9999999))
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}/{3}'.format(
self.trans_id, utils.SERVER_GROUP, self.server_id, self.db_id)
response = self.tester.post(url)
self.assertEquals(response.status_code, 200)
response_data = json.loads(response.data.decode('utf-8'))
self.trans_id = response_data['data']['gridTransId']
cnt = 0
for s in self.sql:
print("Executing and polling with: " + self.print_messages[cnt])

View File

@ -301,14 +301,12 @@ class TestTransactionControl(BaseTestGenerator):
raise Exception("Could not connect to the database.")
def _initialize_query_tool(self):
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}'.format(
utils.SERVER_GROUP, self.server_id, self.db_id)
self.trans_id = str(random.randint(1, 9999999))
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}/{3}'.format(
self.trans_id, utils.SERVER_GROUP, self.server_id, self.db_id)
response = self.tester.post(url)
self.assertEquals(response.status_code, 200)
response_data = json.loads(response.data.decode('utf-8'))
self.trans_id = response_data['data']['gridTransId']
def _initialize_urls(self):
self.start_query_tool_url = \
'/sqleditor/query_tool/start/{0}'.format(self.trans_id)

View File

@ -70,15 +70,14 @@ class TestViewData(BaseTestGenerator):
table_id = result[0][0]
# Initialize query tool
url = '/datagrid/initialize/datagrid/3/table/{0}/{1}/{2}/{3}'.format(
test_utils.SERVER_GROUP, self.server_id, self.db_id, table_id)
self.trans_id = str(random.randint(1, 9999999))
url = '/datagrid/initialize/datagrid/{0}/3/table/{1}/{2}/{3}/{4}'\
.format(self.trans_id, test_utils.SERVER_GROUP, self.server_id,
self.db_id, table_id)
response = self.tester.post(url)
self.assertEquals(response.status_code, 200)
response_data = json.loads(response.data.decode('utf-8'))
self.trans_id = response_data['data']['gridTransId']
url = "/sqleditor/view_data/start/{0}".format(self.trans_id)
response = self.tester.get(url)
self.assertEquals(response.status_code, 200)

View File

@ -149,14 +149,12 @@ class TestQueryUpdatableResultset(BaseTestGenerator):
raise Exception("Could not connect to the database.")
def _initialize_query_tool(self):
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}'.format(
utils.SERVER_GROUP, self.server_id, self.db_id)
self.trans_id = str(random.randint(1, 9999999))
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}/{3}'.format(
self.trans_id, utils.SERVER_GROUP, self.server_id, self.db_id)
response = self.tester.post(url)
self.assertEquals(response.status_code, 200)
response_data = json.loads(response.data.decode('utf-8'))
self.trans_id = response_data['data']['gridTransId']
def _initialize_urls(self):
self.start_query_tool_url = \
'/sqleditor/query_tool/start/{0}'.format(self.trans_id)

View File

@ -323,14 +323,12 @@ class TestSaveChangedData(BaseTestGenerator):
raise Exception("Could not connect to the database.")
def _initialize_query_tool(self):
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}'.format(
utils.SERVER_GROUP, self.server_id, self.db_id)
self.trans_id = str(random.randint(1, 9999999))
url = '/datagrid/initialize/query_tool/{0}/{1}/{2}/{3}'.format(
self.trans_id, utils.SERVER_GROUP, self.server_id, self.db_id)
response = self.tester.post(url)
self.assertEquals(response.status_code, 200)
response_data = json.loads(response.data.decode('utf-8'))
self.trans_id = response_data['data']['gridTransId']
def _initialize_urls_and_select_sql(self):
self.start_query_tool_url = \
'/sqleditor/query_tool/start/{0}'.format(self.trans_id)

View File

@ -17,10 +17,11 @@ describe('#show_data', () => {
let datagrid;
let pgBrowser;
let alertify;
let transId = 98765432;
beforeEach(() => {
alertify = jasmine.createSpyObj('alertify', ['alert']);
datagrid = {
create_transaction: jasmine.createSpy('create_transaction'),
launch_grid: jasmine.createSpy('launch_grid'),
};
pgBrowser = {
treeMenu: new TreeFake(),
@ -98,12 +99,12 @@ describe('#show_data', () => {
context('cannot find the tree node', () => {
it('does not create a transaction', () => {
showDataGrid(datagrid, pgBrowser, alertify, {}, [{id: '10'}]);
expect(datagrid.create_transaction).not.toHaveBeenCalled();
showDataGrid(datagrid, pgBrowser, alertify, {}, [{id: '10'}], transId);
expect(datagrid.launch_grid).not.toHaveBeenCalled();
});
it('display alert', () => {
showDataGrid(datagrid, pgBrowser, alertify, {}, [{id: '10'}]);
showDataGrid(datagrid, pgBrowser, alertify, {}, [{id: '10'}], transId);
expect(alertify.alert).toHaveBeenCalledWith(
'Data Grid Error',
'No object selected.'
@ -113,59 +114,52 @@ describe('#show_data', () => {
context('current node is not underneath a server', () => {
it('does not create a transaction', () => {
showDataGrid(datagrid, pgBrowser, alertify, {}, [{id: 'parent'}]);
expect(datagrid.create_transaction).not.toHaveBeenCalled();
showDataGrid(datagrid, pgBrowser, alertify, {}, [{id: 'parent'}], transId);
expect(datagrid.launch_grid).not.toHaveBeenCalled();
});
});
context('current node is not underneath a schema or view or catalog', () => {
it('does not create a transaction', () => {
showDataGrid(datagrid, pgBrowser, alertify, {}, [{id: 'database1'}]);
expect(datagrid.create_transaction).not.toHaveBeenCalled();
showDataGrid(datagrid, pgBrowser, alertify, {}, [{id: 'database1'}], transId);
expect(datagrid.launch_grid).not.toHaveBeenCalled();
});
});
context('current node is underneath a schema', () => {
it('does not create a transaction', () => {
showDataGrid(datagrid, pgBrowser, alertify, {mnuid: 11}, [{id: 'schema1'}]);
expect(datagrid.create_transaction).toHaveBeenCalledWith(
'/initialize/datagrid/11/schema/1/2/3/4',
null,
'false',
'pg',
'',
'schema1.schema1/database1/someuser@server1',
''
showDataGrid(datagrid, pgBrowser, alertify, {mnuid: 11}, [{id: 'schema1'}], transId);
expect(datagrid.launch_grid).toHaveBeenCalledWith(
98765432,
'/panel/98765432?is_query_tool=false&cmd_type=11&obj_type=schema&obj_id=4&sgid=1&sid=2&did=3&server_type=pg',
false,
'schema1.schema1/database1/someuser@server1'
);
});
});
context('current node is underneath a view', () => {
it('does not create a transaction', () => {
showDataGrid(datagrid, pgBrowser, alertify, {mnuid: 11}, [{id: 'view1'}]);
expect(datagrid.create_transaction).toHaveBeenCalledWith(
'/initialize/datagrid/11/view/1/2/3/5',
null,
'false',
'pg',
'',
'view1.view1/database1/someuser@server1',
''
showDataGrid(datagrid, pgBrowser, alertify, {mnuid: 11}, [{id: 'view1'}], transId);
expect(datagrid.launch_grid).toHaveBeenCalledWith(
98765432,
'/panel/98765432?is_query_tool=false&cmd_type=11&obj_type=view&obj_id=5&sgid=1&sid=2&did=3&server_type=pg',
false,
'view1.view1/database1/someuser@server1'
);
});
});
context('current node is underneath a catalog', () => {
it('does not create a transaction', () => {
showDataGrid(datagrid, pgBrowser, alertify, {mnuid: 11}, [{id: 'catalog1'}]);
expect(datagrid.create_transaction).toHaveBeenCalledWith(
'/initialize/datagrid/11/catalog/1/2/3/6',
null,
'false',
'pg',
'',
'catalog1.catalog1/database1/someuser@server1',
''
showDataGrid(datagrid, pgBrowser, alertify, {mnuid: 11}, [{id: 'catalog1'}], transId);
expect(datagrid.launch_grid).toHaveBeenCalledWith(
98765432,
'/panel/98765432?is_query_tool=false&cmd_type=11&obj_type=catalog&obj_id=6&sgid=1&sid=2&did=3&server_type=pg',
false,
'catalog1.catalog1/database1/someuser@server1'
);
});
});

View File

@ -17,10 +17,11 @@ describe('#showQueryTool', () => {
let queryTool;
let pgBrowser;
let alertify;
let transId = 98765432;
beforeEach(() => {
alertify = jasmine.createSpyObj('alertify', ['alert']);
queryTool = {
create_transaction: jasmine.createSpy('create_transaction'),
launch_grid: jasmine.createSpy('launch_grid'),
};
pgBrowser = {
treeMenu: new TreeFake(),
@ -66,10 +67,10 @@ describe('#showQueryTool', () => {
context('cannot find the tree node', () => {
beforeEach(() => {
showQueryTool(queryTool, pgBrowser, alertify, '', [{id: '10'}]);
showQueryTool(queryTool, pgBrowser, alertify, '', [{id: '10'}], transId);
});
it('does not create a transaction', () => {
expect(queryTool.create_transaction).not.toHaveBeenCalled();
expect(queryTool.launch_grid).not.toHaveBeenCalled();
});
it('display alert', () => {
@ -82,8 +83,8 @@ describe('#showQueryTool', () => {
context('current node is not underneath a server', () => {
it('does not create a transaction', () => {
showQueryTool(queryTool, pgBrowser, alertify, '', [{id: 'parent'}], 'title');
expect(queryTool.create_transaction).not.toHaveBeenCalled();
showQueryTool(queryTool, pgBrowser, alertify, '', [{id: 'parent'}], transId);
expect(queryTool.launch_grid).not.toHaveBeenCalled();
});
it('no alert is displayed', () => {
@ -94,32 +95,26 @@ describe('#showQueryTool', () => {
context('current node is underneath a server', () => {
context('current node is not underneath a database', () => {
it('creates a transaction', () => {
showQueryTool(queryTool, pgBrowser, alertify, 'http://someurl', [{id: 'server1'}]);
expect(queryTool.create_transaction).toHaveBeenCalledWith(
'/initialize/query_tool/1/2',
null,
'true',
'pg',
'http://someurl',
showQueryTool(queryTool, pgBrowser, alertify, 'http://someurl', [{id: 'server1'}], transId);
expect(queryTool.launch_grid).toHaveBeenCalledWith(
98765432,
'/panel/98765432?is_query_tool=true&sgid=1&sid=2&server_type=pg',
true,
'otherdblabel/someuser@server1',
'',
false
'http://someurl'
);
});
});
context('current node is underneath a database', () => {
it('creates a transaction', () => {
showQueryTool(queryTool, pgBrowser, alertify, 'http://someurl', [{id: 'database1'}], 'title');
expect(queryTool.create_transaction).toHaveBeenCalledWith(
'/initialize/query_tool/1/2/3',
null,
'true',
'pg',
'http://someurl',
showQueryTool(queryTool, pgBrowser, alertify, 'http://someurl', [{id: 'database1'}], transId);
expect(queryTool.launch_grid).toHaveBeenCalledWith(
98765432,
'/panel/98765432?is_query_tool=true&sgid=1&sid=2&server_type=pg&did=3',
true,
'database1/someuser@server1',
'',
false
'http://someurl'
);
});
});

View File

@ -18,5 +18,6 @@ define(function () {
'datagrid.initialize_query_tool': '/initialize/query_tool/<int:sgid>/<int:sid>',
'datagrid.initialize_query_tool_with_did': '/initialize/query_tool/<int:sgid>/<int:sid>/<int:did>',
'restore.create_job': '/restore/job/<int:sid>',
'datagrid.panel': '/panel/<int:trans_id>',
};
});

View File

@ -7,7 +7,7 @@
//
//////////////////////////////////////////////////////////////
import { getEpoch, getGCD, getMod, quote_ident, parseFuncParams } from 'sources/utils';
import { getEpoch, getGCD, getMod, quote_ident, parseFuncParams, getRandomInt } from 'sources/utils';
describe('getEpoch', function () {
it('should return non zero', function () {
@ -135,3 +135,10 @@ describe('parseFuncParams', function () {
expect(parseFuncParams(funcLabel)).toEqual(expectedObj);
});
});
describe('getRandomInt', function () {
it('is between', function () {
let id = getRandomInt(1, 9999999);
expect(1 <= id && id <= 9999999).toBeTruthy();
});
});

View File

@ -36,61 +36,5 @@ define(['sources/sqleditor_utils'],
expect(SqlEditorUtils.calcFontSize(2)).toEqual('2em');
});
});
describe('Remove the slashes', function () {
it('it will remove the slashes', function () {
expect(
SqlEditorUtils.removeSlashInTheString('/')
).toEqual({
'slashLocations': '0',
'title': '',
});
});
it('it will remove if slashes are present', function () {
expect(
SqlEditorUtils.removeSlashInTheString('my/test')
).toEqual({
'slashLocations': '2',
'title': 'mytest',
});
});
it('it will remove all the slashes are present', function () {
expect(
SqlEditorUtils.removeSlashInTheString('my/test/value')
).toEqual({
'slashLocations': '2,7',
'title': 'mytestvalue',
});
});
it('it will remove all the slashes are present', function () {
expect(
SqlEditorUtils.removeSlashInTheString('a/bb/ccc/dddd/eeeee')
).toEqual({
'slashLocations': '1,4,8,13',
'title': 'abbcccddddeeeee',
});
});
it('it will not remove if slash is not present', function () {
expect(
SqlEditorUtils.removeSlashInTheString('mytest')
).toEqual({
'slashLocations': '',
'title': 'mytest',
});
});
it('it will not remove if value is not present', function () {
expect(
SqlEditorUtils.removeSlashInTheString('')
).toEqual({
'slashLocations': '',
'title': '',
});
});
});
});
});

View File

@ -3519,9 +3519,9 @@ eslint-scope@^4.0.2, eslint-scope@^4.0.3:
estraverse "^4.1.1"
eslint-utils@^1.3.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.0.tgz#e2c3c8dba768425f897cf0f9e51fe2e241485d4c"
integrity sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==
version "1.4.2"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab"
integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==
dependencies:
eslint-visitor-keys "^1.0.0"