Modify the web code to allow the Query Tool and Debugger to be opened in new tabs, per settings in Preferences. Fixes #1344

Note that this does *not* enable the runtime to use multiple windows at this stage. It's really only useful in Server mode.
This commit is contained in:
Akshay Joshi 2017-03-24 14:43:56 +00:00 committed by Dave Page
parent 0eda6033df
commit 569ceb3906
8 changed files with 295 additions and 165 deletions

View File

@ -24,6 +24,7 @@ from pgadmin.utils.ajax import make_json_response, bad_request, \
internal_server_error
from config import PG_DEFAULT_DRIVER
from pgadmin.utils.preferences import Preferences
class DataGridModule(PgAdminModule):
@ -135,7 +136,11 @@ def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
# Store the grid dictionary into the session variable
session['gridData'] = sql_grid_data
return make_json_response(data={'gridTransId': trans_id})
pref = Preferences.module('sqleditor')
new_browser_tab = pref.preference('new_browser_tab').get()
return make_json_response(data={'gridTransId': trans_id,
'newBrowserTab': new_browser_tab})
@blueprint.route('/panel/<int:trans_id>/<is_query_tool>/<path:editor_title>', methods=["GET"])
@ -171,10 +176,18 @@ def panel(trans_id, is_query_tool, editor_title):
if "linux" in _platform:
is_linux_platform = True
pref = Preferences.module('sqleditor')
if pref.preference('new_browser_tab').get():
new_browser_tab = 'true'
else:
new_browser_tab = 'false'
return render_template("datagrid/index.html", _=gettext, uniqueId=trans_id,
is_query_tool=is_query_tool, editor_title=editor_title,
script_type_url=sURL, is_desktop_mode=app.PGADMIN_RUNTIME,
is_linux=is_linux_platform)
is_query_tool=is_query_tool,
editor_title=editor_title, script_type_url=sURL,
is_desktop_mode=app.PGADMIN_RUNTIME,
is_linux=is_linux_platform,
is_new_browser_tab=new_browser_tab)
@blueprint.route(
@ -234,7 +247,11 @@ def initialize_query_tool(sid, did=None):
# Store the grid dictionary into the session variable
session['gridData'] = sql_grid_data
return make_json_response(data={'gridTransId': trans_id})
pref = Preferences.module('sqleditor')
new_browser_tab = pref.preference('new_browser_tab').get()
return make_json_response(data={'gridTransId': trans_id,
'newBrowserTab': new_browser_tab})
@blueprint.route('/close/<int:trans_id>', methods=["GET"])

View File

@ -310,7 +310,8 @@ function($, pgAdmin, R, S) {
{% endif %}
// Start the query tool.
sqlEditorController.start({{ is_query_tool }}, "{{ editor_title }}", script_sql);
sqlEditorController.start({{ is_query_tool }}, "{{ editor_title }}",
script_sql, {{ is_new_browser_tab }});
});
});
{% endblock %}

View File

@ -327,39 +327,57 @@ define(
var panel_title = ' Query-' + self.title_index;
self.title_index += 1;
var dashboardPanel = pgBrowser.docker.findPanels('dashboard');
dataGridPanel = pgBrowser.docker.addPanel('frm_datagrid', wcDocker.DOCK.STACKED, dashboardPanel[0]);
dataGridPanel.title(panel_title);
dataGridPanel.icon('fa fa-bolt');
dataGridPanel.focus();
// Listen on the panel closed event.
dataGridPanel.on(wcDocker.EVENT.CLOSED, function() {
$.ajax({
url: "{{ url_for('datagrid.index') }}" + "close/" + res.data.gridTransId,
method: 'GET'
});
});
// Open the panel if frame is initialized
baseUrl = "{{ url_for('datagrid.index') }}" + "panel/" + res.data.gridTransId + "/false/"
+ encodeURIComponent(grid_title);
var openDataGridURL = function(j) {
j.data('embeddedFrame').$container.append(self.spinner_el);
setTimeout(function() {
var frameInitialized = j.data('frameInitialized');
if (frameInitialized) {
var frame = j.data('embeddedFrame');
if (frame) {
frame.openURL(baseUrl);
frame.$container.find('.wcLoadingContainer').hide(1);
}
} else {
if (res.data.newBrowserTab) {
var newWin = window.open(baseUrl, '_blank');
// Listen on the window closed event.
newWin.addEventListener("unload", function(e){
$.ajax({
url: "{{ url_for('datagrid.index') }}" + "close/" + res.data.gridTransId,
method: 'GET'
});
}, false);
// 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;
});
} else {
var dashboardPanel = pgBrowser.docker.findPanels('dashboard');
dataGridPanel = pgBrowser.docker.addPanel('frm_datagrid', wcDocker.DOCK.STACKED, dashboardPanel[0]);
dataGridPanel.title(panel_title);
dataGridPanel.icon('fa fa-bolt');
dataGridPanel.focus();
// Listen on the panel closed event.
dataGridPanel.on(wcDocker.EVENT.CLOSED, function() {
$.ajax({
url: "{{ url_for('datagrid.index') }}" + "close/" + res.data.gridTransId,
method: 'GET'
});
});
var openDataGridURL = function(j) {
j.data('embeddedFrame').$container.append(self.spinner_el);
setTimeout(function() {
var frameInitialized = j.data('frameInitialized');
if (frameInitialized) {
var frame = j.data('embeddedFrame');
if (frame) {
frame.openURL(baseUrl);
frame.$container.find('.wcLoadingContainer').hide(1);
}
} else {
openDataGridURL(j);
}
}, 100);
};
openDataGridURL($(dataGridPanel));
}
}, 100);
};
openDataGridURL($(dataGridPanel));
}
},
error: function(e) {
alertify.alert(
@ -422,42 +440,61 @@ define(
contentType: "application/json",
success: function(res) {
/* On successfully initialization find the dashboard panel,
* create new panel and add it to the dashboard panel.
*/
var dashboardPanel = pgBrowser.docker.findPanels('dashboard');
queryToolPanel = pgBrowser.docker.addPanel('frm_datagrid', wcDocker.DOCK.STACKED, dashboardPanel[0]);
queryToolPanel.title(panel_title);
queryToolPanel.icon('fa fa-bolt');
queryToolPanel.focus();
// Listen on the panel closed event.
queryToolPanel.on(wcDocker.EVENT.CLOSED, function() {
$.ajax({
url: "{{ url_for('datagrid.index') }}" + "close/" + res.data.gridTransId,
method: 'GET'
});
});
// Open the panel if frame is initialized
baseUrl = "{{ url_for('datagrid.index') }}" + "panel/" + res.data.gridTransId + "/true/"
+ encodeURIComponent(grid_title) + '?' + "query_url=" + encodeURI(sURL);
var openQueryToolURL = function(j) {
j.data('embeddedFrame').$container.append(pgAdmin.DataGrid.spinner_el);
setTimeout(function() {
var frameInitialized = j.data('frameInitialized');
if (frameInitialized) {
var frame = j.data('embeddedFrame');
if (frame) {
frame.openURL(baseUrl);
frame.$container.find('.wcLoadingContainer').delay(1000).hide(1);
if (res.data.newBrowserTab) {
var newWin = window.open(baseUrl, '_blank');
// Listen on the window closed event.
newWin.addEventListener("unload", function(e){
$.ajax({
url: "{{ url_for('datagrid.index') }}" + "close/" + res.data.gridTransId,
method: 'GET'
});
}, false);
// 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;
});
} else {
/* On successfully initialization find the dashboard panel,
* create new panel and add it to the dashboard panel.
*/
var dashboardPanel = pgBrowser.docker.findPanels('dashboard');
queryToolPanel = pgBrowser.docker.addPanel('frm_datagrid', wcDocker.DOCK.STACKED, dashboardPanel[0]);
queryToolPanel.title(panel_title);
queryToolPanel.icon('fa fa-bolt');
queryToolPanel.focus();
// Listen on the panel closed event.
queryToolPanel.on(wcDocker.EVENT.CLOSED, function() {
$.ajax({
url: "{{ url_for('datagrid.index') }}" + "close/" + res.data.gridTransId,
method: 'GET'
});
});
var openQueryToolURL = function(j) {
j.data('embeddedFrame').$container.append(pgAdmin.DataGrid.spinner_el);
setTimeout(function() {
var frameInitialized = j.data('frameInitialized');
if (frameInitialized) {
var frame = j.data('embeddedFrame');
if (frame) {
frame.openURL(baseUrl);
frame.$container.find('.wcLoadingContainer').delay(1000).hide(1);
}
} else {
openQueryToolURL(j);
}
} else {
openQueryToolURL(j);
}
}, 100);
};
openQueryToolURL($(queryToolPanel));
}, 100);
};
openQueryToolURL($(queryToolPanel));
}
},
error: function(e) {
alertify.alert(

View File

@ -25,6 +25,7 @@ from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER
from pgadmin.model import db, DebuggerFunctionArguments
from pgadmin.utils.preferences import Preferences
# Constants
ASYNC_OK = 1
@ -42,6 +43,7 @@ class DebuggerModule(PgAdminModule):
- Method is used to load the required javascript files for debugger module
"""
LABEL = gettext("Debugger")
def get_own_javascripts(self):
scripts = list()
@ -58,6 +60,14 @@ class DebuggerModule(PgAdminModule):
return scripts
def register_preferences(self):
self.open_in_new_tab = self.preference.register(
'display', 'debugger_new_browser_tab',
gettext("Open in New Browser Tab"), 'boolean', False,
category_label=gettext('Display'),
help_str=gettext('If set to True, the Debugger '
'will be opened in a new browser tab.')
)
blueprint = DebuggerModule(MODULE_NAME, __name__)
@ -317,7 +327,7 @@ def direct_new(trans_id):
return render_template(
"debugger/direct.html",
_=gettext,
function_name='test',
function_name=obj['function_name'],
uniqueId=trans_id,
debug_type=debug_type,
is_desktop_mode=current_app.PGADMIN_RUNTIME,
@ -435,6 +445,7 @@ def initialize_target(debug_type, sid, did, scid, func_id, tri_id=None):
'database_id': did,
'schema_id': scid,
'function_id': func_id,
'function_name': session['funcData']['name'],
'debug_type': debug_type,
'debugger_version': debugger_version,
'frame_id': 0,
@ -478,7 +489,13 @@ def initialize_target(debug_type, sid, did, scid, func_id, tri_id=None):
# Delete the 'funcData' session variables as it is not used now as target is initialized
del session['funcData']
return make_json_response(data={'status': status, 'debuggerTransId': trans_id})
pref = Preferences.module('debugger')
new_browser_tab = pref.preference('debugger_new_browser_tab').get()
return make_json_response(data={'status': status,
'debuggerTransId': trans_id,
'newBrowserTab': new_browser_tab})
@blueprint.route('/close/<int:trans_id>', methods=["GET"])

View File

@ -241,14 +241,26 @@ define(
success: function(res) {
var url = "{{ url_for('debugger.index') }}" + "direct/" + res.data.debuggerTransId;
pgBrowser.Events.once(
'pgadmin-browser:frame:urlloaded:frm_debugger', function(frame) {
frame.openURL(url);
});
if (res.data.newBrowserTab) {
var newWin = window.open(url, '_blank');
// Create the debugger panel as per the data received from user input dialog.
var dashboardPanel = pgBrowser.docker.findPanels(
'dashboard'
// Listen on the window closed event.
newWin.addEventListener("unload", function(e){
var closeUrl = "{{ url_for('debugger.index') }}" + "close/" + res.data.debuggerTransId;
$.ajax({
url: closeUrl,
method: 'GET'
});
}, false);
} else {
pgBrowser.Events.once(
'pgadmin-browser:frame:urlloaded:frm_debugger', function(frame) {
frame.openURL(url);
});
// Create the debugger panel as per the data received from user input dialog.
var dashboardPanel = pgBrowser.docker.findPanels(
'dashboard'
),
panel = pgBrowser.docker.addPanel(
'frm_debugger', wcDocker.DOCK.STACKED, dashboardPanel[0]
@ -264,12 +276,13 @@ define(
method: 'GET'
});
});
},
error: function(e) {
Alertify.alert(
'Debugger target Initialize Error'
);
}
},
error: function(e) {
Alertify.alert(
'Debugger target initialization error'
);
}
});
},
@ -331,29 +344,42 @@ define(
var url = "{{ url_for('debugger.index') }}" + "direct/" + res.data.debuggerTransId;
pgBrowser.Events.once(
'pgadmin-browser:frame:urlloaded:frm_debugger', function(frame) {
frame.openURL(url);
});
if (res.data.newBrowserTab) {
var newWin = window.open(url, '_blank');
// Create the debugger panel as per the data received from user input dialog.
var dashboardPanel = pgBrowser.docker.findPanels(
'dashboard'
),
panel = pgBrowser.docker.addPanel(
'frm_debugger', wcDocker.DOCK.STACKED, dashboardPanel[0]
);
panel.focus();
// Register Panel Closed event
panel.on(wcDocker.EVENT.CLOSED, function() {
var closeUrl = "{{ url_for('debugger.index') }}" + "close/" + res.data.debuggerTransId;
$.ajax({
url: closeUrl,
method: 'GET'
// Listen on the window closed event.
newWin.addEventListener("unload", function(e){
var closeUrl = "{{ url_for('debugger.index') }}" + "close/" + res.data.debuggerTransId;
$.ajax({
url: closeUrl,
method: 'GET'
});
}, false);
} else {
pgBrowser.Events.once(
'pgadmin-browser:frame:urlloaded:frm_debugger', function(frame) {
frame.openURL(url);
});
});
// Create the debugger panel as per the data received from user input dialog.
var dashboardPanel = pgBrowser.docker.findPanels(
'dashboard'
),
panel = pgBrowser.docker.addPanel(
'frm_debugger', wcDocker.DOCK.STACKED, dashboardPanel[0]
);
panel.focus();
// Register Panel Closed event
panel.on(wcDocker.EVENT.CLOSED, function() {
var closeUrl = "{{ url_for('debugger.index') }}" + "close/" + res.data.debuggerTransId;
$.ajax({
url: closeUrl,
method: 'GET'
});
});
}
},
error: function(e) {
Alertify.alert(

View File

@ -553,29 +553,40 @@ define(
var url = "{{ url_for('debugger.index') }}" + "direct/" + res.data.debuggerTransId;
pgBrowser.Events.once(
'pgadmin-browser:frame:urlloaded:frm_debugger', function(frame) {
frame.openURL(url);
});
if (res.data.newBrowserTab) {
var newWin = window.open(url, '_blank');
// Create the debugger panel as per the data received from user input dialog.
var dashboardPanel = pgBrowser.docker.findPanels(
'dashboard'
),
panel = pgBrowser.docker.addPanel(
'frm_debugger', wcDocker.DOCK.STACKED, dashboardPanel[0]
);
panel.focus();
// Panel Closed event
panel.on(wcDocker.EVENT.CLOSED, function() {
var closeUrl = "{{ url_for('debugger.index') }}" + "close/" + res.data.debuggerTransId;
$.ajax({
url: closeUrl,
method: 'GET'
// Listen on the window closed event.
newWin.addEventListener("unload", function(e){
var closeUrl = "{{ url_for('debugger.index') }}" + "close/" + res.data.debuggerTransId;
$.ajax({
url: closeUrl,
method: 'GET'
});
}, false);
} else {
pgBrowser.Events.once(
'pgadmin-browser:frame:urlloaded:frm_debugger', function(frame) {
frame.openURL(url);
});
});
// Create the debugger panel as per the data received from user input dialog.
var dashboardPanel = pgBrowser.docker.findPanels('dashboard'),
panel = pgBrowser.docker.addPanel(
'frm_debugger', wcDocker.DOCK.STACKED, dashboardPanel[0]
);
panel.focus();
// Panel Closed event
panel.on(wcDocker.EVENT.CLOSED, function() {
var closeUrl = "{{ url_for('debugger.index') }}" + "close/" + res.data.debuggerTransId;
$.ajax({
url: closeUrl,
method: 'GET'
});
});
}
if (d._type == "function") {
var _Url = "{{ url_for('debugger.index') }}" + "set_arguments/" + treeInfo.server._id +

View File

@ -84,6 +84,14 @@ class SqlEditorModule(PgAdminModule):
'Values greater than 1 display the notifier for the number of seconds specified.')
)
self.open_in_new_tab = self.preference.register(
'display', 'new_browser_tab',
gettext("Open in New Browser Tab"), 'boolean', False,
category_label=gettext('Display'),
help_str=gettext('If set to True, the Query Tool '
'will be opened in a new browser tab.')
)
self.explain_verbose = self.preference.register(
'Explain', 'explain_verbose',
gettext("Verbose output?"), 'boolean', False,

View File

@ -228,36 +228,38 @@ define(
self.render_history_grid();
// Listen on the panel closed event and notify user to save modifications.
_.each(window.top.pgAdmin.Browser.docker.findPanels('frm_datagrid'), function(p) {
if(p.isVisible()) {
p.on(wcDocker.EVENT.CLOSING, function() {
// Only if we can edit data then perform this check
var notify = false, msg;
if(self.handler.can_edit) {
var data_store = self.handler.data_store;
if(data_store && (_.size(data_store.added) ||
_.size(data_store.updated))) {
msg = "{{ _('The data has been modified, but not saved. Are you sure you wish to discard the changes?') }}";
if (!self.handler.is_new_browser_tab) {
// Listen on the panel closed event and notify user to save modifications.
_.each(window.top.pgAdmin.Browser.docker.findPanels('frm_datagrid'), function(p) {
if(p.isVisible()) {
p.on(wcDocker.EVENT.CLOSING, function() {
// Only if we can edit data then perform this check
var notify = false, msg;
if(self.handler.can_edit) {
var data_store = self.handler.data_store;
if(data_store && (_.size(data_store.added) ||
_.size(data_store.updated))) {
msg = "{{ _('The data has been modified, but not saved. Are you sure you wish to discard the changes?') }}";
notify = true;
}
} else if(self.handler.is_query_tool && self.handler.is_query_changed) {
msg = "{{ _('The query has been modified, but not saved. Are you sure you wish to discard the changes?') }}";
notify = true;
}
} else if(self.handler.is_query_tool && self.handler.is_query_changed) {
msg = "{{ _('The query has been modified, but not saved. Are you sure you wish to discard the changes?') }}";
notify = true;
}
if(notify) {return self.user_confirmation(p, msg);}
return true;
});
// Set focus on query tool of active panel
p.on(wcDocker.EVENT.GAIN_FOCUS, function() {
if (!$(p.$container).hasClass('wcPanelTabContentHidden')) {
setTimeout(function() {
self.handler.gridView.query_tool_obj.focus();
}, 200);
}
});
}
});
if(notify) {return self.user_confirmation(p, msg);}
return true;
});
// Set focus on query tool of active panel
p.on(wcDocker.EVENT.GAIN_FOCUS, function() {
if (!$(p.$container).hasClass('wcPanelTabContentHidden')) {
setTimeout(function() {
self.handler.gridView.query_tool_obj.focus();
}, 200);
}
});
}
});
}
// set focus on query tool once loaded
setTimeout(function() {
@ -1517,7 +1519,7 @@ define(
* 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(is_query_tool, editor_title, script_sql) {
start: function(is_query_tool, editor_title, script_sql, is_new_browser_tab) {
var self = this;
self.is_query_tool = is_query_tool;
@ -1527,6 +1529,7 @@ define(
self.explain_costs = false;
self.explain_buffers = false;
self.explain_timing = false;
self.is_new_browser_tab = is_new_browser_tab;
// We do not allow to call the start multiple times.
if (self.gridView)
@ -2423,11 +2426,17 @@ define(
// Set panel title.
setTitle: function(title) {
_.each(window.top.pgAdmin.Browser.docker.findPanels('frm_datagrid'), function(p) {
if(p.isVisible()) {
p.title(decodeURIComponent(title));
}
});
var self = this;
if (self.is_new_browser_tab) {
window.document.title = title;
} else {
_.each(window.top.pgAdmin.Browser.docker.findPanels('frm_datagrid'), function(p) {
if(p.isVisible()) {
p.title(decodeURIComponent(title));
}
});
}
},
// load select file dialog
@ -2571,14 +2580,18 @@ define(
} else {
var title = '';
// 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;
}
});
if (self.is_new_browser_tab) {
title = window.document.title + ' *';
} else {
// 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;
}
});
title = self.gridView.panel_title + ' *';
title = self.gridView.panel_title + ' *';
}
self.setTitle(title);
}