mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-25 18:20:20 -06:00
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:
parent
25f85fe123
commit
234efc3be7
@ -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.
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,12 +257,8 @@ 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()
|
||||
|
||||
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
|
||||
@ -293,48 +269,31 @@ def panel(trans_id, is_query_tool, editor_title):
|
||||
|
||||
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,
|
||||
}
|
||||
)
|
||||
|
@ -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() {
|
||||
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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 %};"> </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>
|
||||
@ -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 %}
|
||||
|
@ -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;
|
||||
|
BIN
web/pgadmin/tools/sqleditor/static/img/loading.gif
Normal file
BIN
web/pgadmin/tools/sqleditor/static/img/loading.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
@ -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);
|
||||
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();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -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'
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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(
|
||||
|
@ -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])
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -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'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -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>',
|
||||
};
|
||||
});
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
@ -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': '',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user