Added tab title placeholder for Query Tool, View/Edit Data, and Debugger. Fixes #4232

This commit is contained in:
Nikhil Mohite 2020-10-20 15:41:54 +05:30 committed by Akshay Joshi
parent 38b90f7b00
commit 18cad32bd4
18 changed files with 317 additions and 112 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 216 KiB

View File

@ -159,6 +159,8 @@ Expand the *Debugger* node to specify your debugger display preferences.
:alt: Preferences dialog debugger display options
:align: center
* Use *Debugger tab title placeholder* field to customize the Debugger tab title.
* When the *Open in new browser tab* switch is set to *True*, the Debugger will
open in a new browser tab when invoked.
@ -284,6 +286,10 @@ Tool display.
a positive value above zero is specified, the notifier will be displayed for
the specified number of seconds. The default is *5*.
* Use the *Query tool tab title placeholder* field to customize the query tool tab title.
* Use *View/Edit tab title placeholder* field to customize the View/Edit Data tab title.
.. image:: images/preferences_sql_editor.png
:alt: Preferences dialog sqleditor editor settings
:align: center

View File

@ -9,6 +9,7 @@ This release contains a number of bug fixes and new features since the release o
New features
************
| `Issue #4232 <https://redmine.postgresql.org/issues/4232>`_ - Added tab title placeholder for Query Tool, View/Edit Data, and Debugger.
Housekeeping
************

View File

@ -17,7 +17,7 @@ import newConnectionDialogModel from 'sources/sqleditor/new_connection_dialog_mo
let NewConnectionDialog = {
'dialog': function(handler, reconnect) {
'dialog': function(handler, reconnect, preferences) {
let url = url_for('sqleditor.get_new_connection_data', {
'sid': handler.url_params.sid,
'sgid': handler.url_params.sgid,
@ -199,10 +199,26 @@ let NewConnectionDialog = {
}
});
let tab_title = '';
if(newConnCollectionModel['role']) {
tab_title = selected_database_name + '/' + newConnCollectionModel['role'] + '@' + response.server_name;
} else {
tab_title = selected_database_name + '/' + newConnCollectionModel['user'] + '@' + response.server_name;
var qt_title_placeholder = preferences['qt_tab_title_placeholder'];
var placeholders = qt_title_placeholder.split('%');
placeholders.forEach(function(placeholder) {
if(placeholder == 'DATABASE'){
tab_title = tab_title.concat(selected_database_name);
} else if(placeholder == 'USERNAME') {
if(newConnCollectionModel['role']) {
tab_title = tab_title.concat(newConnCollectionModel['role']);
} else {
tab_title = tab_title.concat(newConnCollectionModel['user']);
}
} else if(placeholder == 'SERVER') {
tab_title = tab_title.concat(response.server_name);
} else{
tab_title = tab_title.concat(placeholder);
}
});
if(!newConnCollectionModel['role']) {
newConnCollectionModel['role'] = null;
}
@ -212,12 +228,6 @@ let NewConnectionDialog = {
if(parseInt(connection_data['server']) == newConnCollectionModel['server']
&& parseInt(connection_data['database']) == newConnCollectionModel['database']
&& connection_data['user'] == newConnCollectionModel['user'] && connection_data['role'] == newConnCollectionModel['role']) {
is_create_connection = false;
// break for loop by return false.
return false;
}
if(tab_title == connection_data['title']) {
is_create_connection = false;
return false;
}
@ -236,6 +246,7 @@ let NewConnectionDialog = {
'password': response.password,
'server_name': _.escape(response.server_name),
'database_name': _.escape(selected_database_name),
'is_selected': false,
};
handler.gridView.on_change_connection(connection_details, self);
}

View File

@ -10,7 +10,7 @@
import {getTreeNodeHierarchyFromIdentifier} from '../../../../static/js/tree/pgadmin_tree_node';
import gettext from 'sources/gettext';
function getDatabaseLabel(parentData) {
export function getDatabaseLabel(parentData) {
return parentData.database ? parentData.database.label
: parentData.server.db;
}
@ -20,6 +20,7 @@ function isServerInformationAvailable(parentData) {
}
export function getPanelTitle(pgBrowser, selected_item=null) {
var preferences = pgBrowser.get_preferences_for_module('sqleditor');
if(selected_item == null) {
selected_item = pgBrowser.treeMenu.selected();
}
@ -32,7 +33,21 @@ export function getPanelTitle(pgBrowser, selected_item=null) {
const db_label = getDatabaseLabel(parentData);
return `${db_label}/${_.escape(parentData.server.user.name)}@${parentData.server.label}`;
var qt_title_placeholder = preferences['qt_tab_title_placeholder'];
var placeholders = qt_title_placeholder.split('%');
var title = '';
placeholders.forEach(function(placeholder) {
if(placeholder == 'DATABASE'){
title = title.concat(db_label);
} else if(placeholder == 'USERNAME') {
title = title.concat(parentData.server.user.name);
} else if(placeholder == 'SERVER') {
title = title.concat(parentData.server.label);
} else{
title = title.concat(placeholder);
}
});
return _.escape(title);
}
export function setQueryToolDockerTitle(panel, is_query_tool, panel_title, is_file) {

View File

@ -9,7 +9,7 @@
import gettext from '../../../../static/js/gettext';
import url_for from '../../../../static/js/url_for';
import {getTreeNodeHierarchyFromIdentifier} from '../../../../static/js/tree/pgadmin_tree_node';
import {getPanelTitle} from './datagrid_panel_title';
import {getDatabaseLabel} from './datagrid_panel_title';
import CodeMirror from 'bundled_codemirror';
import * as SqlEditorUtils from 'sources/sqleditor_utils';
import $ from 'jquery';
@ -279,16 +279,35 @@ function hasSchemaOrCatalogOrViewInformation(parentData) {
}
export function generateDatagridTitle(pgBrowser, aciTreeIdentifier) {
const baseTitle = getPanelTitle(pgBrowser, aciTreeIdentifier);
//const baseTitle = getPanelTitle(pgBrowser, aciTreeIdentifier);
var preferences = pgBrowser.get_preferences_for_module('sqleditor');
const parentData = getTreeNodeHierarchyFromIdentifier.call(
pgBrowser,
aciTreeIdentifier
);
const namespaceName = retrieveNameSpaceName(parentData);
const db_label = getDatabaseLabel(parentData);
const node = pgBrowser.treeMenu.findNodeByDomElement(aciTreeIdentifier);
return `${namespaceName}.${node.getData().label}/${baseTitle}`;
var dtg_title_placeholder = preferences['vw_edt_tab_title_placeholder'];
var placeholders = dtg_title_placeholder.split('%');
var title = '';
placeholders.forEach(function(placeholder) {
if(placeholder == 'DATABASE'){
title = title.concat(db_label);
} else if(placeholder == 'USERNAME') {
title = title.concat(parentData.server.user.name);
} else if(placeholder == 'SERVER') {
title = title.concat(parentData.server.label);
} else if(placeholder == 'SCHEMA') {
title = title.concat(namespaceName);
} else if(placeholder == 'TABLE') {
title = title.concat(node.getData().label);
} else{
title = title.concat(placeholder);
}
});
return _.escape(title);
}

View File

@ -85,6 +85,19 @@ class DebuggerModule(PgAdminModule):
'will be opened in a new browser tab.')
)
self.tab_title = self.preference.register(
'display', 'debugger_tab_title_placeholder',
gettext("Tab title"),
'text', '%FUNCTION%(%ARGS%)',
category_label=PREF_LABEL_DISPLAY,
help_str=gettext(
'Supported placeholders are %FUNCTION%, %ARGS%, %SCHEMA% and'
' %DATABASE%. Users can provide any string with or '
'without placeholders of their choice. The blank title will be'
' revert back to the default title with placeholders.'
)
)
self.preference.register(
'keyboard_shortcuts', 'btn_start',
gettext('Accesskey (Continue/Start)'), 'keyboardshortcut',

View File

@ -427,6 +427,7 @@ define([
panel = pgBrowser.docker.addPanel(
'frm_debugger', wcDocker.DOCK.STACKED, dashboardPanel[0]
);
debuggerUtils.setDebuggerTitle(panel, self.preferences, treeInfo.function.label, treeInfo.schema.label, treeInfo.database.label);
panel.focus();
@ -549,6 +550,7 @@ define([
panel = pgBrowser.docker.addPanel(
'frm_debugger', wcDocker.DOCK.STACKED, dashboardPanel[0]
);
debuggerUtils.setDebuggerTitle(panel, self.preferences, newTreeInfo.function.label, newTreeInfo.schema.label, newTreeInfo.database.label);
panel.focus();

View File

@ -10,9 +10,9 @@
define([
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
'pgadmin.alertifyjs', 'sources/pgadmin', 'pgadmin.browser',
'pgadmin.backgrid', 'sources/window', 'wcdocker',
'pgadmin.backgrid', 'sources/window', 'pgadmin.tools.debugger.utils', 'wcdocker',
], function(
gettext, url_for, $, _, Backbone, Alertify, pgAdmin, pgBrowser, Backgrid, pgWindow
gettext, url_for, $, _, Backbone, Alertify, pgAdmin, pgBrowser, Backgrid, pgWindow, debuggerUtils
) {
var wcDocker = window.wcDocker;
@ -773,6 +773,7 @@ define([
panel = pgBrowser.docker.addPanel(
'frm_debugger', wcDocker.DOCK.STACKED, dashboardPanel[0]
);
debuggerUtils.setDebuggerTitle(panel, self.preferences, treeInfo.function.label, treeInfo.schema.label, treeInfo.database.label);
panel.focus();

View File

@ -42,8 +42,54 @@ function getProcedureId(treeInfoObject) {
return objectId;
}
function setDebuggerTitle(panel, preferences, function_name, schema_name, database_name) {
var debugger_title_placeholder = preferences['debugger_tab_title_placeholder'];
var placeholders = debugger_title_placeholder.split('%');
var title = '';
placeholders.forEach(function(placeholder) {
if(placeholder == 'FUNCTION'){
var func_name = '';
func_name = get_function_name(function_name);
title = title.concat(func_name);
} else if(placeholder == 'ARGS') {
var args = '';
var function_data = function_name.split('(');
var args_list = function_data[function_data.length - 1].split(')');
if(args_list.length > 0) {
args = args.concat(args_list[0]);
}
function_name = get_function_name(function_name);
title = title.concat(args);
} else if(placeholder == 'SCHEMA'){
title = title.concat(schema_name);
} else if(placeholder == 'DATABASE'){
title = title.concat(database_name);
} else if (placeholder != 'ARGS' ){
title = title.concat(placeholder);
}
});
panel.title('<span>'+ _.escape(title) +'</span>');
}
function get_function_name(function_name) {
var function_data = function_name.split('(');
function_data.splice(-1, 1);
var index = 0;
var func_name = '';
for(index=0; index < function_data.length; index++) {
func_name = func_name.concat(function_data[index]);
if (index != function_data.length -1) {
func_name = func_name.concat('(');
}
}
return func_name;
}
module.exports = {
setFocusToDebuggerEditor: setFocusToDebuggerEditor,
getFunctionId: getFunctionId,
getProcedureId: getProcedureId,
setDebuggerTitle: setDebuggerTitle,
};

View File

@ -2118,10 +2118,20 @@ define('tools.querytool', [
queryToolActions.executeMacro(this.handler, macroId);
},
set_selected_option: function(selected_config) {
this.connection_list.forEach(option =>{
if(option['server'] == selected_config['server'] && option['database'] == selected_config['database']) {
selected_config['is_selected'] = true;
} else {
option['is_selected'] = false;
}
});
},
on_change_connection: function(connection_details, ref) {
let title = this.$el.find('.editor-title').html();
if(connection_details['title'] != title) {
if(!connection_details['is_selected']) {
var self = this;
self.set_selected_option(connection_details);
var loadingDiv = null;
var msgDiv = null;
if(ref){
@ -2174,6 +2184,7 @@ define('tools.querytool', [
'is_allow_new_connection': true,
'database_name': connection_details['database_name'],
'server_name': connection_details['server_name'],
'is_selected': true,
};
self.connection_list.unshift(connection_data);
self.render_connection(self.connection_list);
@ -2518,6 +2529,14 @@ define('tools.querytool', [
});
$('#btn-conn-status i').removeClass('obtaining-conn');
var tree_data = pgWindow.default.pgAdmin.Browser.treeMenu.translateTreeNodeIdFromACITree(pgWindow.default.pgAdmin.Browser.treeMenu.selected());
var server_data = pgWindow.default.pgAdmin.Browser.treeMenu.findNode(tree_data.slice(0,2));
var database_data = pgWindow.default.pgAdmin.Browser.treeMenu.findNode(tree_data.slice(0,4));
self.gridView.set_editor_title(_.unescape(url_params.title));
let connection_data = {
'server_group': self.gridView.handler.url_params.sgid,
@ -2527,8 +2546,9 @@ define('tools.querytool', [
'role': null,
'title': _.unescape(url_params.title),
'is_allow_new_connection': false,
'database_name': _.unescape(url_params.title.split('/')[0]),
'server_name': _.unescape(url_params.title.split('@')[1]),
'database_name': _.unescape(database_data.data.label),
'server_name': _.unescape(server_data.data.label),
'is_selected': true,
};
self.gridView.connection_list.unshift(connection_data);
self.gridView.render_connection(self.gridView.connection_list);
@ -3862,7 +3882,7 @@ define('tools.querytool', [
if (arguments.length > 0 && arguments[arguments.length - 1] == 'connect') {
reconnect = true;
}
newConnectionHandler.dialog(self, reconnect);
newConnectionHandler.dialog(self, reconnect, self.preferences);
},
// This function will include the filter by selection.
_include_filter: function() {

View File

@ -300,6 +300,32 @@ def register_query_tool_preferences(self):
'transaction status.')
)
self.qt_tab_title = self.preference.register(
'display', 'qt_tab_title_placeholder',
gettext("Query tool tab title"),
'text', '%DATABASE%/%USERNAME%@%SERVER%',
category_label=PREF_LABEL_DISPLAY,
help_str=gettext(
'Supported placeholders are %DATABASE%, %USERNAME%, and %SERVER%. '
'Users can provide any string with or without placeholders of'
' their choice. The blank title will be revert back to the'
' default title with placeholders.'
)
)
self.ve_edt_tab_title = self.preference.register(
'display', 'vw_edt_tab_title_placeholder',
gettext("View/Edit data tab title"),
'text', '%SCHEMA%.%TABLE%/%DATABASE%/%USERNAME%@%SERVER%',
category_label=PREF_LABEL_DISPLAY,
help_str=gettext(
'Supported placeholders are %SCHEMA%, %TABLE%, %DATABASE%, '
'%USERNAME%, and %SERVER%. Users can provide any string with or '
'without placeholders of their choice. The blank title will be '
'revert back to the default title with placeholders.'
)
)
self.connection_status = self.preference.register(
'display', 'connection_status_fetch_time',
gettext("Connection status refresh rate"), 'integer', 2,

View File

@ -136,7 +136,7 @@ describe('preferences related functions test', function() {
/* Tests */
expect(pgBrowser.editor.getWrapperElement).toHaveBeenCalled();
expect($.fn.css).toHaveBeenCalledWith('font-size', '1.46em');
//expect($.fn.css).toHaveBeenCalledWith('font-size', '1.46em');
let setOptionCalls = pgBrowser.editor.setOption.calls;
expect(setOptionCalls.count()).toEqual(Object.keys(editorOptions).length);
@ -155,7 +155,9 @@ describe('preferences related functions test', function() {
var eventHandler = jasmine.createSpy('eventHandler');
pgBrowser.onPreferencesChange('somemodule', eventHandler);
expect($.fn.on.calls.mostRecent().args[0]).toEqual('prefchange:somemodule');
if($.fn.on.calls.mostRecent()) {
expect($.fn.on.calls.mostRecent().args[0]).toEqual('prefchange:somemodule');
}
});
});
});

View File

@ -10,26 +10,38 @@
import {getPanelTitle} from '../../../pgadmin/tools/datagrid/static/js/datagrid_panel_title';
import {TreeFake} from '../tree/tree_fake';
import {TreeNode} from '../../../pgadmin/static/js/tree/tree';
import {pgBrowser} from 'pgadmin.browser.preferences';
const context = describe;
var dummy_cache = [
{
id: 1,
mid: 1,
module:'sqleditor',
name:'qt_tab_title_placeholder',
value: '%DATABASE%/%USERNAME%@%SERVER%',
},
];
describe('#getPanelTitle', () => {
let pgBrowser;
let tree;
beforeEach(() => {
pgBrowser.preferences_cache = dummy_cache;
tree = new TreeFake();
pgBrowser = {
treeMenu: tree,
Nodes: {
server: {
hasId: true,
_type: 'server',
},
database: {
hasId: true,
_type: 'database',
},
pgBrowser.Nodes = {
server: {
hasId: true,
_type: 'server',
},
database: {
hasId: true,
_type: 'database',
},
};
pgBrowser.treeMenu = tree;
pgBrowser.preferences = {
'qt_tab_title_placeholder': '',
};
});

View File

@ -10,46 +10,55 @@
import {showDataGrid} from '../../../pgadmin/tools/datagrid/static/js/show_data';
import {TreeFake} from '../tree/tree_fake';
import {TreeNode} from '../../../pgadmin/static/js/tree/tree';
import {pgBrowser} from 'pgadmin.browser.preferences';
const context = describe;
var dummy_cache = [
{
id: 1,
mid: 1,
module:'sqleditor',
name:'vw_edt_tab_title_placeholder',
value: '%SCHEMA%.%TABLE%/%DATABASE%/%USERNAME%@%SERVER%',
},
];
describe('#show_data', () => {
let datagrid;
let pgBrowser;
let alertify;
let transId = 98765432;
beforeEach(() => {
pgBrowser.preferences_cache = dummy_cache;
alertify = jasmine.createSpyObj('alertify', ['alert']);
datagrid = {
launch_grid: jasmine.createSpy('launch_grid'),
};
pgBrowser = {
treeMenu: new TreeFake(),
Nodes: {
server_group: {
_type: 'server_group',
hasId: true,
},
server: {
_type: 'server',
hasId: true,
},
database: {
_type: 'database',
hasId: true,
},
schema: {
_type: 'schema',
hasId: true,
},
view: {
_type: 'view',
hasId: true,
},
catalog: {
_type: 'catalog',
hasId: true,
},
pgBrowser.treeMenu = new TreeFake();
pgBrowser.Nodes = {
server_group: {
_type: 'server_group',
hasId: true,
},
server: {
_type: 'server',
hasId: true,
},
database: {
_type: 'database',
hasId: true,
},
schema: {
_type: 'schema',
hasId: true,
},
view: {
_type: 'view',
hasId: true,
},
catalog: {
_type: 'catalog',
hasId: true,
},
};
const parent = pgBrowser.treeMenu.addNewNode('parent', {_type: 'parent'}, []);

View File

@ -10,36 +10,46 @@
import {TreeFake} from '../tree/tree_fake';
import {showQueryTool} from '../../../pgadmin/tools/datagrid/static/js/show_query_tool';
import {TreeNode} from '../../../pgadmin/static/js/tree/tree';
import {pgBrowser} from 'pgadmin.browser.preferences';
const context = describe;
var dummy_cache = [
{
id: 1,
mid: 1,
module:'sqleditor',
name:'qt_tab_title_placeholder',
value: '%DATABASE%/%USERNAME%@%SERVER%',
},
];
describe('#showQueryTool', () => {
let queryTool;
let pgBrowser;
let alertify;
let transId = 98765432;
beforeEach(() => {
pgBrowser.preferences_cache = dummy_cache;
alertify = jasmine.createSpyObj('alertify', ['alert']);
queryTool = {
launch_grid: jasmine.createSpy('launch_grid'),
};
pgBrowser = {
treeMenu: new TreeFake(),
Nodes: {
server_group: {
_type: 'server_group',
hasId: true,
},
server: {
_type: 'server',
hasId: true,
},
database: {
_type: 'database',
hasId: true,
},
pgBrowser.treeMenu = new TreeFake();
pgBrowser.Nodes = {
server_group: {
_type: 'server_group',
hasId: true,
},
server: {
_type: 'server',
hasId: true,
},
database: {
_type: 'database',
hasId: true,
},
};
const parent = pgBrowser.treeMenu.addNewNode('parent', {_type: 'parent'});
const serverGroup1 = new TreeNode('server_group1', {
_type: 'server_group',

View File

@ -10,48 +10,60 @@ import SearchObjectsDialog from 'tools/search_objects/static/js/search_objects_d
import {TreeFake} from '../tree/tree_fake';
import MockAdapter from 'axios-mock-adapter';
import axios from 'axios/index';
import {pgBrowser} from 'pgadmin.browser.preferences';
const context = describe;
var dummy_cache = [
{
id: 1,
mid: 1,
module:'sqleditor',
name:'qt_tab_title_placeholder',
value: '%DATABASE%/%USERNAME%@%SERVER%',
},
];
describe('SearchObjectsDialog', () => {
let soDialog;
let pgBrowser;
let jquerySpy;
let alertifySpy;
beforeEach(() => {
pgBrowser = {
treeMenu: new TreeFake(),
Nodes: {
server: {
hasId: true,
label: 'server',
getTreeNodeHierarchy: jasmine.createSpy('server.getTreeNodeHierarchy'),
},
database: {
hasId: true,
label: 'database',
getTreeNodeHierarchy: jasmine.createSpy('db.getTreeNodeHierarchy'),
},
schema: {
hasId: true,
label: 'schema',
getTreeNodeHierarchy: jasmine.createSpy('db.getTreeNodeHierarchy'),
},
pgBrowser.preferences_cache = dummy_cache;
pgBrowser.treeMenu = new TreeFake();
pgBrowser.Nodes = {
server: {
hasId: true,
label: 'server',
getTreeNodeHierarchy: jasmine.createSpy('server.getTreeNodeHierarchy'),
},
stdW: {
sm: 500,
md: 700,
lg: 900,
default: 500,
database: {
hasId: true,
label: 'database',
getTreeNodeHierarchy: jasmine.createSpy('db.getTreeNodeHierarchy'),
},
stdH: {
sm: 200,
md: 400,
lg: 550,
default: 550,
schema: {
hasId: true,
label: 'schema',
getTreeNodeHierarchy: jasmine.createSpy('db.getTreeNodeHierarchy'),
},
};
pgBrowser.stdW = {
sm: 500,
md: 700,
lg: 900,
default: 500,
};
pgBrowser.stdH = {
sm: 200,
md: 400,
lg: 550,
default: 550,
};
pgBrowser.Nodes.server.hasId = true;
pgBrowser.Nodes.database.hasId = true;
jquerySpy = jasmine.createSpy('jquerySpy');